pub async fn player_switch_audio_track(
player: State<'_, PlayerStateWrapper>,
repository_manager: State<'_, RepositoryManagerWrapper>,
repository_handle: String,
stream_index: i32,
array_index: i32,
current_position: Option<f64>,
media_source_id: Option<String>,
) -> Result<AudioTrackSwitchResponse, String>Expand description
Switch audio track. Note: Frontend should handle saving series preferences after this command succeeds
What decides the route is whether the stream in front of the engine
carries the requested track at all — see
determine_audio_track_switch_strategy:
- A native backend playing a direct play holds the source file with every track in it, so ExoPlayer selects in place by track-group index.
- A native backend playing a transcode does not. Jellyfin builds a
transcode around one
AudioStreamIndex, so the alternate tracks are not in the stream; the switch has to re-open it, which this command does itself and resumes atcurrent_position.
That last case is a bug fix, and it was the common case on Android: any
source whose default audio codec the device cannot decode is transcoded, so
ExoPlayer saw Audio tracks: 1 while the menu listed every track in the
file. The old code called setAudioTrack(n) regardless, which indexes
ExoPlayer’s audio track groups, found nothing at n, warned Invalid audio track index and dropped the request — the default track just kept
playing, with nothing in the UI saying so.
mpv selects in place the same way (mpv_tracks::select_audio, by position in
the file’s audio tracks), and re-opens a transcode through the same path.
TRACES: UR-021, UR-005 | IR-019, DR-024, DR-258