You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android屏幕共享WebRTC异常:track无关联MediaStream

问题:WebRTC接收Android屏幕共享时,track无关联MediaStream

我尝试通过JavaScript在Web客户端展示Android设备的屏幕共享内容,流程如下:

  1. Android端启动屏幕捕获
    使用Media Projection API获取屏幕捕获权限:
private fun startScreenCapture(){
    val mediaProjectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
    ActivityCompat.startActivityForResult(this, mediaProjectionManager.createScreenCaptureIntent(), 1, null)
}
  1. 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()
        }
    }
}
  1. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 22:45:00