Summary
A plain SD MKV with mono MP3 audio cannot be played on the native route at all. The mp3 → E-AC-3 bridge is selected, the first segment cut is deferred because no audio sample entry can be built, the forward prime scan does not find one, the pump exits muxerFailed, both rebuilds fail identically, the revive cap is reached and the session ends with:
Source audio cannot be muxed (code -22)
Reproduced nine times out of nine, at nine different start positions including 0.00s, on the same file. The software route plays the same file perfectly.
This looks distinct from the three neighbours, and I have tried to rule each out below rather than assume:
Environment
- AetherEngine 6.27.1
- iPad mini (6th generation), iOS 26.5 (23F77)
- Host: our Flutter app, own
video_player backend; AetherEngine as rung 1, libVLC as rung 2
- Route: native / loopback (
canHardwareDecode codec=27 640x272 -> true)
Source media (ffprobe)
Matroska over HTTP from an Xtream-style IPTV origin, 358,378,434 B. Absolute byte ranges are
honoured (206); the origin does not honour suffix ranges, which the engine notices once
and stops asking for — pump tail prefetch rejected after 1676ms: Content-Range: bytes -65536/358378434 does not describe the 65536B asked for; not asking this origin again this session. Mentioning it only to be complete: it is the same on every run, including the ones
where the software route plays the file to the end.
0 h264 video 640x272 High/L2.1 yuv420p 23.976 fps tel (default)
1 mp3 audio mono 44100 Hz 40 kb/s tel (default) <- selected
2 mp3 audio mono 24000 Hz 32 kb/s tam
3 mp3 audio mono 24000 Hz 32 kb/s hin
4 subrip sub eng (default)
duration 7070.189s, overall bitrate ~405 kb/s
What the engine does
[AetherEngine] dispatch: codec=27 → native
[HLSVideoEngine] video codecpar: codec=27 640x272 profile=100 level=21 fieldOrder=1 extradata=44B head=01640015ffe1001c
[HLSVideoEngine] segment plan: keyframe-aligned, 2152 IRAPs → 1690 segments [firstKeyframePts=0 (0.000s) videoStream.start_time=0 format.start_time=0us plan[0].startSeconds=0.000]
[HLSVideoEngine] audio: codec=mp3 (bridge required), decoding + EAC3 re-encode
[AudioBridge] init: mode=surroundCompat srcCodec=86017 sampleRate=44100 sourceChannels=1 encoderChannels=1 bitRate=128 kbps (source=container, container=1, decoder=1)
[HLSSegmentProducer] init OK (baseIndex=0, segments=1674, targetDur=4.000s, srcVideoTb=1/1000) audio=bridge inTb=1/44100
[HLSVideoEngine] prepared: codec=avc1.640015,ec-3 resolution=640x272 fps=23.976 range=SDR DV=none segments=1674 duration=7070.2s
[AetherEngine] #321: effective video route = loopback
The failure, from 0.00s
[HLSSegmentProducer] video gate open: actual=0 anchorPts=0 target=-9223372036854775808 desired=0 shift=0 videoPID=0 reconstructed=false
[HLSSegmentProducer] first video pkt: dts=0 pts=0 duration=41 size=1060 (fallback=41 in srcVideoTb)
[HLSSegmentProducer] audio gate open: actual=9 target=0 desired=0 shift=0 gapMs=0.0
[HLSSegmentProducer] #65 ledger seg-0 base=0 itemAxis=0.000s sourceStart=0.000s planSource=0.000s drift=0.000s shift=0.000s
[HLSSegmentProducer] #65 ledger seg-1 base=0 itemAxis=20.771s sourceStart=20.771s planSource=10.427s drift=10.344s shift=0.000s
[HLSSegmentProducer] AE#222 seg-0.m4s cut deferred: audio sample entry needs a parsed packet and none has been muxed; scanning forward for a prime frame
[HLSSegmentProducer] pump finished: reason=muxerFailed packetsRead=1308 packetsWritten=500 lastError=0 elapsed=526ms cacheCount=0
[HLSVideoEngine] #99 VOD pump died with muxerFailed; rebuilding producer + muxer at 0.00s -> seg0 (attempt 1/2)
… identical, elapsed=19ms …
[HLSVideoEngine] #99 VOD pump died with muxerFailed; rebuilding producer + muxer at 0.00s -> seg0 (attempt 2/2)
… identical, elapsed=15ms …
[HLSVideoEngine] #99 VOD muxerFailed revive cap reached (3 failures, cap 2); giving up (source not muxable in this session)
Two things stand out to us, offered as observation rather than diagnosis:
- The source audio is right there.
gapMs=0.0, first audio packet at 9 ms. Whatever is missing is downstream of the demuxer — the bridge's encoded E-AC-3 output, not a source packet.
- The scan does travel.
seg-1 lands at sourceStart=20.771s against planSource=10.427s, a 10.3 s drift, so roughly twenty seconds of media went by without an audio sample entry ever being available.
Every attempt, same file
Nine sessions, nine start positions, nine identical outcomes. packetsWritten/packetsRead is 0.37–0.38 throughout.
| startPosition |
anchor seg |
packetsRead |
packetsWritten |
first attempt |
| 0.00 s |
seg-0 |
1308 |
500 |
526 ms |
| 2214.00 s |
seg-545 |
584 |
221 |
400 ms |
| 2483.00 s |
seg-611 |
602 |
228 |
763 ms |
| 2932.00 s |
seg-720 |
1025 |
389 |
447 ms |
| 3331.00 s |
seg-809 |
811 |
305 |
487 ms |
| 5295.00 s |
seg-1306 |
713 |
270 |
650 ms |
| 5658.00 s |
seg-1398 |
589 |
222 |
496 ms |
| 5867.00 s |
seg-1451 |
414 |
155 |
489 ms |
| 5908.00 s |
seg-1460 |
494 |
185 |
429 ms |
Both rebuilds always read exactly the same packet counts as the first attempt and fail in 12–23 ms, so as in #222 the retry re-enters the same configuration rather than changing the decision that caused the failure.
Two things we checked so you don't have to
- The software route plays this file completely. Same URL, same 6.27.1, on the iOS simulator, which has no VideoToolbox decoder —
codec=27 not hardware-decodable by VideoToolbox; routing to the software path so it plays instead of a black screen (#2): 683 frames in 30 s, route=software, all three audio tracks named and selectable, subtitle selection works. So demux and decode of this file are fine; the failure is confined to the loopback muxer path.
- Mono 44.1 kHz E-AC-3 into fragmented MP4 is not inherently impossible. Standalone,
ffmpeg -f lavfi -i sine=…:sample_rate=44100 -ac 1 -c:a eac3 -b:a 128k -movflags +empty_moov+default_base_moof+frag_keyframe+delay_moov -f mp4 produces a valid eac3 / 44100 / 1ch track. We are not claiming that is the same code path — only that the encoder configuration AudioBridge reports is one ffmpeg will accept.
Impact for us
Low, and we are not blocked: our ladder demotes to libVLC and the viewer gets a picture. We are reporting it because mono MP3 in MKV is ordinary IPTV catalogue material rather than an exotic shape, and because a source the software route plays end to end is worth having on the native route too.
Happy to run any diagnostic build against this file, or to try a synthetic reproduction if you would like one — a three-track mono-MP3 MKV should be straightforward to generate.
🤖 Written and posted by Claude Code on behalf of @ksktech-dev.
Summary
A plain SD MKV with mono MP3 audio cannot be played on the native route at all. The
mp3 → E-AC-3bridge is selected, the first segment cut is deferred because no audio sample entry can be built, the forward prime scan does not find one, the pump exitsmuxerFailed, both rebuilds fail identically, the revive cap is reached and the session ends with:Reproduced nine times out of nine, at nine different start positions including 0.00s, on the same file. The software route plays the same file perfectly.
This looks distinct from the three neighbours, and I have tried to rule each out below rather than assume:
AE#222 … cut deferred … scanning forward for a prime frame, i.e. the muxer is correctly declining to write a moov. What fails is the scan that follows.audio gate open: actual=9 target=0 … gapMs=0.0), so the source packet is not what is missing. The 6.25.x midpoint-seeking scan is in this build.startPosition, arriving via the seek/re-anchor path. This reproduces identically from 0.00s with no seek at all.Environment
video_playerbackend; AetherEngine as rung 1, libVLC as rung 2canHardwareDecode codec=27 640x272 -> true)Source media (ffprobe)
Matroska over HTTP from an Xtream-style IPTV origin, 358,378,434 B. Absolute byte ranges are
honoured (
206); the origin does not honour suffix ranges, which the engine notices onceand stops asking for —
pump tail prefetch rejected after 1676ms: Content-Range: bytes -65536/358378434 does not describe the 65536B asked for; not asking this origin again this session. Mentioning it only to be complete: it is the same on every run, including the oneswhere the software route plays the file to the end.
What the engine does
The failure, from 0.00s
Two things stand out to us, offered as observation rather than diagnosis:
gapMs=0.0, first audio packet at 9 ms. Whatever is missing is downstream of the demuxer — the bridge's encoded E-AC-3 output, not a source packet.seg-1lands atsourceStart=20.771sagainstplanSource=10.427s, a 10.3 s drift, so roughly twenty seconds of media went by without an audio sample entry ever being available.Every attempt, same file
Nine sessions, nine start positions, nine identical outcomes.
packetsWritten/packetsReadis 0.37–0.38 throughout.Both rebuilds always read exactly the same packet counts as the first attempt and fail in 12–23 ms, so as in #222 the retry re-enters the same configuration rather than changing the decision that caused the failure.
Two things we checked so you don't have to
codec=27 not hardware-decodable by VideoToolbox; routing to the software path so it plays instead of a black screen (#2): 683 frames in 30 s,route=software, all three audio tracks named and selectable, subtitle selection works. So demux and decode of this file are fine; the failure is confined to the loopback muxer path.ffmpeg -f lavfi -i sine=…:sample_rate=44100 -ac 1 -c:a eac3 -b:a 128k -movflags +empty_moov+default_base_moof+frag_keyframe+delay_moov -f mp4produces a valideac3 / 44100 / 1chtrack. We are not claiming that is the same code path — only that the encoder configurationAudioBridgereports is one ffmpeg will accept.Impact for us
Low, and we are not blocked: our ladder demotes to libVLC and the viewer gets a picture. We are reporting it because mono MP3 in MKV is ordinary IPTV catalogue material rather than an exotic shape, and because a source the software route plays end to end is worth having on the native route too.
Happy to run any diagnostic build against this file, or to try a synthetic reproduction if you would like one — a three-track mono-MP3 MKV should be straightforward to generate.
🤖 Written and posted by Claude Code on behalf of @ksktech-dev.