首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何中断设备音频以播放声音,然后让设备音频在iOS上继续播放

如何中断设备音频以播放声音,然后让设备音频在iOS上继续播放
EN

Stack Overflow用户
提问于 2022-03-30 11:23:30
回答 3查看 583关注 0票数 1

我有一个应用程序,用户可以播放从其他用户收到的语音信息。播放语音信息应该中断设备音频(音乐、播客等),播放语音信息,然后让设备音频继续播放。

下面是我正在尝试实现的一个特定的用例

  • 用户通过Apple
  • 在设备上播放音乐,用户打开应用程序并点击语音消息
  • ,Apple停止
  • 语音消息在应用程序中播放
  • Apple继续播放H 210F 211

通过将AVAudioSession的分类设置为.ambient,我可以播放“播放”Apple的语音信息,但这并不是我所需要的。

如果我使用使Apple停止的.playback类别,则在应用程序中播放语音信息,但是Apple之后不会继续播放。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-03-30 13:26:36

理论上,苹果为中断和恢复背景音频提供了一个“协议”,在一个可下载的例子中,我向您展示了它是什么,并证明了它的工作原理:

https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/bk2ch14p653backgroundPlayerAndInterrupter

在这个例子中,有两个项目,代表两个不同的应用程序。你把它们同时运行。BackgroundPlayer在后台播放声音;断续器中断它,暂停它,当中断结束时,BackgroundPlayer恢复。

正如您将看到的,这是通过让断续器在中断时将其音频会话类别从环境切换到回放,并在中断结束时将其更改回原点,以及在发送.notifyOthersOnDeactivation信号时首先完全停用自己:

代码语言:javascript
运行
复制
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,表现很好。这就是它所做的:

代码语言:javascript
运行
复制
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)继续播放,但更安静。

票数 3
EN

Stack Overflow用户

发布于 2022-03-30 12:40:24

您已经发现,您可以通过激活.playback类别音频会话来中断其他音频应用程序。当您完成您的音频播放,并希望中断的音频继续,停用您的音频会话,并通过notifyOthersOnDeactivation选项。

例如:

代码语言:javascript
运行
复制
try! audioSession.setActive(false, options: .notifyOthersOnDeactivation)
票数 0
EN

Stack Overflow用户

发布于 2022-03-30 12:40:52

我认为那些应该继续使用的应用程序,如Apple Music、Spotify、Radio Apple等,实现了处理中断的功能,以及当另一个应用的音频被停用/想要归还音频的责任时。

所以你能试着看看这是否有效吗

代码语言:javascript
运行
复制
// 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)
        }
        
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71676330

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档