我现在正在做一个webrtc项目,这个项目是之前由另一个开发者写的。虽然我现在是webrtc的新手,我在删除过时的函数和其他东西后努力使它工作,现在我能识别出我的步骤中有什么错误吗?
我正在here中执行以下步骤
我代码是关于触发器的呼叫按钮
$(dod)
.find(".call")
然后我发出信号
wbsc.emit("SEND_EVENT_EMIT_CALL_AUDIO", {
data: { type: "login", id: id },
});
$(dod).hide();
//call*donecallProccess 1
setTimeout(() => {
wbsc.emit("SEND_EVENT_EMIT_CALL_AUDIO", {
data: { type: "doneoif", id: id },
});
}, 2e3);
可以在这里触发和处理
case "donecall":
call(data.id);
break;
case "showcall":
handleLogin(data.success, data.id);
break;
case "offercall":
handleOffer(data.offer, data.name);
break;
case "answercall":
handleAnswer(data.answer);
break;
case "candidatecall":
handleCandidate(data.candidate);
break;
case "leavecall":
handleLeave();
然后,在每个处理程序login和getUserMediaSuccess之后运行此代码,从媒体流收集权限并创建新RTCPeerConnection(服务器),使用addtrack从我的流中获取曲目(如果我正确实现了它,且如果发生了ontrack),我可以收集流以像这样添加到远程对等体吗?或者应该只添加
yourConn.ontrack = (event) => {
if (event.candidate !== null) {
remoteVideo.srcObject = event.streams[0];
} else {
console.log("there is an error with on trackevent", event);
}
};
上次处理登录和呼叫完整代码是
let handleLogin = async (success) => {
try {
if (success) {
localVideo = document.getElementById("wbrtclocal");
remoteVideo = document.getElementById("wbrtcremote");
var getUserMedia = navigator.mediaDevices.getUserMedia|| navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia ;
if (getUserMedia) {
getUserMedia({
audio: { noiseSuppression: false },
})
.then(getUserMediaSuccess)
.catch(errorHandler);
} else {
alert("Your browser does not support getUserMedia API");
}
} else {
alert("Ooops...try a different username");
}
} catch (err) {
errorHandler(error);
}
};
let getUserMediaSuccess = async (streams) => {
try {
yourConn = new RTCPeerConnection(servers);
if(streams){
localStream = streams;
localVideo.srcObject = streams;
streams.getTracks().forEach((track) => yourConn.addTrack(track, streams));
}
yourConn.onicecandidate = (event) => {
if (event.candidate) {
wbsc.emit("SEND_EVENT_EMIT_CALL_AUDIO", {
data: {
type: "candidate",
candidate: event.candidate,
id: connectedUser,
},
});
}
console.log("nwe ice candidate is", event.candidate);
console.log("nwe stream is", streams);
};
remoteStream = new MediaStream();
remoteVideo.srcObject = remoteStream;
yourConn.ontrack = (event) => {
if (event.candidate !== null) {
event.streams[0].getTracks().forEach((track) => {
remoteStream.addTrack(track);
});
} else {
console.log("there is an error with on trackevent", event);
}
};
} catch (err) {
errorHandler(error);
}
console.log("stream is", streams);
};
调用函数
async function call(id) {
$("#videoCall").show();
if (id.length > 0) {
connectedUser = id;
try {
RTCPeerConnection.createOffer().
offer.
await yourConn
.createOffer()
.then((offer) => successCallback)
.catch((e) => {
fl(e);
});
let successCallback = async (offer) => {
try {
yourConn
.setLocalDescription(offer)
.then(
wbsc.emit("SEND_EVENT_EMIT_CALL_AUDIO", {
data: { type: "offer", offer: offer, id: connectedUser },
})
)
.catch((e) => {
fl(e);
});
} catch (e) {
fl(e);
}
};
} catch (e) {
fl(e);
}
const user = U_CASH[id];
if (user) {
$("#videoCall")
.find(".u-pic")
.css("background-image", "url(" + removegifpic(user.pic + ")"));
$("#videoCall").find(".u-topic").text(user.topic);
}
$(".statecall").text("جاري الإتصال");
hl($(".statecall"), "warning");
} else {
alert("username can't be blank!");
}
console.log("connectedUser", id);
console.log("offer", offer);
console.log();
console.log();
console.log();
}
and this about each one for those
[handleOffer , handleAnswer , handleCandidate , handleLeave]
let handleOffer = async (offer, name) => {
$("#callvideonot").show();
const user = U_CASH[name];
if (user) {
$("#callvideonot")
.find(".u-pic")
.css("background-image", "url(" + removegifpic(user.pic + ")"));
$("#callvideonot").find(".u-topic").text(user.topic);
}
$(".callvideoaccept").on("click", async () => {
connectedUser = name;
await yourConn.setRemoteDescription(offer);
yourConn
.createAnswer()
.then((answer) => t.setLocalDescription(answer))
.then(() => {
wbsc.emit("SEND_EVENT_EMIT_CALL_AUDIO", {
data: { type: "answer", answer: answer, id: connectedUser },
});
})
.catch(fl);
const user = U_CASH[name];
if (user) {
$(".statecall").text("متصل");
hl($(".statecall"), "success");
$("#videoCall")
.find(".u-pic")
.css("background-image", "url(" + removegifpic(user.pic + ")"));
$("#videoCall").find(".u-topic").text(user.topic);
}
$("#callvideonot").hide();
$("#videoCall").show();
});
$(".callvideodeny").on("click", function () {
wbsc.emit("SEND_EVENT_EMIT_CALL_AUDIO", {
data: { type: "leave", id: name },
});
});
};
let handleAnswer = async (answer) => {
try {
$(".statecall").text("متصل");
hl($(".statecall"), "success");
//here we delete new RTCSessionDescription because constructor is deprecated.
await yourConn.setRemoteDescription(answer);
} catch (e) {
fl(e);
}
};
let handleCandidate = async (candidate) => {
try {
var NewlyIceCandidate = new RTCIceCandidate(candidate)
.setRemoteDescription().
await yourConn.addIceCandidate(NewlyIceCandidate);
} catch (e) {
fl(e);
}
};
function handleLeave() {
$("#callvideonot").hide();
$(".statecall").text("رفض");
hl($(".statecall"), "danger");
$(".vloumemic").removeClass("fa-volume-off");
$(".vloumemic").addClass("fa-volume-up");
$(".mutemic").removeClass("fa-microphone-slash");
$(".mutemic").addClass("fa-microphone");
setTimeout(() => {
$("#videoCall").hide();
}, 1e3);
if (localStream) {
localStream.getTracks().forEach((e) => e.stop());
}
if (connectedUser) {
connectedUser = null;
}
remoteVideo.src = null;
if (yourConn) {
yourConn.close();
yourConn.onicecandidate = null;
yourConn.ontrack = null;
localStream = null;
}
}
在这里here第7条指令中,他们说我应该添加等待来自信令服务的传入远程SDP描述,并使用RTCPeerConnection.setRemoteDescription()设置它。作为调用者,我可以在哪里添加它?在handleCandidate函数中?
并且在被调用方的第1条指令中,我应该创建一个具有适当ICE配置的新RTCPeerConnection示例。
我能重复使用吗
yourConn = new RTCPeerConnection(servers);
或者应该示例化一个新的连接,以防止在网站服务器进程中发生冲突,作为一个非yourConn的全局值,并在此文件的顶层中,在所有连接上重用它,对等方2或被调用方是否应该有另一个新的RTCPeerConnection?
对于remoteVideo.srcObject = remoteStream;
,remoteStream值是全局的,我覆盖了它。我可以在这里添加新的媒体流吗?还是只处理当前的remoteVideo元素比较好?
// remoteStream = new MediaStream();
remoteVideo.srcObject = remoteStream;
1条答案
按热度按时间lf5gs5x21#
这里的问题是拆分RTCPeerConnection对象,并为本地和远程的每个对等体创建一个新对象,我这样做了,在完全删除addtrack并将其替换为addtranceiver和gettranceiver后,它工作正常。您可以从上一个问题的答案中找到它,我修复了它here
并且不需要覆盖或重置srcObect值。同一MediaStream中接收器端的曲目过渡应该是“无缝的”RTCRtpSender.replaceTrack这允许您无缝地更改正在发送的曲目,而不必以另一个提供/应答周期为代价重新协商