ios: allow sound in silent mode (#3346)

Co-authored-by: Avently <avently@local>
This commit is contained in:
Stanislav Dmitrenko 2023-11-11 03:27:06 +08:00 committed by GitHub
parent 9cc232054c
commit ae286124aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 1 deletions

View File

@ -61,6 +61,7 @@ class AudioRecorder {
await MainActor.run { await MainActor.run {
AppDelegate.keepScreenOn(false) AppDelegate.keepScreenOn(false)
} }
try? av.setCategory(AVAudioSession.Category.soloAmbient)
logger.error("AudioRecorder startAudioRecording error \(error.localizedDescription)") logger.error("AudioRecorder startAudioRecording error \(error.localizedDescription)")
return .error(error.localizedDescription) return .error(error.localizedDescription)
} }
@ -76,6 +77,7 @@ class AudioRecorder {
} }
recordingTimer = nil recordingTimer = nil
AppDelegate.keepScreenOn(false) AppDelegate.keepScreenOn(false)
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.soloAmbient)
} }
private func checkPermission() async -> Bool { private func checkPermission() async -> Bool {
@ -129,6 +131,9 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate {
AppDelegate.keepScreenOn(true) AppDelegate.keepScreenOn(true)
guard let time = self.audioPlayer?.currentTime else { return } guard let time = self.audioPlayer?.currentTime else { return }
self.onTimer?(time) self.onTimer?(time)
AudioPlayer.changeAudioSession(true)
} else {
AudioPlayer.changeAudioSession(false)
} }
} }
} }
@ -157,6 +162,7 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate {
if let player = audioPlayer { if let player = audioPlayer {
player.stop() player.stop()
AppDelegate.keepScreenOn(false) AppDelegate.keepScreenOn(false)
AudioPlayer.changeAudioSession(false)
} }
audioPlayer = nil audioPlayer = nil
if let timer = playbackTimer { if let timer = playbackTimer {
@ -165,6 +171,24 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate {
playbackTimer = nil 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) { func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
stop() stop()
self.onFinishPlayback?() self.onFinishPlayback?()

View File

@ -9,6 +9,7 @@
import SwiftUI import SwiftUI
import AVKit import AVKit
import SimpleXChat import SimpleXChat
import Combine
struct CIVideoView: View { struct CIVideoView: View {
@EnvironmentObject var m: ChatModel @EnvironmentObject var m: ChatModel
@ -28,6 +29,7 @@ struct CIVideoView: View {
@State private var showFullScreenPlayer = false @State private var showFullScreenPlayer = false
@State private var timeObserver: Any? = nil @State private var timeObserver: Any? = nil
@State private var fullScreenTimeObserver: 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<CGFloat?>, scrollProxy: ScrollViewProxy?) { init(chatItem: ChatItem, image: String, duration: Int, maxWidth: CGFloat, videoWidth: Binding<CGFloat?>, scrollProxy: ScrollViewProxy?) {
self.chatItem = chatItem self.chatItem = chatItem
@ -294,6 +296,14 @@ struct CIVideoView: View {
m.stopPreviousRecPlay = url m.stopPreviousRecPlay = url
if let player = fullPlayer { if let player = fullPlayer {
player.play() 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 fullScreenTimeObserver = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: .main) { _ in
player.seek(to: CMTime.zero) player.seek(to: CMTime.zero)
player.play() player.play()
@ -308,6 +318,7 @@ struct CIVideoView: View {
fullScreenTimeObserver = nil fullScreenTimeObserver = nil
fullPlayer?.pause() fullPlayer?.pause()
fullPlayer?.seek(to: CMTime.zero) fullPlayer?.seek(to: CMTime.zero)
publisher?.cancel()
} }
} }
} }

View File

@ -38,8 +38,13 @@ struct VideoPlayerView: UIViewRepresentable {
player.seek(to: CMTime.zero) player.seek(to: CMTime.zero)
player.play() player.play()
} }
var played = false
context.coordinator.publisher = player.publisher(for: \.timeControlStatus).sink { status in 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 return controller.view
} }