GoogleWebRTC 挂起冻结swift 本机应用程序 (OpenVidu) 中的主线程

如何解决GoogleWebRTC 挂起冻结swift 本机应用程序 (OpenVidu) 中的主线程

我们的 iOS (swift) 本机应用程序与 OpenVidu 实现(在引擎盖下使用 GoogleWebRTC )存在挂起问题(应用程序由于主线程锁定而冻结) .需要的具体条件:需要加入现有的房间,并且至少有 8 名参与者已经在直播。有 6 名参与者时,这种情况发生的频率较低,而且在 6 人以下时几乎不会发生。如果参与者一个一个加入,它不会挂起,只有当您加入房间时所有其他参与者都已经在流式传输。这表明问题的并发性质。

GoogleWebRTC 在 setRemoteDescription 调用时挂起:

func setRemoteDescription(sdpAnswer: String) {
    let sessionDescription: RTCSessionDescription = RTCSessionDescription(type: RTCSdpType.answer,sdp: sdpAnswer)
    self.peerConnection!.setRemoteDescription(sessionDescription,completionHandler: {(error) in
        print("Local Peer Remote Description set: " + error.debugDescription)
    })
}

main thread hangs

如上图所示,主线程挂在 __psynch_cvwait 上。似乎没有任何其他线程被锁定。 锁永远不会释放让应用完全冻结。

为了解决这个问题,我尝试了以下方法

  1. 我将 OpenVidu 信号服务器处理(RPC 协议)从主线程移动到单独的线程中。这只会导致锁定现在发生在我创建的单独线程之一中。它现在不会阻止 UI,但会阻止 OV 信号。问题依旧。

  2. 添加了锁以同步一个一个)处理每个信号事件(参与者加入事件、发布视频等)。这也无济于事(它实际上使情况变得更糟)。

  3. 我没有使用 Cocoapods 的 GoogleWebRTC v. 1.1.31999,而是下载了最新的 GoogleWebRTC 源代码,在发布配置和 included into my project 中构建它们。这无助于解决问题。

任何建议/意见将不胜感激。 谢谢!

编辑 1:

signaling_threadworker_thread 都在等待同一种锁中的某些东西。在锁定的那一刻,他们都没有执行我的任何代码

我还尝试在 GoogleWebRTC 的 DEBUG 版本中运行,在这种情况下不会发生锁定,但一切运行速度要慢得多(这对于调试来说是可以的,但我们不能在生产中使用它)。

>

enter image description here

编辑 2:

我尝试为 dispatchQueueoffer 回调包装额外的 setLocalDescription,但这没有任何改变。问题仍然可以很好地重现(几乎 100% 的时间,如果我有 8 个参与者有流):

    self.peerConnection!.offer(for: constrains) { (sdp,error) in
        dispatchQueue.global(qos: .background).async {

            guard let sdp = sdp else {
                return
            }

            self.peerConnection!.setLocalDescription(sdp,completionHandler: { (error) in
                dispatchQueue.global(qos: .background).async {
                    completion(sdp)
                }
            })
        }
    }

解决方法

WebRTC Obj-C API 可以从任何线程调用,但大多数方法调用被传递到 WebRTC 的内部线程,称为 signalling thread

此外,SetLocalDescriptionObserverInterfaceRTCSetSessionDescriptionCompletionHandler 等回调/观察器是从 signaling thread 上的 WebRTC 调用的。

看截图,好像是信令线程当前被阻塞,不能再调用WebRTC API调用了。

因此,为了避免死锁,最好创建自己的线程/dispatch_queue 并处理回调。

https://webrtc.googlesource.com/src/+/0a52ede821ba12ee6fff6260d69cddcca5b86a4e/api/g3doc/index.mdhttps://webrtc.googlesource.com/src/+/0a52ede821ba12ee6fff6260d69cddcca5b86a4e/api/g3doc/threading_design.md 详情。

,

在 OpenVidu 团队发表评论后,通过在添加已经在房间里的参与者之间增加 100 毫秒的延迟来解决问题。我认为这更像是一种 hack,而不是真正的解决方案,但我可以确认它在测试和生产环境中都有效:

DispatchQueue.global(qos: .background).async {
    for info in dict.values {
        let remoteParticipant = self.newRemoteParticipant(info: info)
        if let streamId = info.streamId {
            remoteParticipant.createOffer(completion: {(sdp) in
                self.receiveVideoFrom(sdp: sdp,remoteParticipant: remoteParticipant,streamId: streamId)
            })
        } else {
            print("No streamId")
        }
        Thread.sleep(forTimeInterval: 0.1)
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?