diff --git a/Model/Player/Backends/MPVBackend.swift b/Model/Player/Backends/MPVBackend.swift index d8a98ff9..e67da018 100644 --- a/Model/Player/Backends/MPVBackend.swift +++ b/Model/Player/Backends/MPVBackend.swift @@ -338,11 +338,11 @@ final class MPVBackend: PlayerBackend { // Handle streams with multiple audio tracks if !stream.audioTracks.isEmpty { - if stream.selectedAudioTrackIndex >= stream.audioTracks.count { - stream.selectedAudioTrackIndex = 0 - } + // Ensure the index is within bounds to prevent race conditions + let safeIndex = min(max(0, stream.selectedAudioTrackIndex), stream.audioTracks.count - 1) + stream.selectedAudioTrackIndex = safeIndex - stream.audioAsset = AVURLAsset(url: stream.audioTracks[stream.selectedAudioTrackIndex].url) + stream.audioAsset = AVURLAsset(url: stream.audioTracks[safeIndex].url) let fileToLoad = self.model.musicMode ? stream.audioAsset.url : stream.videoAsset.url let audioTrack = self.model.musicMode ? nil : stream.audioAsset.url diff --git a/Model/Player/PlayerModel.swift b/Model/Player/PlayerModel.swift index a38f79cc..3388f66d 100644 --- a/Model/Player/PlayerModel.swift +++ b/Model/Player/PlayerModel.swift @@ -1575,4 +1575,11 @@ final class PlayerModel: ObservableObject { var availableAudioTracks: [Stream.AudioTrack] { (backend as? MPVBackend)?.availableAudioTracks ?? [] } + + var selectedAudioTrack: Stream.AudioTrack? { + let tracks = availableAudioTracks + guard !tracks.isEmpty else { return nil } + let safeIndex = min(max(0, selectedAudioTrackIndex), tracks.count - 1) + return tracks[safeIndex] + } } diff --git a/Shared/Player/Controls/ControlsOverlay.swift b/Shared/Player/Controls/ControlsOverlay.swift index cbd818d0..fc8399c5 100644 --- a/Shared/Player/Controls/ControlsOverlay.swift +++ b/Shared/Player/Controls/ControlsOverlay.swift @@ -458,7 +458,7 @@ struct ControlsOverlay: View { Menu { audioTrackPicker } label: { - Text(player.availableAudioTracks[player.selectedAudioTrackIndex].displayLanguage) + Text(player.selectedAudioTrack?.displayLanguage ?? "Original") .frame(maxWidth: 240, alignment: .trailing) } .transaction { t in t.animation = .none } @@ -468,7 +468,7 @@ struct ControlsOverlay: View { .frame(height: 40) #else ControlsOverlayButton(focusedField: $focusedField, field: .audioTrack) { - Text(player.availableAudioTracks[player.selectedAudioTrackIndex].displayLanguage) + Text(player.selectedAudioTrack?.displayLanguage ?? "Original") .frame(maxWidth: 320) } .contextMenu { diff --git a/Shared/Player/PlaybackSettings.swift b/Shared/Player/PlaybackSettings.swift index 09bf0054..104bf6ee 100644 --- a/Shared/Player/PlaybackSettings.swift +++ b/Shared/Player/PlaybackSettings.swift @@ -503,7 +503,7 @@ struct PlaybackSettings: View { Menu { audioTrackPicker } label: { - Text(player.availableAudioTracks[player.selectedAudioTrackIndex].displayLanguage) + Text(player.selectedAudioTrack?.displayLanguage ?? "Original") .frame(maxWidth: 240, alignment: .trailing) } .transaction { t in t.animation = .none } @@ -513,7 +513,7 @@ struct PlaybackSettings: View { .frame(height: 40) #else ControlsOverlayButton(focusedField: $focusedField, field: .audioTrack) { - Text(player.availableAudioTracks[player.selectedAudioTrackIndex].displayLanguage) + Text(player.selectedAudioTrack?.displayLanguage ?? "Original") .frame(maxWidth: 320) } .contextMenu {