调用nbmWebRTCPeer.generateOffer导致Android应用崩溃,求排查
Kurento WebRTC Peer Android开发:调用generateOffer崩溃无法生成sdpOffer
我在遵循Kurento WebRTC Peer for Android文档开发时,调用nbmWebRTCPeer.generateOffer("local",true)方法生成sdpOffer时应用直接崩溃,怀疑是nbmWebRTCPeer初始化流程存在问题。
相关代码
private fun receiveVideo(userId: Any?, userName: String) { runOnUiThread { val localView :SurfaceViewRenderer = binding.localview localView.init(EglBase.create().eglBaseContext,null) val mediaConfiguration = NBMMediaConfiguration() nbmWebRTCPeer = NBMWebRTCPeer(mediaConfiguration,this, localView, object:NBMWebRTCPeerObserver(){ override fun onInitialize() { super.onInitialize() Log.d(TAG,"onInitialize") try{ nbmWebRTCPeer.generateOffer("local",true) }catch (e:Exception){ e.printStackTrace() } } override fun onLocalSdpOfferGenerated( localSdpOffer: SessionDescription?, connection: NBMPeerConnection? ) { super.onLocalSdpOfferGenerated(localSdpOffer, connection) Log.d(TAG,"${localSdpOffer?.description}") if(!isMyVideoPublished){ val message = Message( event = "receiveVideoFrom", userid = userId, userName = userName, sdpOffer = localSdpOffer ) socketManager.emitMessage(message) isMyVideoPublished = true } } }) lifecycleScope.launch { nbmWebRTCPeer.initialize() } } }
LogCat崩溃信息截图

问题排查与解决方案
- 线程调度错误:你在UI线程触发初始化,又在初始化回调的UI线程直接调用
generateOffer,但Kurento WebRTC Peer的核心操作(初始化、SDP生成)必须在非UI线程执行,线程冲突会直接引发崩溃。 - EglBase实例管理不当:在方法内临时创建
EglBase.create()会导致渲染上下文不稳定,建议将EglBase作为全局成员提前初始化。 - 初始化未就绪就调用方法:
onInitialize回调触发时,PeerConnection内部可能还未完成初始化流程,直接调用generateOffer会触发未就绪状态的异常。
修复后代码示例
// 类成员变量,全局管理资源 private lateinit var eglBase: EglBase private lateinit var nbmWebRTCPeer: NBMWebRTCPeer private fun receiveVideo(userId: Any?, userName: String) { // 提前初始化EglBase(建议在Activity onCreate中完成) if (!::eglBase.isInitialized) { eglBase = EglBase.create() } val localView: SurfaceViewRenderer = binding.localview localView.init(eglBase.eglBaseContext, null) val mediaConfiguration = NBMMediaConfiguration() nbmWebRTCPeer = NBMWebRTCPeer(mediaConfiguration, this, localView, object : NBMWebRTCPeerObserver() { override fun onInitialize() { super.onInitialize() Log.d(TAG, "onInitialize") // 切换到IO线程执行SDP生成 lifecycleScope.launch(Dispatchers.IO) { try { nbmWebRTCPeer.generateOffer("local", true) } catch (e: Exception) { e.printStackTrace() } } } override fun onLocalSdpOfferGenerated( localSdpOffer: SessionDescription?, connection: NBMPeerConnection? ) { super.onLocalSdpOfferGenerated(localSdpOffer, connection) Log.d(TAG, "${localSdpOffer?.description}") if (!isMyVideoPublished) { val message = Message( event = "receiveVideoFrom", userid = userId, userName = userName, sdpOffer = localSdpOffer ) // Socket发送也放在IO线程执行,避免阻塞UI lifecycleScope.launch(Dispatchers.IO) { socketManager.emitMessage(message) } isMyVideoPublished = true } } }) // 在IO线程执行初始化,避免UI线程阻塞 lifecycleScope.launch(Dispatchers.IO) { nbmWebRTCPeer.initialize() } }
额外注意事项
- 必须提前申请相机、麦克风权限,未授权情况下调用音视频相关方法会直接崩溃。
- 检查
NBMMediaConfiguration是否正确配置了音视频轨道参数,确保开启了需要的媒体流。 - 页面销毁时务必释放资源,避免内存泄漏:
override fun onDestroy() { super.onDestroy() if (::nbmWebRTCPeer.isInitialized) { nbmWebRTCPeer.dispose() } if (::eglBase.isInitialized) { eglBase.release() } }
内容的提问来源于stack exchange,提问作者Himanshu Arya
相关产品推荐
相关产品推荐

