Investigation and Resolution of Android Audio Playback Noise Issue in HLS Streams
The Android app’s HLS video produced an electric‑like noise because FFmpeg’s av_find_best_stream mistakenly selected the second audio track in a dual‑stream file, a track lacking 1‑8 kHz frequencies, whereas iOS and PC used the correct first track; fixing requires publishing videos with a single audio track and adding detection tools.
Background: An Android app playing an HLS‑encoded MV video ("凤凰花开的路口") exhibited a persistent electric‑like noise, while the same content played without noise on iOS and PC platforms.
Initial observations:
Noise occurs only on Android.
All platforms use the same HLS source.
Investigation steps included outlining the playback pipeline and identifying potential failure points.
Playback Process Overview
The pipeline consists of player initialization, data reading, audio decoding, and audio rendering. Key components created during initialization are:
Read thread: read_thread
Queue for pre‑decoded audio data: audioq
Queue for decoded audio frames: sampq
Data reading involves creating a context, probing the protocol ( avformat_open_input ), finding stream info ( avformat_find_stream_info ), selecting streams ( av_find_best_stream ), opening decoders ( stream_component_open ), and reading packets ( av_read_frame(ic, pkt) ) which are then pushed into audioq .
Audio decoding runs in audio_thread , converting packets from audioq into AVFrame objects stored in sampq . Audio rendering uses aout_thread_n to invoke sdl_audio_callback , converting frames to PCM and feeding them to AudioTrack .
Problem Decomposition
The team isolated four possible problematic stages:
File download integrity.
Data reading.
Audio decoding logic.
AudioTrack configuration.
1. File download
TS files on Android matched those on other platforms, confirming the download stage was fine.
2. AudioTrack configuration
Log checks showed that sample rate, bit depth, and channel count matched the audio stream, so this stage was also correct.
3. Audio decoding logic
PCM data analysis revealed that the problematic stream lacked frequency components in the 1‑8 kHz range, which is highly audible. Waveform comparison suggested that the decoding process itself was not the root cause, leading to the hypothesis that the issue lay earlier in data reading.
4. Data reading
Additional logging showed an anomaly during av_find_best_stream . The TS segment contained two audio streams. When each stream was forced to play separately:
Stream 1 produced normal PCM.
Stream 2 produced noisy PCM.
Android selected Stream 2 for playback.
This confirmed that the data‑reading stage chose the wrong audio stream.
Root Cause: Audio Stream Selection
The selection is performed by av_find_best_stream , which prefers streams with a higher number of decoded frames ( codec_info_nb_frames ) and higher bitrate. In the examined file:
codec_info_nb_frames
bit_rate
audio_stream 1
38
122625
audio_stream 2
39
126375
Because Stream 2 has both a higher frame count and bitrate, the algorithm selects it, leading to the noisy playback on Android.
int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type,
int wanted_stream_nb, int related_stream,
AVCodec **decoder_ret, int flags)
{
for (i = 0; i < nb_streams; i++) {
count = st->codec_info_nb_frames; // decoded frames
bitrate = avctx->bit_rate; // bitrate
multiframe = FFMIN(5, count);
// compare decoded frames first, then bitrate
if ((best_multiframe > multiframe) ||
(best_multiframe == multiframe && best_bitrate > bitrate) ||
(best_multiframe == multiframe && best_bitrate == bitrate && best_count >= count))
continue;
best_count = count;
best_bitrate = bitrate;
best_multiframe = multiframe;
ret = real_stream_index; // selected stream index
best_decoder = decoder;
}
return ret;
}Comparison with Other Platforms
iOS and PC players default to the first audio stream, which exposed the issue quickly. Android’s FFmpeg‑based ExoPlayer selects the stream with better metrics, which inadvertently chose the defective stream.
Solution
Edit and re‑publish the video with a single, correct audio track.
In the short term, add detection and reporting for dual‑audio‑stream files to help content reviewers catch such problems.
Long term, implement backend tooling to scan existing videos for multiple audio streams and ensure future transcoding produces only one audio track.
References
https://ffmpeg.org/doxygen/2.8/
https://github.com/google/ExoPlayer
https://www.jianshu.com/p/daf0a61cc1e0
https://www.jianshu.com/p/a6a4bf59cdae
http://km.oa.com/articles/show/319627
https://codeday.me/bug/20170711/39603.html
Tencent Music Tech Team
Public account of Tencent Music's development team, focusing on technology sharing and communication.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.