Selection reads Format.sampleRate, but the rate family is only certain once a
major sync is parsed. When a container announces the 48kHz family and the
bitstream announces 44.1kHz, the packer emits nothing: handleBuffer consumed the
input and reported success, so the stream played as silence for as long as it
lasted. TrueHdMatPacker.reset also left the flag latched, so every later stream
on that packer emitted nothing too.
Leave the offending access unit in the buffer, signal the capability change, and
let the decoder take the stream over. The packer clears the flag on reset.
The latch has to outlive both flush and reset. media3 resets every renderer
disabled by a new selection before enabling its replacement
(ExoPlayerImplInternal.enableRenderers), and both audio renderers share this
sink, so the outgoing renderer's reset arrives in the middle of the handover the
latch exists to cause; clearing it there loops straight back into the mismatch.
The real boundary is a new media item, which only ExoPlayerCore knows, so it
signals one before setting a new source. The same-item recovery, DV-mode and
subtitle reloads deliberately do not.
It is a generation rather than a flag because that hook runs on the app thread
while the mismatch is found on the playback thread: a late buffer from the
outgoing stream would otherwise disable the carrier for its successor.
Verified on the SEI Box R (Android 14, armv7) with a genuine 44.1kHz TrueHD
stream in a container patched to announce 48000, so the bitstream and its
checksums stay valid. The sink enters the carrier at 192kHz, reports the
mismatch, hands over to FFmpeg and plays on. The device test asserts that
sequence from the sink's own diagnostics, because the mismatch fires before the
carrier opens an AudioTrack and the rate sequence alone cannot distinguish it
from never having selected the carrier.