当前位置: 首页 > 知识库问答 >
问题:

Callkit和Webrtc没有音频时接受呼叫从锁定屏幕

连翰
2023-03-14

我试图让callkit在传入呼叫时与webrtc一起工作,但当我从锁定屏幕接收呼叫并接受它时,在我以前台模式运行应用程序之前,不会有声音。我已配置audiosession向RTCAudoSession发送通知,但它不起作用。你有解决办法吗?

      func configureAudioSession() {

        let sharedSession = AVAudioSession.sharedInstance()
        do {
            try sharedSession.setCategory(AVAudioSessionCategoryPlayAndRecord, mode: AVAudioSessionModeVideoChat, options: .mixWithOthers)
            try sharedSession.setMode(AVAudioSessionModeVideoChat)
//            try sharedSession.setAggregatedIOPreference(AVAudioSessionIOType.aggregated)
        } catch {
            debugPrint("Failed to configure `AVAudioSession`")
        }
    }

    func handleIncomingCall(spaceName:String) {
        if callUUID != nil {
            oldCallUUID = callUUID
        }
        callUUID = UUID()
        print("CallManager handle uuid = \(callUUID?.description)")
        let update = CXCallUpdate()
        update.hasVideo = true
        update.remoteHandle = CXHandle(type: .generic, value: spaceName)
        self.configureAudioSession()
        provider?.reportNewIncomingCall(with: callUUID!, update: update, completion: { error in
            print("CallManager report new incoming call completion")
        })
    }

 func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
        print("CallManager didActivate")
        RTCAudioSession.sharedInstance().audioSessionDidActivate(audioSession)
        RTCAudioSession.sharedInstance().isAudioEnabled = true
        self.callDelegate?.callIsAnswered()
    }

    func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
        print("CallManager didDeactivate")
        RTCAudioSession.sharedInstance().audioSessionDidDeactivate(audioSession)
        RTCAudioSession.sharedInstance().isAudioEnabled = false
    }

共有3个答案

柯瀚海
2023-03-14

请注意,我分享我的代码,它将满足我的需要,我分享以供参考。您需要根据需要进行更改。

当您收到voip通知时,创建webrtc处理类的新事件,并将这两行代码添加到代码块,因为从voip通知启用音频会话失败

RTCAudioSession.sharedInstance().useManualAudio = true
RTCAudioSession.sharedInstance().isAudioEnabled = false 

双接收法;

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
               let state = UIApplication.shared.applicationState
               
        
     
                   if(payload.dictionaryPayload["hangup"] == nil && state != .active
                   ){
                       
               
                     Globals.voipPayload = payload.dictionaryPayload as! [String:Any] // I pass parameters to Webrtc handler via Global singleton to create answer according to sdp sent by payload.
                        
                       RTCAudioSession.sharedInstance().useManualAudio = true
                       RTCAudioSession.sharedInstance().isAudioEnabled = false
                       
                     
                      
                     Globals.sipGateway = SipGateway() // my Webrtc and Janus gateway handler class
                    
                       
                     Globals.sipGateway?.configureCredentials(true) // I check janus gateway credentials stored in Shared preferences and initiate websocket connection and create peerconnection 
to my janus gateway which is signaling server for my environment
                    
                       
                  initProvider() //Crating callkit provider
                       
                       self.update.remoteHandle = CXHandle(type: .generic, value:String(describing: payload.dictionaryPayload["caller_id"]!))
                          Globals.callId = UUID()
             
                       let state = UIApplication.shared.applicationState
                       
                      
                          Globals.provider.reportNewIncomingCall(with:Globals.callId , update: self.update, completion: { error in
                           
                           
                          })
                       
                
               }
              
           }
    
        
        func  initProvider(){
            let config = CXProviderConfiguration(localizedName: "ulakBEL")
            config.iconTemplateImageData = UIImage(named: "ulakbel")!.pngData()
            config.ringtoneSound = "ringtone.caf"
                   // config.includesCallsInRecents = false;
                    config.supportsVideo = false
            
            Globals.provider = CXProvider(configuration:config )
            Globals.provider.setDelegate(self, queue: nil)
             update = CXCallUpdate()
             update.hasVideo = false
             update.supportsDTMF = true
      
        }
    

修改您的didActivate和didDeActive委托函数,如下所示,

func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
       print("CallManager didActivate")
       RTCAudioSession.sharedInstance().audioSessionDidActivate(audioSession)
       RTCAudioSession.sharedInstance().isAudioEnabled = true
      // self.callDelegate?.callIsAnswered()
    
 
   }

   func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
       print("CallManager didDeactivate")
RTCAudioSession.sharedInstance().audioSessionDidDeactivate(audioSession)
       RTCAudioSession.sharedInstance().isAudioEnabled = false
    
 
   }

在Webrtc处理程序类中,配置媒体发送器和audiosession

