Skip to content

Request video during PeerJs ongoing live connection (stream)

I am new to PeerJs and recently starting developing an app for my school during this Covid pandemic.

I have been able to deploy code to NodeJs server with express and was able to establish connection between 2 users.

But the problem arises when video is turned off from the beginning of stream for both users and a user wants to initiate a video call.

What I need is, to send some kind of notification to user 2 that user 1 is requesting for video. So that user 2 will turn on video.

My existing code is:

var url = new URL(window.location.href);
var disableStreamInBeginning = url.searchParams.get("disableStreamInBeginning"); // To disable video in the beginning
var passwordProtectedRoom = url.searchParams.get("passwordProtectedRoom");
var muteAllInBeginning = url.searchParams.get("muteAllInBeginning");

const socket = io('/')
const localVideoDiv = document.getElementById('local-video-div')
const oneOnOneSelf = document.getElementById('local-video')
const oneOnOneRemote = document.getElementById('remote-video')
if(typeof disableStreamInBeginning !== 'undefined' && disableStreamInBeginning == 'true'){
    var disbaleSelfStream = true
} else {
    var disbaleSelfStream = false
}
if(typeof passwordProtectedRoom !== 'undefined' && passwordProtectedRoom == 'true'){
    var passwordProtected = true
} else {
    var passwordProtected = false
}
if(typeof muteAllInBeginning !== 'undefined' && muteAllInBeginning == 'true'){
    var muteAll = true
} else {
    var muteAll = false
}
var systemStream

oneOnOneSelf.style.opacity = 0
oneOnOneRemote.style.opacity = 0

const myPeer = new Peer(undefined, {
    host: '/',
    port: '443',
    path: '/myapp',
    secure: true
})
const ownVideoView = document.createElement('video')
const peers = {}
navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
}).then(ownStream => {
    systemStream = ownStream
    addVideoStream(ownStream, oneOnOneSelf)

    myPeer.on('call', call => {
        call.answer(ownStream)
        call.on('stream', remoteStream => {
            addVideoStream(remoteStream, oneOnOneRemote)
        })
    })

    socket.on('user-connected', userId => {
        //connectToNewUser(userId, stream)
        setTimeout(connectToNewUser, 1000, userId, ownStream)
    })

})

socket.on('user-disconnected', userId => {
    if (peers[userId]) peers[userId].close()
})

myPeer.on('open', id => {
    //Android.onPeerConnected();
    socket.emit('join-room', ROOM_ID, id)
})

function connectToNewUser(userId, stream) {
    const call = myPeer.call(userId, stream)
    call.on('stream', remoteStream => {
        //console.log('Testing')
        addVideoStream(remoteStream, oneOnOneRemote)
    })
    call.on('close', () => {
        oneOnOneRemote.remove()
    })

    peers[userId] = call
}

function addVideoStream(stream, videoView) {
    videoView.srcObject = stream
    videoView.addEventListener('loadedmetadata', () => {
        if(disbaleSelfStream){
            audioVideo(true)
        } else {
            localVideoDiv.style.opacity = 0
            videoView.style.opacity = 1
            videoView.play()
        }
    })
}

function audioVideo(bool) {
    if(bool == true){
        localVideoDiv.style.opacity = 1
        oneOnOneSelf.style.opacity = 0
        systemStream.getVideoTracks()[0].enabled = false
    } else {
        if(disbaleSelfStream){
            console.log('Waiting For Another User To Accept') // Here is need to inform user 2 to tun on video call
        } else {
            localVideoDiv.style.opacity = 0
            oneOnOneSelf.style.opacity = 1
            systemStream.getVideoTracks()[0].enabled = true
        }
    }
}

function muteUnmute(bool) {
    if(bool == true){
        systemStream.getAudioTracks()[0].enabled = true
    } else {
        systemStream.getAudioTracks()[0].enabled = false
    }
}

function remoteVideoClick(){
    alert('Hi');
}

Please help.

Answer

You can send messages back and forth directly using peer itself const dataConnection = peer.connect(id) will connect you to the remote peer, it returns a dataConnection class instance that you can later use with the send method of that class.

Just remember that you also want to setup listener on the other side to listen for this events, like “open” to know when the data channel is open: dataConnection.on(‘open’, and dataConnection.on(‘data…

You have a bug in your code above, I know you didn’t ask about it, it is hard to see and not always will manifest. The problem will occur when your originator sends a call before the destination has had time to receive the promise back with its local video/audio stream. The solution is to invert the order of the calls and to start by setting up the event handler for peer.on(“call”, … rather than by starting by waiting for a promise to return when we ask for the video stream. The failure mode will depend on how long does it take for your destination client to signal it wants and call to the originator plus how long it takes for the originator to respond versus how long it takes for the stream promise to return on the destination client. You can see a complete working example, where messages are also sent back and forth here.

// Function to obtain stream and then await until after it is obtained to go into video chat call and answer code. Critical to start the event listener ahead of everything to ensure not to miss an incoming call.
peer.on("call", async (call) => {
    let stream = null;
    console.log('*** "call" event received, calling call.answer(strem)');
    // Obtain the stream object
    try {
        stream = await navigator.mediaDevices.getUserMedia(
            {
                audio: true,
                video: true,
            });
        // Set up event listener for a peer media call -- peer.call, returns a mediaConnection that I name call        
        // Answer the call by sending this clients video stream --myVideo-- to calling remote user
        call.answer(stream);
        // Create new DOM element to place the remote user video when it comes
        const video = document.createElement('video');
        // Set up event listener for a stream coming from the remote user in response to this client answering its call
        call.on("stream", (userVideoStream) => {
            console.log('***"stream" event received, calling addVideoStream(UserVideoStream)');
            // Add remote user video stream to this client's active videos in the DOM
            addVideoStream(video, userVideoStream);
        });
    } catch (err) {
        /* handle the error */
        console.log('*** ERROR returning the stream: ' + err);
    };
});