基于AppRTC的P2P屏幕共享异常:仅本地可见如何修复?
问题描述
我基于AppRTC仓库(主仓库及src/collider模块)搭建了源码,当前音视频通话功能正常,但缺少屏幕共享选项。自行添加屏幕共享按钮后,仅共享者本地能看到画面,远端无法显示,相关代码如下,请问该如何修复?
Call.prototype.maybeGetMediaForScreenSharing_ = function() { var needStream = (this.params_.mediaConstraints.audio !== false || this.params_.mediaConstraints.video !== false); var mediaPromise = null; if (needStream) { var mediaConstraints = '{"audio":true,"video":{"optional":[{"minWidth":"1280"},{"minHeight":"720"},{"mediaSource":"screen"}],"mandatory":{}}}'; mediaPromise = navigator.mediaDevices.getDisplayMedia({ audio: true, video: true }).catch(function(error) { if (error.name !== 'NotFoundError') { throw error; } return navigator.mediaDevices.getDisplayMedia({ audio: true, video: true }); }).then(function(stream) { var videoTracks = this.localStream_.getVideoTracks(); var audioTracks = this.localStream_.getAudioTracks(); //this.onlocalstreamadded(stream); this.onremotestreamadded(stream); }.bind(this)).catch(function(error) { alert("Error"); this.onError_('Error getting user media: ' + error.message); this.onUserMediaError_(error); }.bind(this)); } else { mediaPromise = Promise.resolve(); } return mediaPromise; };
修复方案
你的代码存在几个核心问题,导致远端无法接收屏幕共享流,以下是具体修复步骤:
1. 修正本地流处理方法
你错误调用了this.onremotestreamadded(stream),这个方法是用来处理远端传入的媒体流的。本地屏幕共享流应该调用this.onlocalstreamadded(stream)完成本地渲染,同时关键是要将流的轨道更新到RTCPeerConnection中,才能推送给远端。
2. 更新RTCPeerConnection的媒体轨道
AppRTC在通话建立后,本地流已经和PeerConnection绑定,新增屏幕共享流需要将其轨道添加到PeerConnection,并发送新的会话描述(SDP)通知远端:
修改后的核心代码如下:
Call.prototype.maybeGetMediaForScreenSharing_ = function() { var needStream = (this.params_.mediaConstraints.audio !== false || this.params_.mediaConstraints.video !== false); var mediaPromise = null; if (needStream) { mediaPromise = navigator.mediaDevices.getDisplayMedia({ audio: true, video: { width: 1280, height: 720 } }).then(function(stream) { // 先处理本地屏幕共享流的显示 this.onlocalstreamadded(stream); // 获取当前的PeerConnection实例(AppRTC中通常通过this.pcClient_.pc_获取) var pc = this.pcClient_.pc_; // 可选:移除原有的摄像头视频轨道(如果需要替换而非新增流) const existingVideoSenders = pc.getSenders().filter(sender => sender.track?.kind === 'video'); existingVideoSenders.forEach(sender => pc.removeTrack(sender)); // 将屏幕共享的音视频轨道添加到PeerConnection stream.getTracks().forEach(track => { pc.addTrack(track, stream); }); // 创建新的Offer并更新本地SDP,然后发送给远端 return pc.createOffer().then(offer => { return pc.setLocalDescription(offer); }).then(() => { // 通过AppRTC的信令通道发送更新后的SDP this.sendSdp_(pc.localDescription); }); }.bind(this)).catch(function(error) { alert("获取屏幕共享失败: " + error.message); this.onError_('获取用户媒体错误: ' + error.message); this.onUserMediaError_(error); }.bind(this)); } else { mediaPromise = Promise.resolve(); } return mediaPromise; };
3. 确保远端正确处理轨道更新
远端需要监听PeerConnection的ontrack事件,接收新的媒体轨道并更新渲染元素。在AppRTC现有逻辑基础上,可补充或调整远端流处理逻辑:
// 集成到AppRTC的远端流处理逻辑中 pc.ontrack = function(event) { const remoteVideo = document.getElementById('remote-video'); if (event.track.kind === 'video') { remoteVideo.srcObject = event.streams[0]; } };
关键注意事项
- 必须将屏幕共享轨道添加到RTCPeerConnection,并发送新的SDP通知远端,这是远端能收到流的核心前提
- 不要混淆本地流和远端流的处理方法,本地流用
onlocalstreamadded,远端流处理逻辑负责接收渲染 - 若需要在摄像头和屏幕共享之间切换,记得移除旧轨道再添加新轨道,避免远端出现多个流
内容的提问来源于stack exchange,提问作者Adesh Patel
相关产品推荐
相关产品推荐

