我有一个应用程序,用户可以播放从其他用户收到的语音信息。播放语音信息应该中断设备音频(音乐、播客等),播放语音信息,然后让设备音频继续播放。
下面是我正在尝试实现的一个特定的用例
H 210F 211
通过将AVAudioSession的分类设置为.ambient,我可以播放“播放”Apple的语音信息,但这并不是我所需要的。
如果我使用使Apple停止的.playback类别,则在应用程序中播放语音信息,但是Apple之后不会继续播放。
发布于 2022-03-30 13:26:36
理论上,苹果为中断和恢复背景音频提供了一个“协议”,在一个可下载的例子中,我向您展示了它是什么,并证明了它的工作原理:
在这个例子中,有两个项目,代表两个不同的应用程序。你把它们同时运行。BackgroundPlayer在后台播放声音;断续器中断它,暂停它,当中断结束时,BackgroundPlayer恢复。
正如您将看到的,这是通过让断续器在中断时将其音频会话类别从环境切换到回放,并在中断结束时将其更改回原点,以及在发送.notifyOthersOnDeactivation
信号时首先完全停用自己:
func playFile(atPath path:String) {
self.player?.delegate = nil
self.player?.stop()
let fileURL = URL(fileURLWithPath: path)
guard let p = try? AVAudioPlayer(contentsOf: fileURL) else {return} // nicer
self.player = p
// error-checking omitted
// switch to playback category while playing, interrupt background audio
try? AVAudioSession.sharedInstance().setCategory(.playback, mode:.default)
try? AVAudioSession.sharedInstance().setActive(true)
self.player.prepareToPlay()
self.player.delegate = self
let ok = self.player.play()
print("interrupter trying to play \(path): \(ok)")
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { // *
let sess = AVAudioSession.sharedInstance()
// this is the key move
try? sess.setActive(false, options: .notifyOthersOnDeactivation)
// now go back to ambient
try? sess.setCategory(.ambient, mode:.default)
try? sess.setActive(true)
delegate?.soundFinished(self)
}
然而,问题在于,对.notifyOthersOnDeactivation
的响应完全取决于另一个应用程序是否表现良好。我的另一个应用,BackgroundPlayer,表现很好。这就是它所做的:
self.observer = NotificationCenter.default.addObserver(forName:
AVAudioSession.interruptionNotification, object: nil, queue: nil) {
[weak self] n in
guard let self = self else { return } // legal in Swift 4.2
let why = n.userInfo![AVAudioSessionInterruptionTypeKey] as! UInt
let type = AVAudioSession.InterruptionType(rawValue: why)!
switch type {
case .began:
print("interruption began:\n\(n.userInfo!)")
case .ended:
print("interruption ended:\n\(n.userInfo!)")
guard let opt = n.userInfo![AVAudioSessionInterruptionOptionKey] as? UInt else {return}
let opts = AVAudioSession.InterruptionOptions(rawValue: opt)
if opts.contains(.shouldResume) {
print("should resume")
self.player.prepareToPlay()
let ok = self.player.play()
print("bp tried to resume play: did I? \(ok as Any)")
} else {
print("not should resume")
}
@unknown default:
fatalError()
}
}
如您所见,我们注册中断通知,如果中断,则查找.shouldResume
选项--这是中断器首先设置notifyOthersOnDeactivation
的结果。
到现在为止还好。但这有个障碍。在这方面,有些应用程序表现不佳。最不守规矩的是苹果自己的音乐应用程序!因此,实际上不可能让音乐应用程序做你想做的事情。你最好使用ducking,系统只是为您调整两个应用程序的相对级别,允许后台应用程序(Music)继续播放,但更安静。
发布于 2022-03-30 12:40:24
您已经发现,您可以通过激活.playback
类别音频会话来中断其他音频应用程序。当您完成您的音频播放,并希望中断的音频继续,停用您的音频会话,并通过notifyOthersOnDeactivation
选项。
例如:
try! audioSession.setActive(false, options: .notifyOthersOnDeactivation)
发布于 2022-03-30 12:40:52
我认为那些应该继续使用的应用程序,如Apple Music、Spotify、Radio Apple等,实现了处理中断的功能,以及当另一个应用的音频被停用/想要归还音频的责任时。
所以你能试着看看这是否有效吗
// I play the audio using this AVAudioPlayer
var player: AVAudioPlayer?
// Implement playing a sound
func playSound() {
// Local url for me, but you could configure as you need
guard let url = Bundle.main.url(forResource: "se_1",
withExtension: "wav")
else { return }
do {
// Set the category to playback to interrupt the current audio
try AVAudioSession.sharedInstance().setCategory(.playback,
mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
player = try AVAudioPlayer(contentsOf: url)
// This is to know when the sound has ended
player?.delegate = self
player?.play()
} catch let error {
print(error.localizedDescription)
}
}
extension AVAudioInterruptVC: AVAudioPlayerDelegate {
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer,
successfully flag: Bool) {
do {
// When the sound has ended, notify other apps
// You can do this where ever you want, I just show the
// example of doing it when the audio has ended
try AVAudioSession.sharedInstance()
.setActive(false, options: [.notifyOthersOnDeactivation])
}
catch {
print(error)
}
}
}
https://stackoverflow.com/questions/71676330
复制相似问题