regosen / Gapless-5

Gapless JavaScript audio player using HTML5 and WebAudio
MIT License
142 stars 22 forks source link

Fails on Safari (iOS and macOS) for mp3 and m4a tracks around 10-15 minutes long #27

Open straydogmatagram opened 2 years ago

straydogmatagram commented 2 years ago

When I load tracks that are between about 10 and 15 minutes long, the player fails on these tracks. (These times are not exact. Problems start for tracks a little longer than 10 minutes, and tracks a bit longer than 15 seem to work.) This only happens on Safari on my Mac and on Safari on iOS. It also only happens for mp3 and m4a files -- wavs work fine.

It is easy to reproduce. For example, upload a 12-or-so minute track to the demonstration page here: https://ccrma.stanford.edu/~regosen/gapless5 On Safari on a Mac, the time shown is truncated to 2 minutes. I have one iPhone running iOS 15, and it is the same as on my Mac. On another iPhone still running iOS 14, then the time shown is not truncated but the player stops playing after two minutes.

(Actually Brave browser, Firefox, and Chrome also show this same problem on iOS, but I think they are just using Safari's innards.)

This is with gapless 5 version 1.3.4.

Any ideas for fix or workaround would really be appreciated.

regosen commented 2 years ago

Hi, I'm trying it right now on macOS safari with a 60-minute .m4a (stereo 256 kbps) file and so far it's playing fine and I'm 25 minutes in. I have a couple questions:

  1. What exactly happens when it fails? Does it play for 10-15 minutes and then go silent?
  2. Any errors in the JS console?
straydogmatagram commented 2 years ago

It also works for me for long files. It is only when they are between about 10 minutes long and 15 minutes long that there is a problem. Do you have one in that range to test?

Here is what happens:

On Safari on a Mac: The play does not show the correct duration, but something about 10 minutes less. For example, if the track is 12 minutes long, the player shows it as 2 minutes long. The first two minutes play, and then it advances to the next track.

On Safari on iOS 15, it is the same as above.

On Safari on iOS 14, the play shows the correct time (12 minutes) but after 2 minutes it goes silent.

Try it with a 12 or 13 minute file.

straydogmatagram commented 2 years ago

This should allow you to reproduce the problem easily. Here is a track that is 12 minutes and 6 seconds. https://cloud.grwelch.com/index.php/s/aqEcNDzceZJseHb

This is an ordinary 44.1 kHz, 2 channel, 128 kbps, aac encoded track. Afinfo on a Mac shows the time as 726.07 seconds (12:06). You can download this file to test.m4a.

Now go to this demo page for Gapless-5: https://ccrma.stanford.edu/~regosen/gapless5/

Using the file upload button at the bottom, upload test.m4a. On Safari, you will see that instead of showing the duration as 12:06, it is shown as 1:57. If you click play, it stops after 1:57. Other browsers on a Mac work correctly. No browsers (afaict) on iOS work correctly.

I don't see anything untoward on the javascript console.

regosen commented 2 years ago

Thanks for the details and the link to the track- if only all GitHub issue postings were of this quality! :chef_kiss:

That being said, below is a screenshot of your track after playing for a few minutes through the same demo page- using Safari 15.2 on macOS Monterey (12.1).

This is quite an odd issue- normally I'd suspect you're low on memory or something, but as you said it doesn't happen with longer tracks (or with WAV files no less).

If you have a local setup, can you try constructing the Gapless5 object with either of these options set to false?

Screen Shot 2022-01-25 at 8 31 32 PM

straydogmatagram commented 2 years ago

First, thank you for responding so quickly. I really appreciate the help! Yes, this is very frustrating.

To simplify things, I have created a test page here. This page is very simple; it just loads the player with test.mp4 as the sole entry in the play list. I've attached some screenshots in my follow-up.

On Firefox, it loads correctly and shows the correct track time of 12:06. It also plays all the way through. On Safari on either Mac or iOS, the track time shown is truncated to 1:57, and only plays for 1:57.

I also don't think it is a memory issue, because my Mac has 32 GB of ram. But anyway, you can't change your ram in your iPhone. And yes, it works for tracks longer than about 15 minutes, and also with wavs.

As to your question, setting useWebAudio: false does "fix" this problem. That is, the track loads correctly and play all the way through. But this is not really a fix, beause the entire point of the exercise is to get gapless playback and this setting causes a gap after every track.

Setting useHTML5Audio: false has no affect.

straydogmatagram commented 2 years ago

Using the test page mentioned above:

On Safari on a Mac, this is what I see:

mac

Note that the track duration is not correct: It is showing 1:57. This happens not only on my machine, but every Mac I have tested it on, running Monterrey and Big Sur. Again, the problem is only on Safari, not other browsers.

On my iPhone, I see this:

iphone

Again, you see the track time is 1:57. I have tested this on my wife's iPhone, a friend, and my nextdoor neighbor, and all see the same thing as me.

The behavior is the same on iOS under Firefox, Brave, and Chrome.

I do have an older iPad running iOS 14, and on it the track time is shown correctly. However, the music stops playing (goes silent) after 1:57.

straydogmatagram commented 2 years ago

It is very frustrating that this works for you, yet for me it fails on Safari on every machine I try, including those of friends and family. Do you have an iPhone to try it on? I am not sure how much time you want to spend on it, but I would love to use your player in a project and I would be happy to perform any further testing you would like to suggest.

Frankly, I'm much more interested in iOS than Mac. However, I suspect that whatever problem is at the root here is common to both.

I fear that we have uncovered a bug in how Apple implements Web Audio. But if there is something in your library that could be fixed, that would be fantastic for me.

regosen commented 2 years ago

Oh interesting! I'm able to reproduce it now on my iPhone. And on macOS Safari it shows the full duration but went silent after a few seconds... though that only happened once.

Would you mind updating your page such that the Gapless5 constructor options includes logLevel: LogLevel.Debug ?

straydogmatagram commented 2 years ago

Done! I added that line in the constructor. But where is the log?

I have to run off to some meetings right now, so it will be some hours before I can check back here. Thanks again so much for looking at it!

regosen commented 2 years ago

Oh the option keys are case-sensitive. I see you did this:

const player = new Gapless5({
    guiId: 'gapless5-player-id',
    LogLevel: LogLevel.Debug,
});

But that last line needs to be this:

    logLevel: LogLevel.Debug,

Then you should see information under Develop -> Show JavaScript Console

straydogmatagram commented 2 years ago

Sorry! Just changed it. Does this tell you anything?

regosen commented 2 years ago

Thanks for this. I see on iPhone we're calling decodeAudioData with data of the correct size, but for some reason decodeAudioData's callback is being called with truncated decoded data.

I think there's something wrong with the file itself that other players are able to handle but not Safari. As a test, I re-converted test.m4a using the Apple Music app, and now it plays fine on my iPhone.

Re-exported file: https://ccrma.stanford.edu/~regosen/gapless5/test-reexport.m4a Test with new file: https://ccrma.stanford.edu/~regosen/gapless5/bug.html

So I wonder how you're converting these files to mp3 and m4a, and if there's some setting in there that isn't playing nicely with Safari.

straydogmatagram commented 2 years ago

Man, this is really tough.

Perhaps we are making progress, but this is not solved. While the track you encoded does work on my Mac in Safari, it does not work on my iPhone. I tried my wife's iPhone too (a different model but same iOS version), and it has the same behavior as before (track time showing 1:57 instead of 12:06). This is the same using my test site with your re-encoded file, and also with your test site. I will contact friends and ask them to try it on their iPhones too. What iOS version do you have? I have what seems to be the latest: 15.2.1.

So, progress, but no win.

For what it's worth, I encode all my files with Apple's own tool, afconvert: afconvert file.wav -d aac -f m4af -b 256000 -q 127 -s 2 file.m4a (Note, I used 128k for the test track. No difference with 256k.) They play fine (and gaplessly) in Apple's music apps on the Mac and on the iPhone.

I see the same problem with mp3 as well. I encode those with lame: lame -v -q 1 -V 0 file.wav file.mp3

Running afinfo on my file and also on yours, they are not very different. Yours has a bit different bit rate, and also has sound-check info. Can you tell me how you made it?

I will play around with other conversion options, and also try using fdk-aac instead of Apple's stuff to see if it makes a difference.

straydogmatagram commented 2 years ago

Oh man. I refreshed your test page in Safari on my Mac, and now it is no longer working.

I also got a friend across town to try it on her iPhone, and it's the same as mine. No glory :-(.

straydogmatagram commented 2 years ago

Progress!

I tried re-encoding the file with fdk_aac. It works! Both on the Mac and on the iPhone. I tried my wife's iPhone and also my friend, and both play the whole 12 minutes!

You can find the re-encoded file here.

You can run my test site with it in the same place as before.

I am now re-encoding a lot of tracks to run more tests. I will keep you posted.

It is absolutely stunning that Apple's browser fails which Apple's encoder, but works using open source stuff.

Thanks again for bothering! I wish there was a way I could pay the project back, but I'm not much for javascript. I'm pretty good server-side, but JS seems hard to wrap my head around.

regosen commented 2 years ago

I'm glad to know that fixed it, such a weird bug!

If you create a cool site that uses this player, I'd be happy to link to it in the Gapless 5 readme under Demos, let me know.

straydogmatagram commented 2 years ago

Unfortunately there are still problems. Sometimes (it seems random) the player just stops. The timer keeps going up and the scrobbler keeps advancing, but no sound. This happens by far the most after loading, but not always, and sometimes just during playback. Often if I switch from Safari to another app, and then back to Safari, the player will keep advancing but no sound.

I've found some tricks to get the sound back: jumping between tracks sometimes works, and loading a YouTube video in another tab seems to always cause this player to start making sound again.

Unless you have any other ideas, I will keep playing with different encodings. Very frustrating that Safari is so pathetic for decoding aac.

I have high hopes for this. One thing I can say for your player is that the gapless playback is perfect. And that's really hard to find these days.

regosen commented 2 years ago

I wonder if it happens when switching from HTML5 Audio to WebAudio. Does it go away if you initialize with useHTML5Audio: false ? It's not needed for gapless playback, but it would allow you to start a track a little sooner.

straydogmatagram commented 2 years ago

Sadly, that has no (discernible) affect on the problem. I think it's bound to be that the encoding is still not quite something Safari can handle. For example, in one folder of 27 songs, there was still one track where the duration showed up wrong, although it is mostly always right now.

It seems really weird to me that Safari is so much less robust with aac encoding than the Music app (which has no problem with any of these files).