From ec4ec420671942a44681f8ed0f3269ca93ceafe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20D=C3=A9fago?= Date: Fri, 13 Oct 2023 07:32:00 +0200 Subject: [PATCH] Fix media selection issues when altering current selection programmatically (#600) --- Sources/Player/Internal/QueuePlayer.swift | 20 +++++++++++++++++++ Sources/Player/Player+MediaSelection.swift | 12 +++++++++++ .../Player/UserInterface/SettingsMenu.swift | 9 +-------- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/Sources/Player/Internal/QueuePlayer.swift b/Sources/Player/Internal/QueuePlayer.swift index 88bec1fb4..5f8157d36 100644 --- a/Sources/Player/Internal/QueuePlayer.swift +++ b/Sources/Player/Internal/QueuePlayer.swift @@ -30,6 +30,10 @@ class QueuePlayer: AVQueuePlayer { private var pendingSeeks = Deque() + // Starting with iOS 17 accessing media selection criteria might be slow. Use a cache for the lifetime of the + // player. + var mediaSelectionCriteria: [AVMediaCharacteristic: AVPlayerMediaSelectionCriteria?] = [:] + private var targetSeek: Seek? { pendingSeeks.last } @@ -130,6 +134,22 @@ class QueuePlayer: AVQueuePlayer { private func notifySeekEnd() { Self.notificationCenter.post(name: .didSeek, object: self) } + + override func mediaSelectionCriteria(forMediaCharacteristic mediaCharacteristic: AVMediaCharacteristic) -> AVPlayerMediaSelectionCriteria? { + if let cachedCriteria = mediaSelectionCriteria[mediaCharacteristic] { + return cachedCriteria + } + else { + let criteria = super.mediaSelectionCriteria(forMediaCharacteristic: mediaCharacteristic) + mediaSelectionCriteria[mediaCharacteristic] = criteria + return criteria + } + } + + override func setMediaSelectionCriteria(_ criteria: AVPlayerMediaSelectionCriteria?, forMediaCharacteristic mediaCharacteristic: AVMediaCharacteristic) { + mediaSelectionCriteria[mediaCharacteristic] = criteria + super.setMediaSelectionCriteria(criteria, forMediaCharacteristic: mediaCharacteristic) + } } extension AVQueuePlayer { diff --git a/Sources/Player/Player+MediaSelection.swift b/Sources/Player/Player+MediaSelection.swift index 34612d686..1578535d8 100644 --- a/Sources/Player/Player+MediaSelection.swift +++ b/Sources/Player/Player+MediaSelection.swift @@ -79,6 +79,18 @@ public extension Player { queuePlayer.setMediaSelectionCriteria(updatedSelectionCriteria, forMediaCharacteristic: characteristic) } + /// A binding to read and write the current media selection for a characteristic. + /// + /// - Parameter characteristic: The characteristic. + /// - Returns: The binding. + func mediaOption(for characteristic: AVMediaCharacteristic) -> Binding { + .init { + self.selectedMediaOption(for: characteristic) + } set: { newValue in + self.select(mediaOption: newValue, for: characteristic) + } + } + /// The current media option for a characteristic. /// /// - Parameter characteristic: The characteristic. diff --git a/Sources/Player/UserInterface/SettingsMenu.swift b/Sources/Player/UserInterface/SettingsMenu.swift index 4c9bf20b2..094c9bf89 100644 --- a/Sources/Player/UserInterface/SettingsMenu.swift +++ b/Sources/Player/UserInterface/SettingsMenu.swift @@ -33,21 +33,14 @@ private struct PlaybackSpeedMenuContent: View { private struct MediaSelectionMenuContent: View { let characteristic: AVMediaCharacteristic @ObservedObject var player: Player - @State private var selection: MediaSelectionOption = .automatic var body: some View { - Picker("", selection: $selection) { + Picker("", selection: player.mediaOption(for: characteristic)) { ForEach(mediaOptions, id: \.self) { option in Text(option.displayName).tag(option) } } .pickerStyle(.inline) - .onAppear { - selection = player.selectedMediaOption(for: characteristic) - } - .onChange(of: selection) { value in - player.select(mediaOption: value, for: characteristic) - } } private var mediaOptions: [MediaSelectionOption] {