WebRTC从WKWebView AVAudioSession运行开发障碍

ddrv8njm  于 2022-11-26  发布在  iOS
关注(0)|答案(1)|浏览(137)

在过去的几年里,我已经稳定地开发了一个完整的基于WebRTC的浏览器电话使用SIP协议。主要的SIP工具箱是SIPJS(https://sipjs.com/),它提供了所有的工具,一个需要作出和接收呼叫到一个基于SIP的PBX自己。
浏览器电话项目:https://github.com/InnovateAsterisk/Browser-Phone/为SIPJS提供了完整的功能和用户界面。你可以简单地在浏览器中导航到手机并开始使用它。一切都会完美地运行。

在移动的上

苹果终于允许在WKWebView上使用WebRTC(getUserMedia()),所以没过多久人们就开始问它在移动的上会如何工作。虽然UI非常适合手机和平板电脑,但现在仅仅是UI还不足以成为一个完整的解决方案。
主要的考虑是移动的应用程序通常寿命较短,因为你不能或不可以让它在后台运行,就像你可以或愿意在PC上运行浏览器一样。这给真正让浏览器手机移动的友好带来了一些挑战。iOS会希望一旦它不是最前面的应用程序就关闭它--这是正确的。所以有一些工具可以处理这个问题,比如Callkit & Push Notifications。这允许应用程序被唤醒,这样它就可以接受呼叫,并通知用户。
请记住,这个应用程序是通过打开一个UIViewController,添加一个WKWebView,然后导航到手机页面创建的。应用程序和html & Javascript之间有完整的通信,因此事件可以来回传递。

WKWebView和音频视频会话问题

在阅读了大量未解决的论坛帖子后,很明显AVAudioSession.sharedInstance()根本没有连接到WKWebView,或者有一些未记录的连接。
结果是,如果通话从应用程序开始,并发送到后台,麦克风被禁用。显然,这不是一个选项,如果你在通话中。现在,我可以管理这个限制一点,通过把呼叫暂停时,应用程序发送到后台-虽然这将是一个混乱的用户和一个糟糕的用户体验
然而,真实的的问题是,如果应用程序从Callkit中被唤醒,因为应用程序从来不会进入前台(因为Callkit是),麦克风在第一时间就不会被激活,即使你切换到应用程序,它也不会激活。这是一个不可接受的用户体验
我发现有趣的是,如果你在iOS(15.x)上打开Safari浏览器,然后导航到手机页面:https://www.innovateasterisk.com/phone/(没有用xCode制作应用程序并将其加载到WKWebView中),当应用程序被发送到后台时,麦克风继续工作。那么Safari是如何做到这一点的呢?当然,这并不能解决CallKit问题,但有趣的是,Safari可以在后台使用麦克风,因为Safari是基于WKWebView构建的。
(我在阅读关于权利的书,这可能要特别授予......我不知道这是如何工作的?)
AVAudioSession的下一个问题是,由于无法访问WkWebView的会话,因此无法更改<audio>元素的输出,因此无法将其从扬声器更改为耳机,或使其使用蓝牙设备。
使用过时的WebRTC SDK(Google不再维护WebRTC iOS SDK)重新开发整个应用程序,然后构建我自己的Swift SIP堆栈(如SIPJS)并最终使用两组代码进行维护,这是不可行的......因此,我的主要问题是:
1.如何访问WKWebView的AVAudioSession以便设置输出路径/设备?
1.当应用程序发送到后台时,如何让麦克风保持活动状态?
1.当Callkit启动应用软件时(应用软件在后台运行),如何启动麦克风?

dkqlctbz

dkqlctbz1#

for 1)也许有人也在遵循这种方法,并可以添加一些见解/纠正错误的假设:WebRTC站点中的音频被表示为一个媒体流。也许可以在没有WKWebView的情况下获取该流,并在应用程序中以某种方式播放它?此代码应该传递一些缓冲区,但当它们以swift方式到达时,它们是空的:

//javascript
...
someRecorder = new MediaRecorder(audioStream);
someRecorder.ondataavailable = async (e) =>
{
    window.webkit.messageHandlers.callBackMethod.postMessage(await e.data.arrayBuffer());
}
mediaRecorder.start(1000);

然后迅速接收它

//swift
import UIKit
import WebKit

class ViewController: UIViewController, WKScriptMessageHandler {
...
let config = WKWebViewConfiguration()
config.userContentController = WKUserContentController()
config.userContentController.add(self, name: "callBackMethod")
let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 10, height: 10), configuration: config)
...
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    addToPlayingAudioBuffer(message.body)
    //print(message.body) gives the output "{}" every 1000ms.
}

相关问题