我开始使用WebRTC开发,但那件事从来没有给我ICE候选人。我设置了所有内容,我正在交换描述和内容,我还在那里缩小了一个超级丑陋的功能,以确保一切都正常运行,一个接一个。信号状态对两者都是稳定的, onError 永远不会被触发(如预期的那样),但onIceCandidate也是(不是预期的),当我想发送一个随机的空MediaStream对象pc1.addStream(new webkitMediaStream());
时,它总是触发 onNegotiationNeeded 。
有没有人知道我的代码到底有什么问题?我花了几个小时浏览Stack Overflow,HTML5 Rocks和W3C文档,但我不明白。这是我的整个代码:
var config={
'iceServers':[{
'url':'stun:stun.l.google.com:19302'
},{
'url':'stun:stun1.l.google.com:19302'
},{
'url':'stun:stun2.l.google.com:19302'
},{
'url':'stun:stun3.l.google.com:19302'
},{
'url':'stun:stun4.l.google.com:19302'
}]
};
var pc1=new webkitRTCPeerConnection(config);
var pc2=new webkitRTCPeerConnection(config);
var onError=function(error)
{
console.error(error);
}
pc1.onicecandidate=function()
{
console.log('PC1 onIceCandidate (finally) fired!');
}
pc2.onicecandidate=function()
{
console.log('PC2 onIceCandidate (finally) fired!');
}
pc1.oniceconnectionstatechange=function()
{
console.log('PC1 oniceconnectionstatechange fired!');
}
pc2.oniceconnectionstatechange=function()
{
console.log('PC2 oniceconnectionstatechange fired!');
}
pc1.onnegotiationneeded=function()
{
console.log('PC1 onnegotiationneeded fired!');
}
pc2.onnegotiationneeded=function()
{
console.log('PC2 onnegotiationneeded fired!');
}
pc1.createOffer(function(offer){
pc1.setLocalDescription(offer,function(){
pc2.setRemoteDescription(new RTCSessionDescription(offer),function(){
pc2.createAnswer(function(answer){
pc2.setLocalDescription(answer,function(){
pc1.setRemoteDescription(new RTCSessionDescription(answer),new Function()/*I don't need you, bro*/,onError);
},onError);
},onError);
},onError);
},onError);
},onError);
BTW我正在使用Google Chrome进行开发。我会确保它也在Firefox中运行,但是现在问题应该是跨浏览器。我想在之前使用数据通道...(但我没有反对使用Firefox或跨浏览器代码的工作解决方案)
答案 0 :(得分:10)
在Chrome 38及更早版本中,OfferToReceiveAudio
默认为true
。从Chrome 39开始,OfferToReceiveAudio
默认为false,正如WebRTC工程师在PSA: Behavior change to PeerConnection.createOffer constraint OfferToReceiveAudio所宣布的那样(引用如下)。
由于此更改,createOffer
返回的SDP不包含任何媒体,因此ICE收集过程永远不会启动。您可以通过观察永远不会触发ICE事件,并且PeerConnection的iceGatheringState
和iceConnectionState
保持" new"来注意到此更改的后果。
要确保ICE收集的开始和完成,您必须在商品中添加媒体,例如通过在以下约束中为您的商品设置OfferToReceiveAudio:true
(作为PeerConnection
constructor的参数,或作为peerConnection.createOffer
方法的参数):
{
mandatory: {
OfferToReceiveAudio: true
}
}
(在SDP中获取媒体的其他方式包括设置OfferToReceiveVideo:true
,或使用您从getUserMedia
获得的媒体流调用peerConnection.addStream
webrtc-discuss:PSA: Behavior change to PeerConnection.createOffer constraint OfferToReceiveAudio:
我将提交更改(https://webrtc-codereview.appspot.com/16309004/)以更改RTCPeerConnection.createOffer的行为。 预计此更改将包含在Chrome M39中。
发生了什么变化:
目前,如果未在PeerConnection.createOffer中指定OfferToReceiveAudio约束,则生成的商品SDP将具有" m = audio"即使没有连接到PeerConnection的音频轨道也行。换句话说,OfferToReceiveAudio默认为true。
我的更改后,OfferToReceiveAudio不再默认为true。提供SDP是否具有" m = audio" line取决于是否已将任何音轨附加到PeerConnection。
未更改的内容:
为OfferToReceiveAudio设置显式值的行为保持不变,即OfferToReceiveAudio:true将导致" m = audio"无论音轨是否存在,都行; OfferToReceiveAudio:false将导致no" m = audio"除非使用包含" m = audio"的SDP调用setLocalDescription,否则无论音轨是否存在都行。在这种情况下,新商品SDP会将音频内容标记为无效,而不是删除音频内容。
答案 1 :(得分:3)
2015年1月3日Rob W的v2 Samples解决方案最初为我工作但导致了另一个问题。
我在{'offerToReceiveAudio':true,'offerToReceiveVideo':true}
和createOffer
来电中加入createAnswer
,并按照说明调用了onIceCandidate
。
但是,如果我做对了,offerToReceive...
表示仅接收但不发送流。我认为这是因为sdp报价中的a=recvonly
和sdp答案中的a=sendonly
。因此,只有来电者可以看到被调查者的视频,反之亦然。反之亦然。
Rob正确地说:
在SDP中获取媒体的其他方法包括使用a调用peerConnection.addStream 您从getUserMedia获得的媒体流
添加流是我最初做过的事情。但是,我发送的sdp发生在添加之前,因为我的逻辑流程混乱了。把它带到正确的顺序(addStream -> sdp = getLocalDescription -> send(sdp)
)并删除offerOptions对我来说很有用
希望这对任何人都有帮助。
答案 2 :(得分:2)
2020年的解决方案
您必须做两件事:
offerToReceiveAudio
时包括offerToReceiveVideo
和RTCPeerConnection
addTrack
示例代码:
const peerConnection= new RTCPeerConnection({
configuration: {
offerToReceiveAudio: true,
offerToReceiveVideo: true
},
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
})
localStream.getTracks().forEach(track => {
peerConnection.addTrack(track, localStream)
})
const offer = await peerConnection.createOffer()
await peerConnection.setLocalDescription(offer)
peerConnection.onicecandidate = event => {
if (event.candidate) {
console.log('Ice candidate: ', event.candidate)
}
}
... other codes
答案 3 :(得分:0)
我找到了解决方案。如果在配置声明后添加此代码:
var mediaConstraints = {
optional: [],
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
}
};
并像这样修改最后一行
},onError,mediaConstraints);
它只是有效。不要问我为什么。