diff --git a/apps/ios/Shared/Model/AudioRecPlay.swift b/apps/ios/Shared/Model/AudioRecPlay.swift index 78773f5ea..a9d0d6c1d 100644 --- a/apps/ios/Shared/Model/AudioRecPlay.swift +++ b/apps/ios/Shared/Model/AudioRecPlay.swift @@ -61,6 +61,7 @@ class AudioRecorder { await MainActor.run { AppDelegate.keepScreenOn(false) } + try? av.setCategory(AVAudioSession.Category.soloAmbient) logger.error("AudioRecorder startAudioRecording error \(error.localizedDescription)") return .error(error.localizedDescription) } @@ -76,6 +77,7 @@ class AudioRecorder { } recordingTimer = nil AppDelegate.keepScreenOn(false) + try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.soloAmbient) } private func checkPermission() async -> Bool { @@ -129,6 +131,9 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate { AppDelegate.keepScreenOn(true) guard let time = self.audioPlayer?.currentTime else { return } self.onTimer?(time) + AudioPlayer.changeAudioSession(true) + } else { + AudioPlayer.changeAudioSession(false) } } } @@ -157,6 +162,7 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate { if let player = audioPlayer { player.stop() AppDelegate.keepScreenOn(false) + AudioPlayer.changeAudioSession(false) } audioPlayer = nil if let timer = playbackTimer { @@ -165,6 +171,24 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate { playbackTimer = nil } + static func changeAudioSession(_ playback: Bool) { + // When there is a audio recording, setting any other category will disable sound + if AVAudioSession.sharedInstance().category == .playAndRecord { + return + } + if playback { + if AVAudioSession.sharedInstance().category != .playback { + logger.log("AudioSession: playback") + try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: .duckOthers) + } + } else { + if AVAudioSession.sharedInstance().category != .soloAmbient { + logger.log("AudioSession: soloAmbient") + try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.soloAmbient) + } + } + } + func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { stop() self.onFinishPlayback?() diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift index bc7153ed4..be8b25a0f 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift @@ -9,6 +9,7 @@ import SwiftUI import AVKit import SimpleXChat +import Combine struct CIVideoView: View { @EnvironmentObject var m: ChatModel @@ -28,6 +29,7 @@ struct CIVideoView: View { @State private var showFullScreenPlayer = false @State private var timeObserver: Any? = nil @State private var fullScreenTimeObserver: Any? = nil + @State private var publisher: AnyCancellable? = nil init(chatItem: ChatItem, image: String, duration: Int, maxWidth: CGFloat, videoWidth: Binding, scrollProxy: ScrollViewProxy?) { self.chatItem = chatItem @@ -294,6 +296,14 @@ struct CIVideoView: View { m.stopPreviousRecPlay = url if let player = fullPlayer { player.play() + var played = false + publisher = player.publisher(for: \.timeControlStatus).sink { status in + if played || status == .playing { + AppDelegate.keepScreenOn(status == .playing) + AudioPlayer.changeAudioSession(status == .playing) + } + played = status == .playing + } fullScreenTimeObserver = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: .main) { _ in player.seek(to: CMTime.zero) player.play() @@ -308,6 +318,7 @@ struct CIVideoView: View { fullScreenTimeObserver = nil fullPlayer?.pause() fullPlayer?.seek(to: CMTime.zero) + publisher?.cancel() } } } diff --git a/apps/ios/Shared/Views/Helpers/VideoPlayerView.swift b/apps/ios/Shared/Views/Helpers/VideoPlayerView.swift index 416fa0c37..33acf22eb 100644 --- a/apps/ios/Shared/Views/Helpers/VideoPlayerView.swift +++ b/apps/ios/Shared/Views/Helpers/VideoPlayerView.swift @@ -38,8 +38,13 @@ struct VideoPlayerView: UIViewRepresentable { player.seek(to: CMTime.zero) player.play() } + var played = false context.coordinator.publisher = player.publisher(for: \.timeControlStatus).sink { status in - AppDelegate.keepScreenOn(status == .playing) + if played || status == .playing { + AppDelegate.keepScreenOn(status == .playing) + AudioPlayer.changeAudioSession(status == .playing) + } + played = status == .playing } return controller.view }