Audio stops playing, the player doesn't stop nor reports an error
Version
Media3 1.2.1
More version details
Also reproducible on main c6bf380d50d4601ce6ec567ebd56ccf5e36fa8cf
Devices that reproduce the issue
Android emulator API28 (probably others as well) Samsung Galaxy S22
Devices that do not reproduce the issue
No response
Reproducible in the demo app?
Yes
Reproduction steps
Use the attached file. Play it for 2:18.
Expected result
Audio keeps playing till the end. Alternatively an error is reported to the app and state is no longer "playing"
Actual result
Audio stops at 2:18. The UI is still in the playing state, the progress bar keeps advancing.
Media
Bug Report
- [X] You will email the zip file produced by
adb bugreportto [email protected] after filing this issue.
When audio stops I can see a logcat message from AudioTrack.stop(). Indeed, I can verify with a debugger that DefaultAudioSink.playPendingData() calls audioTrack.stop(). This is being called indirectly from MediaCodecRenderer.drainOutputBuffer where
boolean isEndOfStream = (outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
is being set to true.
I can reproduce the observed behaviour in the demo app on a Pixel 7a.
I also see that after entering the problematic/silent state, if you seek back to just before 2:18 then playback progresses correctly (I didn't test all the way to the end of the file, but at least beyond 3:00).
Seeking forward to just before 2:18 still allows the problem to reproduce.
Immediately seeking to near the end of the file after the start of playback (about 7:33) causes playback to quickly go silent (before the end of the file).
mediainfo and ExoPlayer both think this file is about 7:57 long. VLC on MacOS can't decide how long it thinks the file is. When I started playing it said 10:54, then at about 1:00 it updated this to 7:57 and then to 8:02. It is able to play past the 2:18 mark without interruption though.
This file looks a bit broken - you can see this by trying to parse it with ffprobe:
$ ffprobe -show_frames demo.mp3
....
[mp3float @ 0x55f7f5d5e180] big_values too big
[mp3float @ 0x55f7f5d5e180] Error while decoding MPEG audio frame.
[mp3float @ 0x55f7f5d5e180] Header missing
I also counted the number of frames emitted by ffprobe -show_frames: 18290. Given 1152 samples per frame, and sample rate of 44.1kHz, that gives a duration (derived from frame count) of 18290 * 1152 / 44100 = 477.8 seconds (or 7mins 57s).
Logcat gives a clue as to where things are going wrong in ExoPlayer:
VbriSeeker androidx.media3.demo.main W VBRI data size mismatch: 13097088, 3769067
That log line comes from here:
https://github.com/androidx/media/blob/b930b40a16c06318e43c81771fa2b1024bdb3f29/libraries/extractor/src/main/java/androidx/media3/extractor/mp3/VbriSeeker.java#L94-L97
Hacking the code to pass inputLength into the VbriSeeker constructor instead allows playback to continue past the 2:18 mark.
So this file is broken, since it has a VBRI frame that reports a file size of 3769067 bytes when the real file is actually 13097088 bytes.
If we compare that to the ffprobe -show_frames output above, we can find the frame that ends at the 3769067 byte position (next one starts at pkt_pos=3769319):
[FRAME]
media_type=audio
stream_index=0
key_frame=1
pts=1951580160
pts_time=138.292245
pkt_dts=1951580160
pkt_dts_time=138.292245
best_effort_timestamp=1951580160
best_effort_timestamp_time=138.292245
pkt_duration=368640
pkt_duration_time=0.026122
duration=368640
duration_time=0.026122
pkt_pos=3768693
pkt_size=626
sample_fmt=fltp
nb_samples=1152
channels=2
channel_layout=stereo
[/FRAME]
And from here you can see where 2:18 comes from, since pts_time=138.292245 (in seconds) is 2:18.
In general, when ExoPlayer is provided an invalid/broken file, the result is undefined behaviour. So we don't guarantee to always emit an error in cases like this. It may be that we don't make any changes here. I will have a think.