When a playback fails with some ExoPlaybackException, it’s relatively easier to know what’s is wrong and how to fix it, but how do you solve some non-crash problems like playback stalls for a very short time under certain conditions, or output surface flickers on a specific device.
This is a story of how I debugged a non-crash playback issue and hope this helps someone solve these kinds of problems.
audio and video stop for a very short amount of time (like 500ms) when switching from a lower resolution to a higher resolution.
One day this ticked was assigned to me, and I started an investigation.
EventLogger and DebugTextViewHelper
DebugTextViewHelper.java is a quick way to see what’s going on during the playback, so I checked the outputs of these two at first.
EventLogger prints out ExoPlayer events, and you can use this just setting a lister to an ExoPlayer instance.
DebugViewHelper provides an overlay view that shows playback information. You can confirm which resolution is currently playing or audio/video format, playback state, etc.
looking at the logs from EventLogger, I found that
c2.android.aac.decoder was reinitialized for some reason when a resolution switch happened, and at that time the playback stall happened.
To know the reason why the audio decoder is reinitialized, I started looking for the conditions of decoder initialization from ExoPlayer source code and finally found it.
canKeepCodec function determines whether or not decoder should be initialized. Our media of ~240p was monaural sound and 360p~ was stereo sound and
KEEP_CODEC_RESULT_NO when the channel count is different.
I understood that channel count difference causes audio decoder initialization and that makes playback stalls happen. It makes sense that audio pauses because of this, but why the video pauses too.
To take a deeper look, you can use systrace, which allows you to collect and inspect timing information across all processes running on your device at the system level, and ExoPlayer embeds their own information by default. While ExoPlayer is playing some media, you can start tracing using this command below.
python .../platform-tools/systrace/systrace.py --app=your.package.name
If you want to know systrace more, this youtube video is very helpful.
And this is what I got when audio decoder reinitialization happened. 10
The thin blue bars are
releaseOutputBuffer and these are timings when video frames are rendered on a provided surface, so if you play some 30fps video you will see the blue bar every 33.3ms.
When the audio decoder reinitialization happens, there is a time gap of 500ms until the next frame is rendered on the
ExoPlayerImplIn thread. Considering ExoPlayer retrieves audio output buffer and video output buffer with the same single thread, audio decoder reinitialization may delay next video frame rendering.
After fixed to use the same channel count across all resolutions, playback stalls never happened. 🚀