Android WebRTC本地/远程视频黑屏无音频,Firebase信令正常求助
你的代码中存在多个逻辑错误和初始化缺失,导致本地/远程视频黑屏、音频无法传输,以下是具体问题和修复方案:
1. 媒体设备初始化逻辑完全颠倒
在init()方法中,你先调用setupMediaDevices(),但此时videoCapturer还未初始化,触发setupMediaDevices()开头的if (videoCapturer == null) return直接退出,音视频轨道、媒体流完全没有创建,PeerConnection也没添加任何流,对方自然收不到你的音视频,本地也没有捕获到摄像头数据。
修复:
调整init()方法的调用顺序,先初始化摄像头,再设置媒体设备:
private fun init() { Log.d(TAG, " videocall onCreate: here 9") val iceServers = arrayListOf( PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").createIceServer() ) createPeerConnection(iceServers) // 先初始化摄像头,再设置媒体设备 videoCapturer = createFrontCameraCapturer(if (useCamera2()) Camera2Enumerator(context) else Camera1Enumerator(false)) setupMediaDevices() call() }
同时修改setupMediaDevices()开头的判断,确保摄像头初始化失败时有明确提示:
private fun setupMediaDevices() { // Ensure that the videoCapturer is initialized before calling this function if (videoCapturer == null) { Log.e(TAG, "setupMediaDevices: 摄像头初始化失败,无法创建媒体流") onStatusChangedListener(VideoCallStatus.FAILED) return } // ... 剩余代码不变 }
2. SurfaceViewRenderer未绑定到VideoRenderers
你的VideoRenderers类需要通过updateViewRenders()方法接收Activity中布局的SurfaceViewRenderer实例,但代码中没有任何地方调用这个方法。如果localView和remoteView为null,所有视频帧都会被sink()丢弃,导致黑屏。
修复:
在Activity的onCreate或onStart中,调用videoCallSession.videoRenderers.updateViewRenders(localSurfaceView, remoteSurfaceView),将布局中的SurfaceViewRenderer实例传入。
3. 摄像头初始化缺少SurfaceTextureHelper
setupVideoTrack()中调用videoCapturer!!.initialize(null, context, null)时,第三个参数SurfaceTextureHelper传null,这会导致摄像头无法正确捕获视频帧,因为WebRTC需要SurfaceTextureHelper来处理摄像头的纹理数据。
修复:
创建SurfaceTextureHelper并传入初始化方法:
private fun setupVideoTrack(front: Boolean): VideoTrack? { val camera = if (useCamera2()) Camera2Enumerator(context) else Camera1Enumerator(false) videoCapturer = if (front) createFrontCameraCapturer(camera) else createBackCameraCapturer(camera) if (videoCapturer == null) { Log.e(TAG, "setupVideoTrack: 摄像头初始化失败") return null } // 创建SurfaceTextureHelper,使用EGL上下文 val surfaceTextureHelper = SurfaceTextureHelper.create("CameraCaptureThread", eglBase.eglBaseContext) videoCapturer!!.initialize(surfaceTextureHelper, context, null) val videoSource = factory.createVideoSource(videoCapturer!!.isScreencast()) // 保存videoSource到成员变量,方便后续释放 this.videoSource = videoSource videoCapturer!!.startCapture(videoWidth, videoHeight, videoFPS) val videoRenderer = VideoSink(videoRenderers.localRenderer) val videoTrack = factory.createVideoTrack(VIDEO_TRACK_LABEL, videoSource) videoTrack?.addSink(videoRenderer) // 保存videoTrack到成员变量 this.videoTrack = videoTrack Log.d(TAG, "createFrontCameraCapturer: 摄像头初始化完成,视频轨道创建成功") return videoTrack }
4. 创建Answer时使用空MediaConstraints
在handleRemoteDescriptor()中,接收Offer后创建Answer时用了MediaConstraints()空约束,这会导致不请求接收音视频,对方的流无法被正确处理。
修复:
将创建Answer的约束改为defaultPcConstraints():
peerConnection?.createAnswer(SDPCreateCallback(this::createDescriptorCallback), defaultPcConstraints())
5. 视频源成员变量未赋值
setupVideoTrack()中创建的videoSource是局部变量,类的videoSource成员变量始终为null,导致terminate()时无法正确释放资源,可能引发内存泄漏或后续初始化问题。
修复:
在setupVideoTrack()中添加this.videoSource = videoSource,如上述修复代码所示。
6. 权限检查缺失
确保你的AndroidManifest.xml中添加了必要的权限,并且在运行时请求:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
在Activity中,启动通话前必须检查并请求CAMERA和RECORD_AUDIO权限,否则摄像头和麦克风无法正常工作。
内容的提问来源于stack exchange,提问作者hithere

