playlist shows wrong song duration on mobile safari

455 views
Skip to first unread message

danI

unread,
Feb 5, 2011, 3:22:07 PM2/5/11
to jPlayer: HTML5 Audio & Video for jQuery
Hi everyone,

Thanks to folks for making jPlayer, it's really great!

I couldn't find this topic on the list, so apologies if it has already
been mentioned.

I found this bug on an ipod touch running iOS 4.2. But it is normal on
an ipad. Don't have an iphone handy, maybe someone could check it on
that.

The audio playlist (I am testing with the audio playlist demo at the
bottom of http://jplayer.org/latest/demo-02/ ) doesn't properly update
the duration of the song that has been selected. It gets the duration
of the _previously_ selected song instead. It displays the wrong time,
and this leads to the progress bar being improperly rendered.

Anybody know if there a fix for this?

thanks, Dan

mxadler

unread,
Feb 6, 2011, 10:57:38 PM2/6/11
to jPlayer: HTML5 Audio & Video for jQuery
I'm seeing similar behavior on iOS 4.2 (iPhone) and have narrowed it
down some. It looks like a timing problem.

I copied just the main HTML page from http://jplayer.org/latest/demo-02/
to my local web server. I then changed all the local references
within the pages to link back to jplayer.org, so the only file being
served is the primary HTML page. I was interested only in the audio
section at the bottom and didn't test video.

The test works fine on Firefox 3.6 and IE8. Clicking on a different
track updates the display and starts playing the track.

The test works fine on my iPhone when connected on a high latency (3G)
link.

The test fails on the same iPhone when connecting on the local WiFi
LAN with very low latency. The HTTP (Apache) server is on the same
LAN. When it fails, typically the track length doesn't update when
clicking on a new track. Sometimes the track starts to play anyway.
Often it starts to play but the "play" button shows instead of the
"pause" button.

I turned on error alerts. When it fails it throws: jPlayer 2.0.0:
id='jquery_jplayer_2': Error! Media URL could not be loaded.
Context: http://www.jplayer.org/audio/mp3/Miaow-04-Lismore.mp3. The
media is definitely there and served correctly, since the same code
works over 3G.

Strangely, when it fails I see the iPhone hitting the server to reload
the main HTML page, which is cacheable. When connected via the slower
3G link the iPhone loads the HTML page only once and does not reload
it when new tracks are selected. It is almost as though the browser
is incorrectly requesting the HTML be loaded instead of the MP3 file.

I tried to find a race by inspection in the Javascript, but gave up in
the web of jQuery callbacks. It seems as though there is a race
somewhere in setMedia between adding HTML5 audio MP3, expecting the
callback with media duration, and generating the play event.

-Michael

Mark Panaghiston

unread,
Feb 8, 2011, 2:46:39 PM2/8/11
to jpl...@googlegroups.com
I was just taking a look at this. I reviewed on an iPhone with iOS4.2.1 and found the duration problem you described.

The duration is set when a durationchange event is generated by the browser. Apparently, the durationchange event is being fired before the Mobile Safari browser has updated its duration value on the media element. I would need to look into this more though before raising a bug report with Apple.

A possible quick fix for this would be to read the duration when the other html values are read.
In the _getHtmlStatus() function, add after the vars are created... ie., at the top of the function:
this.status.duration = media.duration;

It has to be at the top since the status value is used in the coding... Well, it requires the fewest other changes if put there.

As for the problem Michael described, I am not sure... I usually test on my iPhone or iPod over my WiFi and have not found that problem... However, the problem you described... "it is like it tried to load the HTML"... This sounds like the clearMedia command. It sets the media SRC to "", an empty string, and issues the load() so as to clear the previous media. This only happens under some circumstances when new media is set using setMedia. It is performed so that changing the media without a following play does not leave the old media downloading.

Best regards,
Mark P.

mxadler

unread,
Feb 9, 2011, 12:09:55 PM2/9/11
to jPlayer: HTML5 Audio & Video for jQuery
From Mark's suggestions I was able to fix both iPhone problems. The
duration problem is fixed by putting

if (media.duration) this.status.duration = media.duration;

at the beginning of __getHtmlStatus(). Without the test for
media.duration != 0 some browsers briefly display NaN:NaN for the
duration due to, I assume, the order of events. Perhaps there is a
better test than media.duration != 0.

To fix the problem of the media not loading correctly I extended the
test in _html_clearMedia() to include Webkit browsers in the set of
browsers that do not call this.htmlElement.media.load(). It appears
to me that in some, timing dependent, cases that load triggers a load
of the main HTML document as the media. I'm guessing it is loaded as
the media because the request is for a byte range, not the whole page.

This is my patch. (I'm using the web interface for sending mail and
it doesn't offer file upload, so this may not work.)

-Michael


*** jquery.jplayer.js.~1~ Wed Feb 9 10:53:40 2011
--- jquery.jplayer.js Wed Feb 9 11:51:09 2011
***************
*** 738,743 ****
--- 738,744 ----
_getHtmlStatus: function(media, override) {
var ct = 0, d = 0, cpa = 0, sp = 0, cpr = 0;

+ if (media.duration) this.status.duration = media.duration;
ct = media.currentTime;
cpa = (this.status.duration > 0) ? 100 * ct /
this.status.duration : 0;
if((typeof media.seekable === "object") && (media.seekable.length
> 0)) {
***************
*** 1430,1436 ****
this.htmlElement.media.pause();
this.htmlElement.media.src = "";

! if(!($.browser.msie && Number($.browser.version) >= 9)) { // IE9
Bug: media.load() on broken src causes an exception. In try/catch IE9
generates the error event too, but it is delayed and corrupts
jPlayer's event masking.
this.htmlElement.media.load(); // Stops an old, "in progress"
download from continuing the download. Triggers the loadstart, error
and emptied events, due to the empty src. Also an abort event if a
download was in progress.
}
}
--- 1431,1441 ----
this.htmlElement.media.pause();
this.htmlElement.media.src = "";

! // IE9 Bug: media.load() on broken src causes an exception. In
try/catch IE9 generates the error event too, but it is delayed and
corrupts jPlayer's event masking.
! // This load on Webkit (at least iOS) may also cause an error.
In
! // some cases it appears to load main web page's URL as the
media.
! if(!($.browser.msie && Number($.browser.version) >= 9) &&
! !($.browser.webkit)) {
this.htmlElement.media.load(); // Stops an old, "in progress"
download from continuing the download. Triggers the loadstart, error
and emptied events, due to the empty src. Also an abort event if a
download was in progress.
}
}

Mark Panaghiston

unread,
Feb 9, 2011, 12:35:16 PM2/9/11
to jpl...@googlegroups.com
Thank you for the feedback.

I expect I'll apply a patch along the lines that you used.

The only thing I would probably change is to use the jPlayer browser sniffer. It is copied from jQuery 1.4.4, since otherwise jQuery 1.3.2 did not detect Chrome correctly as webkit. But erm, you're using it to detect iOS, so should not matter I suppose. Actually, now I think about it, you can ignore this comment... I left it in otherwise the next sentence does not make sense.
$.jPlayer.browser.webkit

I do plan to expand and review that sniffer. In particular to detect the iOS browser. Originally this was because the volume controls are redundant on iOS. I'll also review any changes in jQuery 1.5.x.

Cheers,
Mark P.
Reply all
Reply to author
Forward
0 new messages