多方 - 与peerJS 进行视频会议

Sik*_*kki 2 javascript webrtc peerjs

我尝试使用peerJS进行webRTC视频会议并成功进行了一对一会议,我需要一些帮助来推进多方视频会议,在这里我尝试解释我做了什么,请从我罢工的地方提供帮助

在这里我发布我的完整代码,以便任何人都可以通过修改一些信息来使用,

意图

  1. Alice 登录并呼叫 Bob
  2. 鲍勃加入爱丽丝通话
  3. Alice 呼叫 Carole(使用“添加呼叫”按钮)
  4. 卡罗尔加入爱丽丝呼叫
  5. 在 Alice、Bob 和 Carole 之间创建会议(使用“加入通话”按钮)

达到了

  1. Alice 登录并呼叫 Bob
  2. 鲍勃加入爱丽丝通话
  3. 爱丽丝给卡罗尔打电话
  4. 卡罗尔加入爱丽丝

我的情况

  • 注册并创建爱丽丝。
  • 爱丽丝登录。使用导航转到“呼叫”。
  • 使用“添加联系人”创建 Bob 和 Carole。
  • 转至电话簿,给 BOB 拨打了电话。
  • 鲍勃加入了爱丽丝。
  • Alice 使用 add call 再次拨打了 Carole 的电话。
  • 卡罗尔加入了爱丽丝。
  • 爱丽丝有鲍勃和卡罗尔,而鲍勃和卡罗尔却互相思念。
  • 还没有合并他们的流!

待处理需要帮助

  1. 当我单击“加入会议”时,在 Alice、Bob 和 Carole 之间创建会议 Bob 和 carole 也应该有 alice

如何在 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

Mr *_*ery 5

您可以存储所有传入的流并播放它。

这是一些简单的例子:

var1. 从定义你的s开始

var localStream;
var remoteStream = {};
Run Code Online (Sandbox Code Playgroud)

2.先获取自己的本地流:

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)

3. 等待和管理呼叫流

这是当您已经在通话中,但有人加入通话时,因此他们将运行步骤 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)

4. 拨打电话

一旦页面加载,这个就会调用。因此,如果用户刷新页面,它将自动对可用联系人进行每次呼叫。

//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 是“拨打电话”。但这两个接收远程流。

如何获取用户Peer ID

最简单的方法是,您必须room在数据库中创建一条记录。因此,aroom将拥有具有 16 个字符的唯一 (az,AZ,0-9) 对等 ID 的其他联系人。因此,每个登录的用户都知道自己的对等 ID,并且知道其他用户使用对等 ID。

固定peer id不太安全,因为其他人可以使用它。处理此问题的最佳方法是不断更改对等 ID,也许在完成调用后创建到期或通过数据通道发送或使用到期令牌访问等。


Copyright Info

© Copyright 2013-2021 admin@qa.1r1g.com

如未特别说明,本网站的内容使用如下协议:
Creative Commons Atution-NonCommercial-ShareAlike 4.0 International license
.

用以下方式浏览
回到顶部