Sik*_*kki 2 javascript webrtc peerjs
我尝试使用peerJS进行webRTC视频会议并成功进行了一对一会议,我需要一些帮助来推进多方视频会议,在这里我尝试解释我做了什么,请从我罢工的地方提供帮助
在这里我发布我的完整代码,以便任何人都可以通过修改一些信息来使用,
意图
达到了
我的情况
待处理并需要帮助
如何在 Alice、Bob 和 Carole 之间进行会议?
/*-----------------
indexedDB
------------------*/
var iDB;
const openiDB = indexedDB.open('webRTC',1)
openiDB.onupgradeneeded = function(){
iDB = openiDB.result
if(!iDB.objectStoreNames.contains('contacts')){
iDB.createObjectStore('contacts',{keyPath:'mobile',unique:true})
}
if(!iDB.objectStoreNames.contains('callLog')){
iDB.createObjectStore('callLog',{keyPath:'id',autoIncrement:true})
}
if(!iDB.objectStoreNames.contains('chatLog')){
iDB.createObjectStore('chatLog',{keyPath:'mobile'})
}
}
openiDB.onsuccess = function(){
iDB = openiDB.result
}
openiDB.onerror = function(){
console.log(openiDB.error)
}
/*-----------------
jQuery
------------------*/
$(document).ready(function(){
/*-----------------
functions
------------------*/
function gIndex(){
$("body").append(
$("<footer>").text("2020 All rights reserved to SIKANDAR")
)
}
function uIndex(){
$("main").empty().append(
$("<div>").attr('class','error'),
$("<article>").attr('class','welCome').append(
$("<h2>").attr('class','aH2').text("Hello "+user.fName),
$("<aside>").attr('class','msg')
),
$("<nav>").append(
$("<span>").attr({'class':'navIcon','id':'meetings'}).text("MEETINGS"),
$("<span>").attr({'class':'navIcon','id':'calls'}).text("CALLS"),
$("<span>").attr({'id':'logo'}).text("HOME"),
$("<span>").attr({'class':'navIcon','id':'chats'}).text("CHATS"),
$("<span>").attr({'class':'navIcon','id':'settings'}).text("MENU")
),
$("<section>").attr('class','modal').append(
$("<span>").attr('class','mClose').text("X"),
$("<div>").attr('class','mWrap').append(
$("<aside>").attr('class','contacts').append(
$("<div>").attr('class','formContact'),
$("<div>").attr('class','showContacts')
),
$("<aside>").attr('class','players').append(
$("<div>").attr('class','row').append(
$("<video playsinline muted>").attr({'controls':false,'id':'lCam','preload':'none'})
),
$("<div>").attr('class','row'),
$("<div>").attr('class','row2').append(
$("<button>").attr('id','aCall').text("ADD"),
$("<button>").attr('id','jCall').text("JOIN").prop('disabled',true),
$("<button>").attr('id','eCall').text("END")
)
)
),
),
$("<section>").attr('class','iScreen').append()
)
$('.modal,.contacts,.players,.iScreen,.error').hide()
}
function lCamCheck(cT,iCall){
let lCam = $("#lCam")[0]
switch(cT){
case 'incoming':{
switch(lCam.srcObject){
case null:{
navigator.mediaDevices.getUserMedia(constraints).then(stream=>{
lCam.srcObject = stream;
iCall.answer(stream)
lCam.play()
}).catch(error=>console.error(error))
break;
}
default:{
iCall.answer(lCam.srcObject)
break;
}
}
break;
}
case 'outgoing':{
switch(lCam.srcObject){
case null:{
navigator.mediaDevices.getUserMedia(constraints).then(stream=>{
lCam.srcObject = stream;
let outGoing = socket.call(iCall,stream)
lCam.play()
outGoing.on('stream',rStream=>{
rCamCheck(iCall,rStream)
$("button[value='"+iCall+"']").prop('disabled',true)
$(".players").show()
},err=>console.error(err))
addLog(iCall,'outgoing')
}).catch(error=>console.error(error))
break;
}
default:{
let outGoing = socket.call(iCall,lCam.srcObject)
lCam.play()
outGoing.on('stream',rStream=>{
rCamCheck(iCall,rStream)
$("button[value='"+iCall+"']").prop('disabled',true)
},err=>console.error(err))
addLog(iCall,'outgoing')
break;
}
}
break;
}
}
}
function rCamCheck(m,rS){
let rCam = $("video[name='"+m+"']")[0]
if(!rCam){
$(".players .row:nth-child(2)").append(
$("<video playinline>").attr({'class':'rCam','name':m,'controls':false,'preload':'none'})
)
$("video[name='"+m+"']")[0].srcObject = rS
$("video[name='"+m+"']")[0].play()
}else{ // function is repeating two times hence writing else
$("video[name='"+m+"']")[0].pause()
//$("video[name='"+m+"']")[0].srcObject = rS
$("video[name='"+m+"']")[0].play()
console.log(socket)
}
}
function addLog(m,t){
let dt = new Date()
let log = {
'date' : dt.toLocaleDateString('en-CA'),
'time' : dt.toLocaleTimeString('en-CA',{hour12:false}),
'mobile': m,
'type' : t
}
let addLog = iDB.transaction(["callLog"],'readwrite').objectStore("callLog").add(log)
addLog.onerror = function(){
console.error(addLog.error)
}
}
function showLog(){
let sLog = iDB.transaction(["callLog"]).objectStore("callLog").getAll()
sLog.onsuccess = function(){
if(sLog.result.length>0){
$(".callLog").empty().append(
$("<div>").attr('class','row1').append(
$("<span>").attr('class','cSpan').text("DATE"),
$("<span>").attr('class','cSpan').text("TIME"),
$("<span>").attr('class','cSpan').text("MOBILE"),
$("<span>").attr('class','cSpan').text("TYPE")
)
)
$.each(sLog.result,function(k,v){
$("<div>").attr('class','row1').append(
$("<span>").attr('class','cSpan').text(v.date),
$("<span>").attr('class','cSpan').text(v.time),
$("<span>").attr('class','cSpan').text(v.mobile),
$("<span>").attr('class','cSpan').text(v.type)
).appendTo(".callLog")
})
}else{
$(".callLog").empty().append(
$("<div>").attr('class','row1').append(
$("<span>").attr('class','cSpan').text("DATE"),
$("<span>").attr('class','cSpan').text("TIME"),
$("<span>").attr('class','cSpan').text("MOBILE"),
$("<span>").attr('class','cSpan').text("TYPE")
),
$("<div>").attr('class','row').text("No Call Records")
)
}
}
sLog.onerror = function(){
console.log(sLog.error)
}
}
function phBook(){
let lCNT = iDB.transaction(["contacts"]).objectStore("contacts").getAll()
lCNT.onsuccess = function(){
$(".showContacts").empty().append(
$("<div>").attr('class','row2').append(
$("<span>").text("DP"),$("<span>").text("NAME"),$("<span>").text("CALL")
)
)
if(lCNT.result.length>0){
$.each(lCNT.result,function(k,v){
$(".showContacts").append(
$("<div>").attr('class','row2').append(
$("<img>").attr({'alt':'DP'}),
$("<span>").text(v.fName),
$("<button>").attr({'value':v.mobile,'class':'vCall'}).text("CALL")
)
)
})
}else{
$(".showContacts").append(
$("<div>").attr('class','row').text("No Contacts")
)
}
}
lCNT.onerror = function(){
console.error(lCNT.error)
}
}
function showLogin(){
$("main").append(
$("<article>").append(
$("<aside>").attr('class','login').append(
$("<fieldset>").append(
$("<legend>").text("User Login"),
$("<form>").attr('id','formLogin').append(
$("<div>").attr('class','row').append(
$("<input>").attr({
'type':'text','name':'lMobile','placeholder':'Enter Mobile Number',
'pattern':'[0-9]{10}','title':'Enter 10 digit mobilenumbers without country code'
}).prop('required',true),
$("<label>").attr('for','lMobile').text("*")
),
$("<div>").attr('class','row').append(
$("<input>").attr({'type':'submit','value':'LOGIN'}),
$("<input>").attr({'type':'button','name':'signUP','value':'SIGNUP'})
)
)
)
),
$("<aside>").attr('class','signup').append(
$("<fieldset>").append(
$("<legend>").text("User Registration"),
$("<form>").attr('id','formSignup').append(
$("<div>").attr('class','row').append(
$("<input>").attr({
'type':'text','name':'fName','placeholder':'Enter First Name'
}).prop('required',true),
$("<label>").attr('for','fName').text("*")
),
$("<div>").attr('class','row').append(
$("<input>").attr({
'type':'text','name':'lName','placeholder':'Enter Last Name'
}).prop('required',true),
$("<label>").attr('for','lName').text("*")
),
$("<div>").attr('class','row').append(
$("<input>").attr({'type':'email','name':'email','placeholder':'Enter e-Mail Id'}),
$("<label>").attr('for','email').text("*")
),
$("<div>").attr('class','row').append(
$("<input>").attr({
'type':'tel','name':'mobile','placeholder':'Enter Mobile Number',
'pattern':'[0-9]{10}','title':'Enter 10 digit mobile number with out country code'
}).prop('required',true),
$("<label>").attr('for','mobile').text("*")
),
$("<div>").attr('class','row').append(
$("<input>").attr({'type':'submit','value':'REGISTER'}),
$("<input>").attr({'type':'reset','value':'reset'})
)
)
)
)
)
)
$(".signup").hide()
}
/*-----------------
appShell
------------------*/
let user;let uAuth = localStorage.getItem('uAuth');
if(typeof(user)=="undefined"){
user = JSON.parse(localStorage.getItem('user'))
}
let iceServers = {
'iceServers':[{'urls':'stun:stun.l.google.com:19302'},{'urls':'stun:stun1.l.google.com:19302'}]
}
//console.log(navigator.mediaDevices.getSupportedConstraints())
let constraints = {
'video':{'width':640,'height':480,'frameRate':{'max':24}},
'audio':{'echoCancellation':true,'noiseSuppression':true,'sampleSize':8}
}
let socket; let peerJS = {'host':'localhost','port':9000,'path':'/myapp','config':iceServers};
switch(uAuth){
case null:{
gIndex();
showLogin()
break;
}
case 'true':{
uIndex()
socket = new Peer(user.mobile,peerJS)
socket.on('open',function(){
console.log(socket.id+" Connceted")
})
socket.on('error',function(error){
$(".error").text(error.message).show()
//$(".aH1").css('color','firebrick')
let lCam = $("#lCam")[0];let rCams = $("video")
lCam.srcObject.getTracks().forEach(track=>{track.stop();$(".modal").hide()})
if(rCams.length>1){
let rCam = $("video")
rCam[1].srcObject.getTracks().forEach(track=>track.stop())
}
})
socket.on('call',async function(inComing){
$('.iScreen').show()
await lCamCheck('incoming',inComing)
await phBook()
await inComing.on('stream',rStream=>{
rCamCheck(inComing.peer,rStream)
$(".modal,.players").show()
$("button[value='"+inComing.peer+"']").prop('disabled',true)
},err=>console.error(err))
await addLog(inComing.peer,'incoming')
})
}
}
$(document).on('submit','form',function(e){
e.preventDefault()
})
$(document).on('click','input[name="signUP"]',function(){
$(".login").hide(),
$(".signup").show()
})
$(document).on('submit','#formSignup',async function(){
let nUser = await {
fName : $("input[name='fName']").val(),
lName : $("input[name='lName']").val(),
email : $("input[name='email']").val(),
mobile : $("input[name='mobile']").val()
}
await localStorage.setItem('user',JSON.stringify(nUser))
location.reload()
})
$(document).on('submit','#formLogin',function(){
let mobile = $("input[name='lMobile']").val();
switch(user){
case null:{
$("input[name='lMobile']").val("")
$("label[for='lMobile']").text(" please signup").css('color','firebrick')
break;
}
default:{
if(mobile == user.mobile){
localStorage.setItem('uAuth',true)
location.reload()
}else{
$("input[name='lMobile']").val("")
$("label[for='lMobile']").text(" re-check mobile").css('color','firebrick')
}
}
}
})
$(document).on('click','.navIcon',function(){
let text = $(this).attr('id')
$("article").remove()
$("<article>").empty().attr("class",text).append(
$("<h2>").attr('class','aH2').text(text.toUpperCase())
).insertBefore("nav")
})
$(document).on('click','#calls',function(){
$(".calls").append(
$("<aside>").append(
$("<div>").attr('class','row2').append(
$("<img>").attr({
'alt':'addCNT','src':'assets/addContact.svg','type':'image/svg+xml','id':'aCNT','class':'cOPT'
}),
$("<img>").attr({
'alt':'phBook','src':'assets/phBook.svg','type':'image/svg+xml','id':'phBook','class':'cOPT'
})
)
),
$("<aside>").attr('class','callLog').append(
$("<h3>").attr('class','aH3')
)
)
showLog()
})
$(document).on('click','#aCNT',function(){
$(".showContacts").hide()
$(".formContact").empty().append(
$("<fieldset>").append(
$("<legend>").text("ADD CONTACT"),
$("<form>").attr('id','formCNT').append(
$("<div>").attr('class','row').append(
$("<input>").attr({
'type':'text','name':'fName','placeholder':'Enter First Name'
}).prop('required',true),
$("<label>").attr('for','fName')
),
$("<div>").attr('class','row').append(
$("<input>").attr({
'type':'text','name':'lName','placeholder':'Enter Last Name'
}).prop('required',true),
$("<label>").attr('for','lName')
),
$("<div>").attr('class','row').append(
$("<input>").attr({
'type':'tel','name':'mobile','placeholder':'Enter Mobile Number',
'pattern':'[0-9]{10}','title':'Enter 10 digit mobile number with out country code'
}).prop('required',true),
$("<label>").attr('for','mobile')
),
$("<div>").attr('class','row').append(
$("<inp
您可以存储所有传入的流并播放它。
这是一些简单的例子:
var1. 从定义你的s开始var localStream;
var remoteStream = {};
Run Code Online (Sandbox Code Playgroud)
navigator.medisDevices.getUserMedia({video: true, audio: true}).then((stream) =>{
localStream = stream;
//Plays it on your video
$("#local-video").prop("srcObject", localStream);
});
Run Code Online (Sandbox Code Playgroud)
这是当您已经在通话中,但有人加入通话时,因此他们将运行步骤 4 中的代码,然后您会在步骤 3 中收到。
peer.on("call", (call) => {
call.answer(localStream);
call.on("stream", (stream) => { //here's where you get the stream
remoteStream[call.peer] = stream; //Update your record.
$("#video-" + call.peeer).remove(); //Remove remote video if exists before
$("#video-list").append("<video id='video-"+ call.peeer +"' autoplay></video>"); //Create new video element
$("#video-"+ call.peeer).prop("srcObject", stream); //Put stream to the video
});
});
Run Code Online (Sandbox Code Playgroud)
一旦页面加载,这个就会调用。因此,如果用户刷新页面,它将自动对可用联系人进行每次呼叫。
//You have you contacts in var contacts
contacts.forEach((x, y) => {
call = peer.call(x.peerId, localStream);
call.on("stream", () => {
remoteStream[call.peer] = stream; //Update your record.
$("#video-" + call.peeer).remove(); //Remove remote video if exists before
$("#video-list").append("<video id='video-"+ call.peeer +"' autoplay></video>"); //Create new video element
$("#video-"+ call.peeer).prop("srcObject", stream); //Put stream to the video
});
});
Run Code Online (Sandbox Code Playgroud)
这是处理多个呼叫的基本方法。它只是简单地接受呼叫,并相互交换流。
如您所见,步骤 3 和步骤 4 具有类似的处理远程流的技术,但它们的不同之处只是步骤 3 是“等待呼叫”而步骤 4 是“拨打电话”。但这两个接收远程流。
最简单的方法是,您必须room在数据库中创建一条记录。因此,aroom将拥有具有 16 个字符的唯一 (az,AZ,0-9) 对等 ID 的其他联系人。因此,每个登录的用户都知道自己的对等 ID,并且知道其他用户使用对等 ID。
固定peer id不太安全,因为其他人可以使用它。处理此问题的最佳方法是不断更改对等 ID,也许在完成调用后创建到期或通过数据通道发送或使用到期令牌访问等。