I'm attempting to use HTML5 to simulate a more robust multimedia player which loads ads in the background and swaps between video and ads as required.
The first challenge I ran into was that most mobile devices don't allow you to pre-load video, meaning the very concept of loading ads "in the background" isn't possible. Instead I took a much less elegant approach: have a single <video>
tag and change its src
attribute when it's time to throw an ad. The advantage to this is that you can commandeer the existing permission to pre-load and auto play, but the disadvantage is nasty buffering every time the video element changes. This was acceptable to our clients, however.
So the ideal behavior is:
The second challenge I ran into was getting content to resume at the correct location. When you change the src
attribute, the video starts playing from time 0. As a result I had to go with another ugly solution: Wait for the video to load (canPlayThrough
event) then perform a seek to the desired time. This actually causes it to buffer twice when switching from an ad back to content - but it's an acceptable cost for not using the native apps.
To figure out exactly where we should seek to, I have a "virtual content player" running in the background. Basically a variable that stores the current time and updates when the <video>
element throws an updateTime
event. So as the ad progresses, the virtual content advances at the exact same rate. When it's time to switch back, we've skipped exactly one minute of content.
The challenge I've run into is that sometimes it seeks to a random location. I have absolutely no idea why. As an example, here's the console logs for different seek events when I played an ad at 7:39 (459 seconds) that was supposed to end at 8:09 (489 seconds):
@@ seeking from: 30.06833267211914, to: 0
@@ seeked to: 0
Content currentTime: 0
Content currentTime: 489.0016784667969
@@ seeking from: 489.0016784667969, to: 489.0016784667969
Content currentTime: 489.0016784667969
@@ seeking from: 489.0016784667969, to: 489.0016784667969
Content currentTime: 489.0016784667969
@@ seeked to: 489.0016784667969
Content currentTime: 489.0016784667969
Content currentTime: 441.502197265625
Content currentTime: 441.3605346679683
Content currentTime: 441.6107177734375
To explain what you're looking at:
I have a seekFrom
variable that is updated when the updateTime
event fires. This is used to get the "from" value during the seeking
event. The to
value is equal to video.currentTime
. During the seeked
event I just show video.currentTime
.
So originally there was a seek from 30 to 0 (this is the "seek to 0" performed when the source is changed). Shortly afterwards the current time changed to 489 before the seek event fired. There were then two seek events -- one representing the change from 0 to 489 (which was misinterpreted as 489 to 489 since the current time updated early) and another representing an unsolicited change from 489 to 441 (also misinterpreted as 489 to 489 since the current time updated late). After this the current time changed to 441.
All of this was created by the following two lines of code:
video.src = content.source;
video.currentTime = content.currentTime;
At the time those two lines were run, content.currentTime
was equal to 489. Nowhere else do I set video.currentTime
manually, and no seeks were performed on the seek bar. The number 441 seemed to come out of thin air, but if I replay the video over and over again it always seeks to this exact same location -- so there must be some significance.
So the question is:
Why on Earth is it seeking twice, and how do I stop it?
Note: This behavior was all experienced using QuickTime on a Macbook Pro. I haven't even gotten to testing on iOS yet (since it isn't working right) and Android will be a whole different issue all together when I get there.
Also, note: I receive a seeking
event prior to the second seek - so if there's any way in HTML5 to "cancel" a seek, that might be an acceptable solution.
After experimenting and researching and trying every random suggestion I could find on obscure blog posts I found something that works:
iOS has trouble seeking to decimal locations. A seek to 491.337 will fail, but a seek to 491 will succeed.
I just added the following:
video.currentTime = content.currentTime | 0; // Shortcut for truncating positive integers