CallKit 可以在交换通话后重新激活声音

Posted

技术标签:

【中文标题】CallKit 可以在交换通话后重新激活声音【英文标题】:CallKit can reactivate sound after swapping call 【发布时间】:2017-11-21 15:16:43 【问题描述】:

我正在开发 CallKit 应用程序,我有一个问题,在 CallKit 屏幕上“交换”呼叫时,呼叫保持无法重新启动音频,直到用户返回到应用内呼叫屏幕。我可以通过更新绕过这个:

supportsHolding = false

但是我可以解决这个问题,例如 whatsapp 可以正确地做到这一点!

附言我正在使用 webrtc 拨打电话!

谢谢!

编辑:

这是提供者的代码:

public func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) 

    guard let call = conductor!.callWithUUID(uuid: action.callUUID) else 
        WebRtcConductor.debug("\(self.TAG) ???? failed to perform HeldAction: uuid: \(action.uuid), calluiid: \(action.callUUID)")
        action.fail()
        return
    

    setIsHeld(call: call, isHeld: action.isOnHold)
    action.fulfill()

setIsHeld 函数简单地做:

audioTrack.isEnabled = enabled

如果我使用 callkit 屏幕的“静音”按钮,一切正常,但如果我有 2 个活动呼叫,当我从 webrtc 呼叫滑动到正常呼叫时,调用 CXSetHeldCallAction 并且音轨确实被禁用,如果我再次滑动到webrtc 调用,音轨已启用,但我什么也没听到,如果我返回主应用程序屏幕,音频又可以正常工作了!

【问题讨论】:

请展示您编写的相关代码,但也要清楚说明会发生什么以及您期望会发生什么。 我添加了更多代码!谢谢! 嗨@LucaBecchetti,你解决了这个问题吗? 【参考方案1】:

实际上,在实现支持交换调用的 CallKit 集成时,Google WebRTC 库中存在一个限制,这会导致所描述的问题。

WebRTC Issue 8126 已知已有一年多,但尚未集成到 WebRTC 主分支中。但是,您可以在原始票证中找到必要的代码更改来解决此问题。

但是,作为一种解决方法,您可以触发 WebRTC 内部订阅的系统通知。

在 CallKit Provider 的“didActivate audiosession”方法中发布AVAudioSessionInterruptionType.ended 通知:

var userInfo = Dictionary<AnyHashable, Any>()
let interrupttioEndedRaw = AVAudioSessionInterruptionType.ended.rawValue
userInfo[AVAudioSessionInterruptionTypeKey] = interrupttioEndedRaw
NotificationCenter.default.post(name: NSNotification.Name.AVAudioSessionInterruption, object: self, userInfo: userInfo)

PS:盯着票以增加合并的机会;-)

【讨论】:

对于 Swift 4:NotificationCenter.default.post(name: AVAudioSession.interruptionNotification, object: self, userInfo: userInfo) 我应该在哪里使用它?填满后? @WorieN in 'didActivate audioSession' 感谢您为我工作。 func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) print("Provider - Activate Audio Session: (audioSession.category)") var userInfo = Dictionary() let interrupttioEndedRaw = AVAudioSession.InterruptionType.ended。 rawValue userInfo[AVAudioSessionInterruptionTypeKey] = interrupttioEndedRaw NotificationCenter.default.post(name: AVAudioSession.interruptionNotification, object: self, userInfo: userInfo) 对我来说很酷,我使用 Tokbox 而不是 Google WebRTC,尝试了所有方法但没有让它工作,但触发系统通知让它也适用于 Tokbox!谢谢!【参考方案2】:

有同样的问题。如果我有 1 个活动呼叫,然后有新呼叫,我点击保持并接受。新通话有效,但在 CallKit 中使用 Swap 后音频停止工作。

发现CXProviderDelegate 协议中的provider:performSetHeldCallAction: 方法是您可以通过CallKit 本机接口为Swap 调用实际停用/激活音频的地方。

在我的例子中,我使用audioController.deactivateAudioSession() 方法将呼叫置于 OnHold 中。 但发现当通过 CallKit 轻按 Swap 按钮时,对于其他处于活动状态(从 OnHold 状态)的呼叫,会触发相同的方法 provider:performSetHeldCallAction:

因此,您只需分别停用/激活音频即可进入通话状态(保持或不保持)。

通常它应该是这样的:

func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) 
    // Retrieve the Call instance corresponding to the action's call UUID
    guard let call = callManager.callWithUUID(uuid: action.callUUID) else 
        action.fail()
        return
    

    // Update the Call's underlying hold state.
    call.isOnHold = action.isOnHold

    // Stop or start audio in response to holding or unholding the call.
    if call.isOnHold 
        stopAudio()
     else 
        startAudio()
    

    // Signal to the system that the action has been successfully performed.
    action.fulfill()

附:看起来您应该有一些响应音频会话的类。它应该实现activate audio session / deactivate audio session

【讨论】:

这在我的情况下不起作用。我也在使用 WebRTC 并将audioTrack.isEnabled 设置为false(对于本地和远程轨道)。这可能与 WebRTC 如何在内部处理音频有关。但是,在交换呼叫后(通过按 CallKit UI 中的“我的应用程序”按钮)强制应用程序回到前台时,音频再次工作(传入和传出 - 这很神奇)。 哦,我面临着完全相同的问题。你解决了这个问题吗? @Bogdan 你找到解决这个问题的方法了吗? @AhadKhan 不幸的是,那个项目是 2 年前的,从那以后我就没有参与过那个项目。从那时起,Swift 版本也发生了变化。因此,您可以将该想法用作方法或模式。对我来说,它确实有效,并且在通过本机 iOS 界面交换呼叫时真正解决了声音问题 @AhadKhan 我看到你正在使用 WebRTC。这可能是个问题。您需要检查声音的“静音”/“取消静音”方法类型,或者检查流是否暂停或取消暂停。

以上是关于CallKit 可以在交换通话后重新激活声音的主要内容,如果未能解决你的问题,请参考以下文章

当我从 callKit 结束通话时,通话没有结束,我可以看到绿色的状态栏

手机通话声音小,怎么解决,用了很多软件,不行。

CallKit + WebRTC:在 iOS 中按下锁定/电源按钮时 CallKit 通话断开

CallKit:屏幕锁定时启动应用程序

CallKit 与 OpenTok 一起使用

技术福利干货音视频 iOS CallKit 开发指南