Debugging on ExoPlayer

Taku Semba
Jul 14, 2019 · 4 min read

Debugging Problem

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.

Ticket assignment

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

EventLogger.java and 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

EventLogger prints out ExoPlayer events, and you can use this just setting a lister to an ExoPlayer instance.

setting an EventLogger

DebugViewHelper

DebugViewHelper provides an overlay view that shows playback information. You can confirm which resolution is currently playing or audio/video format, playback state, etc.

DebugView Overlay
setting a DebugViewHelper

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.

EventLogger Log

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 andcanKeepCodec returns KEEP_CODEC_RESULT_NO when the channel count is different.

reinitialization codec

Systrace

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.

Android Performance: An Overview

And this is what I got when audio decoder reinitialization happened. 10

systrace

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. 🚀

References

Taku Semba

Written by

Android Engineer at AbemaTV Github: https://github.com/takusemba

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade