Android屏幕共享WebRTC异常:track无关联MediaStream
问题:WebRTC接收Android屏幕共享时,track无关联MediaStream
我尝试通过JavaScript在Web客户端展示Android设备的屏幕共享内容,流程如下:
- Android端启动屏幕捕获
使用Media Projection API获取屏幕捕获权限:
private fun startScreenCapture(){ val mediaProjectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager ActivityCompat.startActivityForResult(this, mediaProjectionManager.createScreenCaptureIntent(), 1, null) }
- Android端创建视频轨道并添加到PeerConnection
获取用户授权后,通过WebRTC创建屏幕捕获轨道并添加到PeerConnection:
fun startScreenCapture(permissionIntent: Intent, view: SurfaceViewRenderer, peerDevice: String){ if(peerConnection == null){ capturer = ScreenCapturerAndroid(permissionIntent, object : MediaProjection.Callback() { override fun onStop() { super.onStop() Log.d("TAG", "onStop: stopped screen casting permission") } }) peerConnection = peerConnectionFactory.createPeerConnection(iceServer, object: PeerConnectionObserver(){ override fun onIceCandidate(candidate: IceCandidate?) { super.onIceCandidate(candidate) candidate?.let { sendIceCandidate(it, peerDevice) } } override fun onConnectionChange(newState: PeerConnection.PeerConnectionState?) { super.onConnectionChange(newState) if(newState == PeerConnection.PeerConnectionState.CONNECTED){ } } override fun onRenegotiationNeeded() { super.onRenegotiationNeeded() createOffer(peerDevice) } }) val defaultDisplay = DisplayManagerCompat.getInstance(context).getDisplay(Display.DEFAULT_DISPLAY) val displayContext = context.createDisplayContext(defaultDisplay!!) val screenWidthPixels = displayContext.resources.displayMetrics.widthPixels val screenHeightPixels = displayContext.resources.displayMetrics.heightPixels val surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread",eglBaseContext) val localVideoSource = peerConnectionFactory.createVideoSource(capturer!!.isScreencast) capturer!!.initialize(surfaceTextureHelper,context,localVideoSource.capturerObserver) capturer!!.startCapture(screenWidthPixels,screenHeightPixels,30) localVideoTrack = peerConnectionFactory.createVideoTrack("${deviceId}_video",localVideoSource) localVideoTrack!!.addSink(capturer) try{ peerConnection?.addTrack(localVideoTrack) }catch (e:Exception){ e.printStackTrace() } } }
- Web端接收轨道异常
Web端peerConnection.ontrack事件触发,但event.streams长度为0,无法获取关联的MediaStream设置到视频元素:
peerConnection.ontrack = (event) => { console.log(`New track ${event.track}`) console.log(`Track ID: ${event.track.id}`) console.log(`Track kind: ${event.track.kind}`) console.log(`Track label: ${event.track.label}`) console.log(`Streams: ${event.streams.length}`) console.log(`First stream: ${event.streams[0]}`) remoteVideo.srcObject = event.streams[0]; };
浏览器日志:
New track [object MediaStreamTrack] main.js:107 Track ID: 12345_video main.js:108 Track kind: video main.js:109 Track label: 12345_video main.js:110 Streams: 0 main.js:111 First stream: undefined
WebRTC其他信令交互正常,请问为何track无关联MediaStream?
解决方案
原因分析
问题出在Android端添加轨道的逻辑:直接调用peerConnection.addTrack(localVideoTrack)时,没有将轨道与MediaStream关联。WebRTC的ontrack事件中,event.streams仅包含发送端显式绑定到轨道的MediaStream,若发送端未做关联,Web端就无法获取到。
修复方案
方案1:创建MediaStream并关联轨道后添加到PeerConnection
修改Android端添加轨道的代码,先创建MediaStream并将轨道加入其中,再通过addStream方法添加到PeerConnection:
// 创建本地MediaStream val localStream = peerConnectionFactory.createLocalMediaStream("screen_share_stream") // 将视频轨道加入MediaStream localStream.addTrack(localVideoTrack) // 将关联好的MediaStream添加到PeerConnection peerConnection?.addStream(localStream)
注:
addStream是兼容性较好的旧API,适合多数场景。
方案2:调用addTrack时指定关联的MediaStream
使用WebRTC最新的轨道优先模型,调用addTrack时传入包含轨道的MediaStream数组:
val localStream = peerConnectionFactory.createLocalMediaStream("screen_share_stream") localStream.addTrack(localVideoTrack) // 添加轨道时显式指定关联的MediaStream peerConnection?.addTrack(localVideoTrack, listOf(localStream))
Web端兼容处理(可选)
为了兼容发送端可能未关联MediaStream的情况,Web端可以手动创建MediaStream并添加轨道:
peerConnection.ontrack = (event) => { console.log(`New track ${event.track}`) console.log(`Track ID: ${event.track.id}`) console.log(`Track kind: ${event.track.kind}`) console.log(`Track label: ${event.track.label}`) console.log(`Streams: ${event.streams.length}`) let stream; if (event.streams.length > 0) { stream = event.streams[0]; } else { // 手动创建MediaStream并添加轨道 stream = new MediaStream([event.track]); } remoteVideo.srcObject = stream; };
内容的提问来源于stack exchange,提问作者tyczj
相关产品推荐
相关产品推荐