private func createPeerConnection(webRTCCallbacks:PluginHandleWebRTCCallbacksDelegate) {
   
        let rtcConfig =  RTCConfiguration.init()
        rtcConfig.iceServers = server.iceServers
        rtcConfig.bundlePolicy = RTCBundlePolicy.maxBundle
        rtcConfig.rtcpMuxPolicy = RTCRtcpMuxPolicy.require
        rtcConfig.continualGatheringPolicy = .gatherContinually
        rtcConfig.sdpSemantics = .planB
        
        let constraints = RTCMediaConstraints(mandatoryConstraints: nil,
                                                 optionalConstraints: ["DtlsSrtpKeyAgreement":kRTCMediaConstraintsValueTrue])
           
        pc = sessionFactory.peerConnection(with: rtcConfig, constraints: constraints, delegate: nil)
        self.createMediaSenders()
        self.configureAudioSession()
        
   
        
      if webRTCCallbacks.getJsep() != nil{
        handleRemoteJsep(webrtcCallbacks: webRTCCallbacks)
        }
      
    }

媒体发送者;

private func createMediaSenders() {
        let streamId = "stream"
        
        // Audio
        let audioTrack = self.createAudioTrack()
        self.pc.add(audioTrack, streamIds: [streamId])
        
        // Video
      /*  let videoTrack = self.createVideoTrack()
        self.localVideoTrack = videoTrack
        self.peerConnection.add(videoTrack, streamIds: [streamId])
        self.remoteVideoTrack = self.peerConnection.transceivers.first { $0.mediaType == .video }?.receiver.track as? RTCVideoTrack
        
        // Data
        if let dataChannel = createDataChannel() {
            dataChannel.delegate = self
            self.localDataChannel = dataChannel
        }*/
    }

  private func createAudioTrack() -> RTCAudioTrack {
        let audioConstrains = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: nil)
        let audioSource = sessionFactory.audioSource(with: audioConstrains)
        let audioTrack = sessionFactory.audioTrack(with: audioSource, trackId: "audio0")
        return audioTrack
    }

音频会议;

private func configureAudioSession() {
        self.rtcAudioSession.lockForConfiguration()
        do {
            try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue)
            try self.rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)
        } catch let error {
            debugPrint("Error changeing AVAudioSession category: \(error)")
        }
        self.rtcAudioSession.unlockForConfiguration()
    }

请考虑,因为我工作的回调和委托代码包括委托和回调块。

供参考您也可以在此链接查看示例

杨凯旋
2023-03-14

您测试的iPhone的iOS版本是什么?

齐涛
2023-03-14

好的,我找到了问题的原因。在IOS 12中,webrtc存在一个问题,当您从锁定屏幕启动webrtc并尝试访问摄像头时,输出音量会中断,因此解决方案是检查屏幕是否处于活动状态,如果不是,则不要请求并将本地RTCDeoTrack添加到RTCStream中。

 类似资料:
  • 这是一个会议应用程序,我正在启动传出呼叫,以使我的VoIP呼叫具有高优先级,并且在我进行VoIP呼叫时不会中断传入呼叫。 我在我的应用程序中使用WebRTC CallKit。我开始了一个呼叫,当我按下锁定/电源按钮,然后CallKit呼叫断开,我的Voip呼叫音频路由更改为接收器并保持不变。 为什么要锁定iPhone以终止通话。 这是我的代码。

  • 我在这里尝试了许多解决方案,但没有人奏效。WebRTC工作正常,我在设备锁定时接听电话时处于连接状态,解锁后音频打开,视频启动。当屏幕保持锁定状态时,我如何只能获得音频? 我已启用RTCAdioSession,并在呼叫停止时将其禁用。 当设备第一次解锁时,它工作得很好,当我把它锁回去时,我得到了音频。但是第一次,当我接听来自CallKit的电话时,它不起作用。它只在设备解锁后才开始工作。

  • 我们的项目使用WebRTC进行VOIP呼叫,并且在访问CallKit框架之前运行良好。但是当我试图访问CallKit框架时,出现了双方都听不到对方讲话的情况。当我删除CallKit时,一切恢复正常。 CallKit的应答按钮与项目中的原始应答按钮功能相同。 令我惊讶的是,没有必要听到任何声音。有时一切正常,但有时会有问题。嗯,出现问题的可能性更大。 此外,我很好奇套接字不稳定是否会导致CallKi

  • 如果我们在前台启动应用程序,一切都很好。但是,当应用程序之前被杀死并通过在锁定屏幕上接收PushKit通知而重新启动时,会出现问题。 当应用程序收到PushKit通知时,我们将显示CallKit UI。这是正确的。用户可以通过WebRTC接听电话并建立连接。但是根本没有音频。 奇怪的是,如果用户通过点击应用程序图标从CallKit屏幕打开应用程序,音频就会启动并按预期工作。看来问题出在音频会话配置

  • 录制完一个呼出的电话后,我试图播放录制的文件——以确保通话录音按预期工作(我使用“媒体播放器”进行),但没有声音。所以我试图访问手机上的实际文件(只需将手机连接到电脑上并访问它的文件)。当我播放录音时,它的长度是正确的,但同样没有声音。 我错过了什么? 这是我记录电话的方式: 这是结束通话记录的代码: 这是我播放音频文件的方式:

  • 我已经开发了一个用于WebRTC视频呼叫的android应用程序,运行良好。现在的要求是记录通话音频并将其存储在外部存储器中。我尝试过MedieRecorder,它正在录制音频并存储,但这里面临一个问题。当我开始录制音频时,声音在接收器一侧停止。Media Recorder不允许webrtc使用麦克风。 我尝试了以下代码。 我也尝试过“录音机”音频源(媒体记录器,音频源.MIC);录音机音频源(M