fix: make audio player safe with other app audio/music session
This commit is contained in:
parent
001d216d12
commit
cdbb9cf2d1
|
@ -69,7 +69,8 @@ final class VideoPlayerViewModel {
|
|||
case .gif:
|
||||
break
|
||||
case .video:
|
||||
try? AVAudioSession.sharedInstance().setCategory(.soloAmbient, mode: .default)
|
||||
break
|
||||
// try? AVAudioSession.sharedInstance().setCategory(.soloAmbient, mode: .default)
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
@ -107,7 +108,8 @@ extension VideoPlayerViewModel {
|
|||
case .gif:
|
||||
break
|
||||
case .video:
|
||||
try? AVAudioSession.sharedInstance().setCategory(.soloAmbient, mode: .default)
|
||||
break
|
||||
// try? AVAudioSession.sharedInstance().setCategory(.soloAmbient, mode: .default)
|
||||
}
|
||||
|
||||
player.play()
|
||||
|
|
|
@ -23,7 +23,6 @@ final class AudioPlaybackService: NSObject {
|
|||
var statusObserver: Any?
|
||||
var attachment: Attachment?
|
||||
|
||||
let session = AVAudioSession.sharedInstance()
|
||||
let playbackState = CurrentValueSubject<PlaybackState, Never>(PlaybackState.unknown)
|
||||
|
||||
let currentTimeSubject = CurrentValueSubject<TimeInterval, Never>(0)
|
||||
|
@ -31,6 +30,23 @@ final class AudioPlaybackService: NSObject {
|
|||
override init() {
|
||||
super.init()
|
||||
addObserver()
|
||||
|
||||
playbackState
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { status in
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: audio status: %s", ((#file as NSString).lastPathComponent), #line, #function, status.description)
|
||||
switch status {
|
||||
case .unknown, .buffering, .readyToPlay:
|
||||
break
|
||||
case .playing:
|
||||
try? AVAudioSession.sharedInstance().setCategory(.soloAmbient)
|
||||
try? AVAudioSession.sharedInstance().setActive(true)
|
||||
case .paused, .stopped, .failed:
|
||||
try? AVAudioSession.sharedInstance().setCategory(.ambient)
|
||||
try? AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,12 +55,6 @@ extension AudioPlaybackService {
|
|||
guard let url = URL(string: audioAttachment.url) else {
|
||||
return
|
||||
}
|
||||
do {
|
||||
try session.setCategory(.playback)
|
||||
} catch {
|
||||
print(error)
|
||||
return
|
||||
}
|
||||
|
||||
notifyWillPlayAudioNotification()
|
||||
if audioAttachment == attachment {
|
||||
|
@ -64,27 +74,6 @@ extension AudioPlaybackService {
|
|||
}
|
||||
|
||||
func addObserver() {
|
||||
UIDevice.current.isProximityMonitoringEnabled = true
|
||||
NotificationCenter.default.publisher(for: UIDevice.proximityStateDidChangeNotification, object: nil)
|
||||
.sink { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
if UIDevice.current.proximityState == true {
|
||||
do {
|
||||
try self.session.setCategory(.playAndRecord)
|
||||
} catch {
|
||||
print(error)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
try self.session.setCategory(.playback)
|
||||
} catch {
|
||||
print(error)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
NotificationCenter.default.publisher(for: VideoPlayerViewModel.appWillPlayVideoNotification)
|
||||
.sink { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
|
@ -96,7 +85,7 @@ extension AudioPlaybackService {
|
|||
guard let self = self else { return }
|
||||
self.currentTimeSubject.value = time.seconds
|
||||
})
|
||||
player.publisher(for: \.status, options: .new)
|
||||
player.publisher(for: \.status, options: [.initial, .new])
|
||||
.sink(receiveValue: { [weak self] status in
|
||||
guard let self = self else { return }
|
||||
switch status {
|
||||
|
|
|
@ -23,3 +23,21 @@ public enum PlaybackState : Int {
|
|||
|
||||
case failed = 6
|
||||
}
|
||||
|
||||
// MARK: - CustomStringConvertible
|
||||
extension PlaybackState: CustomStringConvertible {
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .unknown: return "unknown"
|
||||
case .buffering: return "buffering"
|
||||
case .readyToPlay: return "readyToPlay"
|
||||
case .playing: return "playing"
|
||||
case .paused: return "paused"
|
||||
case .stopped: return "stopped"
|
||||
case .failed: return "failed"
|
||||
default:
|
||||
assertionFailure()
|
||||
return "<nil>"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ extension VideoPlaybackService {
|
|||
} else {
|
||||
if latestPlayingVideoPlayerViewModel === playerViewModel {
|
||||
latestPlayingVideoPlayerViewModel = nil
|
||||
try? AVAudioSession.sharedInstance().setCategory(.soloAmbient, mode: .default)
|
||||
// try? AVAudioSession.sharedInstance().setCategory(.soloAmbient, mode: .default)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ extension VideoPlaybackService {
|
|||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", (#file as NSString).lastPathComponent, #line, #function)
|
||||
|
||||
// note: do not retain view controller
|
||||
// pause all player when view disppear exclude full screen player and other transitioning scene
|
||||
// pause all player when view disappear exclude full screen player and other transitioning scene
|
||||
for viewModel in viewPlayerViewModelDict.values {
|
||||
guard !viewModel.isTransitioning else {
|
||||
viewModel.isTransitioning = false
|
||||
|
|
Loading…
Reference in New Issue