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

Android平台WebRTC中如何向PeerConnection添加多条媒体轨道?

问题描述

我需要向远端对等端发送多条媒体轨道(videoTrack、audioTrack、shareScreenTrack),已配置UNIFIED_PLAN模式:

val rtcConfig = PeerConnection.RTCConfiguration(
    arrayListOf(PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").createIceServer())
).apply { sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN }

通过以下方式添加轨道:

peerConnection?.addTrack(videoTrack)
peerConnection?.addTrack(audioTrack)
peerConnection?.addTrack(captureScreenVideoTrack)

但只有第一条轨道能成功传输,远端onTrack仅触发一次(仅videoTrack生效),audioTrack和captureScreenVideoTrack均未触发回调。远端调试代码如下:

override fun onTrack(transceiver: RtpTransceiver?) {
    super.onTrack(transceiver)
    val track = transceiver?.receiver?.track() ?: return
    when (track.kind()){
            MediaStreamTrack.VIDEO_TRACK_KIND ->{
                //videoTrack or captureScreenVideoTrack
            }
            MediaStreamTrack.AUDIO_TRACK_KIND ->{
                //audioTrack
            }

            else -> {}
        }    
}
解决方法

1. 添加轨道时关联MediaStream

UNIFIED_PLAN模式下,建议将轨道关联到MediaStream后再添加,或者在addTrack时指定目标流标识:

// 方式1:统一添加到同一个MediaStream
val mediaStream = peerConnection?.createLocalMediaStream("multi-track-stream")
mediaStream?.addTrack(videoTrack)
mediaStream?.addTrack(audioTrack)
mediaStream?.addTrack(captureScreenVideoTrack)

// 方式2:逐个添加时指定流标识
peerConnection?.addTrack(videoTrack, listOf("multi-track-stream"))
peerConnection?.addTrack(audioTrack, listOf("multi-track-stream"))
peerConnection?.addTrack(captureScreenVideoTrack, listOf("multi-track-stream"))

这样SDP协商时会生成对应所有轨道的m-line,确保远端能识别到多条轨道。

2. 手动创建独立RtpTransceiver

自动生成的transceiver可能存在复用问题,手动为每条轨道创建独立的传输器:

// 为音频轨道创建transceiver
peerConnection?.addTransceiver(
    audioTrack,
    RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY)
)

// 为摄像头视频轨道创建transceiver
peerConnection?.addTransceiver(
    videoTrack,
    RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY)
)

// 为屏幕共享轨道创建transceiver
peerConnection?.addTransceiver(
    captureScreenVideoTrack,
    RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY)
)

手动指定传输方向为SEND_ONLY(仅发送场景),保证每条轨道拥有独立的传输通道。

3. 验证SDP是否包含所有轨道

创建Offer后打印SDP内容,确认是否存在音频、两条视频对应的m-line:

peerConnection?.createOffer(object : SdpObserver {
    override fun onCreateSuccess(desc: SessionDescription?) {
        desc?.let {
            println("Offer SDP: ${it.description}")
            peerConnection?.setLocalDescription(this, it)
        }
    }
    override fun onCreateFailure(error: String?) {}
    override fun onSetSuccess() {}
    override fun onSetFailure(error: String?) {}
}, MediaConstraints())

如果SDP中只有一个m-line,检查轨道是否处于活跃状态(track.enabled需为true)。

4. 修正远端onTrack回调处理

UNIFIED_PLAN模式下每条轨道会单独触发onTrack,需确保远端同样启用UNIFIED_PLAN,同时避免默认父类方法的干扰:

override fun onTrack(transceiver: RtpTransceiver?) {
    val track = transceiver?.receiver?.track() ?: return
    when (track.kind()) {
        MediaStreamTrack.VIDEO_TRACK_KIND -> {
            // 通过track.id区分摄像头和屏幕共享轨道
            if (track.id() == captureScreenVideoTrack.id()) {
                // 处理屏幕共享轨道
            } else {
                // 处理摄像头视频轨道
            }
        }
        MediaStreamTrack.AUDIO_TRACK_KIND -> {
            // 处理音频轨道
        }
        else -> {}
    }
}

内容的提问来源于stack exchange,提问作者cafer yıldız

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:39:33