mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 19:44:05 +00:00
Fix: release audio session after playback ends (#1992)
This commit is contained in:
@@ -50,8 +50,14 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
|
|||||||
private var appBackgroundObserver: NSObjectProtocol?
|
private var appBackgroundObserver: NSObjectProtocol?
|
||||||
private var autoplay = false
|
private var autoplay = false
|
||||||
|
|
||||||
|
private let audioSession = AVAudioSession.sharedInstance()
|
||||||
|
@CancellableTask private var releaseAudioSessionTask: Task<Void, Never>?
|
||||||
|
private let releaseAudioSessionTimeoutInterval = 5.0
|
||||||
|
|
||||||
private(set) var url: URL?
|
private(set) var url: URL?
|
||||||
|
|
||||||
|
private var deinitInProgress = false
|
||||||
|
|
||||||
var duration: TimeInterval {
|
var duration: TimeInterval {
|
||||||
abs(CMTimeGetSeconds(internalAudioPlayer?.currentItem?.duration ?? .zero))
|
abs(CMTimeGetSeconds(internalAudioPlayer?.currentItem?.duration ?? .zero))
|
||||||
}
|
}
|
||||||
@@ -83,6 +89,7 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
|
|||||||
private var isStopped = true
|
private var isStopped = true
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
|
deinitInProgress = true
|
||||||
stop()
|
stop()
|
||||||
unloadContent()
|
unloadContent()
|
||||||
}
|
}
|
||||||
@@ -100,18 +107,14 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
|
|||||||
|
|
||||||
func play() {
|
func play() {
|
||||||
isStopped = false
|
isStopped = false
|
||||||
do {
|
setupAudioSession()
|
||||||
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
|
|
||||||
try AVAudioSession.sharedInstance().setActive(true)
|
|
||||||
} catch {
|
|
||||||
MXLog.error("Could not redirect audio playback to speakers.")
|
|
||||||
}
|
|
||||||
internalAudioPlayer?.play()
|
internalAudioPlayer?.play()
|
||||||
}
|
}
|
||||||
|
|
||||||
func pause() {
|
func pause() {
|
||||||
guard case .playing = internalState else { return }
|
guard case .playing = internalState else { return }
|
||||||
internalAudioPlayer?.pause()
|
internalAudioPlayer?.pause()
|
||||||
|
releaseAudioSession(after: releaseAudioSessionTimeoutInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stop() {
|
func stop() {
|
||||||
@@ -119,6 +122,7 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
|
|||||||
isStopped = true
|
isStopped = true
|
||||||
internalAudioPlayer?.pause()
|
internalAudioPlayer?.pause()
|
||||||
internalAudioPlayer?.seek(to: .zero)
|
internalAudioPlayer?.seek(to: .zero)
|
||||||
|
releaseAudioSession(after: releaseAudioSessionTimeoutInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
func seek(to progress: Double) async {
|
func seek(to progress: Double) async {
|
||||||
@@ -129,6 +133,37 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
|
|||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
|
private func setupAudioSession() {
|
||||||
|
releaseAudioSessionTask = nil
|
||||||
|
do {
|
||||||
|
try audioSession.setCategory(AVAudioSession.Category.playback)
|
||||||
|
try audioSession.setActive(true)
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Could not redirect audio playback to speakers.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func releaseAudioSession(after timeInterval: TimeInterval) {
|
||||||
|
guard !deinitInProgress else {
|
||||||
|
releaseAudioSession()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
releaseAudioSessionTask = Task { [weak self] in
|
||||||
|
try? await Task.sleep(for: .seconds(timeInterval))
|
||||||
|
guard !Task.isCancelled else { return }
|
||||||
|
guard let self else { return }
|
||||||
|
self.releaseAudioSession()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func releaseAudioSession() {
|
||||||
|
releaseAudioSessionTask = nil
|
||||||
|
if audioSession.category == .playback, !audioSession.isOtherAudioPlaying {
|
||||||
|
MXLog.info("releasing audio session")
|
||||||
|
try? audioSession.setActive(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func unloadContent() {
|
private func unloadContent() {
|
||||||
mediaSource = nil
|
mediaSource = nil
|
||||||
url = nil
|
url = nil
|
||||||
@@ -183,6 +218,8 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
|
|||||||
.sink { [weak self] _ in
|
.sink { [weak self] _ in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
self.pause()
|
self.pause()
|
||||||
|
// Release the audio session right away, as we don't play audio in the background
|
||||||
|
self.releaseAudioSession()
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user