Recently, I delved into experimenting with the straightforward mediasoup demo available at: https://github.com/Dirvann/mediasoup-sfu-webrtc-video-rooms
After setting up the demo, everything seemed to be functioning correctly.
The initial task on my agenda was to incorporate URL parameters to bypass the login screen. It sounded like a simple enough task, right? However, when trying to access a room directly by manipulating the URL parameters, that's where things took an unexpected turn – the remote streams of other users weren't displaying in the room! Strangely enough, they did display when a user entered a room through the login form.
What confuses me is that whether you click 'join' via the login form or have the parameters already in the URL, the same JavaScript method is triggered!
Let me walk you through the execution flow:
Initially, we have one user sharing their webcam in room 123. A second user visits the URL without the relevant parameters and encounters the login form: https://i.sstatic.net/bxfgp.png
Upon reviewing the details, the user decides to stick with the defaults and clicks the join button. This action triggers a basic function that updates the URL with the room and user values, leading to a page refresh.
After the page finishes refreshing, the required parameters are present, resulting in the video room loading and the remote stream appearing as shown here: https://i.sstatic.net/mPoEE.png
However, the issue arises when we skip the login form and directly append those necessary parameters to the URL ourselves, depicted here: https://i.sstatic.net/d35yM.png There should ideally be a remote stream displayed here since it's the same room from the previous image. I'm completely puzzled as to why this problem persists.
Included below is my index.js file, with all the modifications enclosed within the slashes towards the end of the file:
if (location.href.substr(0, 5) !== 'https')
location.href = 'https' + location.href.substr(4, location.href.length - 4)
const socket = io()
let producer = null;
nameInput.value = 'bob' + Math.round(Math.random() * 1000)
socket.request = function request(type, data = {}) {
return new Promise((resolve, reject) => {
socket.emit(type, data, (data) => {
if (data.error) {
reject(data.error)
} else {
resolve(data)
}
})
})
}
let rc = null
function joinRoom(name, room_id) {
if (rc && rc.isOpen()) {
console.log('already connected to a room')
} else {
rc = new RoomClient(localMedia, remoteVideos, remoteAudios, window.mediasoupClient, socket, room_id, name, roomOpen)
addListeners()
}
}
function roomOpen() {
login.className = 'hidden'
reveal(startAudioButton)
hide(stopAudioButton)
reveal(startVideoButton)
hide(stopVideoButton)
reveal(startScreenButton)
hide(stopScreenButton)
reveal(exitButton)
control.className = ''
reveal(videoMedia)
}
function hide(elem) {
elem.className = 'hidden'
}
function reveal(elem) {
elem.className = ''
}
function addListeners() {
rc.on(RoomClient.EVENTS.startScreen, () => {
hide(startScreenButton)
reveal(stopScreenButton)
})
rc.on(RoomClient.EVENTS.stopScreen, () => {
hide(stopScreenButton)
reveal(startScreenButton)
})
rc.on(RoomClient.EVENTS.stopAudio, () => {
hide(stopAudioButton)
reveal(startAudioButton)
})
rc.on(RoomClient.EVENTS.startAudio, () => {
hide(startAudioButton)
reveal(stopAudioButton)
})
rc.on(RoomClient.EVENTS.startVideo, () => {
hide(startVideoButton)
reveal(stopVideoButton)
})
rc.on(RoomClient.EVENTS.stopVideo, () => {
hide(stopVideoButton)
reveal(startVideoButton)
})
rc.on(RoomClient.EVENTS.exitRoom, () => {
hide(control)
reveal(login)
hide(videoMedia)
/////////////////////////
let indexOfQuestionMark = location.href.indexOf("?")
location.href = location.href.split('').slice(0, indexOfQuestionMark-1).join('')
/////////////////////////
})
}
// Load mediaDevice options
navigator.mediaDevices.enumerateDevices().then(devices =>
devices.forEach(device => {
let el = null
if ('audioinput' === device.kind) {
el = audioSelect
} else if ('videoinput' === device.kind) {
el = videoSelect
}
if(!el) return
let option = document.createElement('option')
option.value = device.deviceId
option.innerText = device.label
el.appendChild(option)
})
)
/////////////////////////
if (window.location.href.includes("?r=") && window.location.href.includes("n=")) {
let indexOfRoomNumber = location.href.indexOf("?r=")+3
let array = location.href.split('')
let room = array.slice(indexOfRoomNumber,indexOfRoomNumber+3).join("")
let username = array.slice(indexOfRoomNumber+6, array.length).join("")
joinRoom(username,room)
console.log(`Welcome to room: ${room}, ${username}`)
}
function addParams(name, room_id) {
window.location.href = `${location.href}?r=${room_id}+n=${name}`
}
//////////////////////////
The Join button within index.html invokes the addParams function directly, visible here:
<html>
<head>
<script src="socket.io/socket.io.js"></script>
<script src="modules/mediasoupclient.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/EventEmitter/5.2.8/EventEmitter.min.js"></script>
<script src="RoomClient.js"></script>
<style>
.containers {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(auto-fit, 1fr);
grid-template-rows: repeat(auto-fit, 300px);
}
.container {
display: flex;
}
.vid {
flex: 0 1 auto;
height: 400px;
}
.settings {
background-color: #4CAF50;
border: none;
color: white;
padding: 5px 10px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
margin: 2px 2px;
cursor: pointer;
}
.hidden {
display: none
}
</style>
</head>
<body>
<div id="login">
Room: <input id="roomidInput" value="123" type="text" />
<!--<button id="createRoom" onclick="createRoom(roomid.value)" label="createRoom">Create Room</button>-->
<br />
User: <input id='nameInput' value="bob" type="text" />
<button id='joinButton' onclick="addParams(nameInput.value, roomidInput.value)">Join</button>
</div>
<div id="control" class="hidden">
<button id='exitButton' class='hidden' onclick="rc.exit()">Exit</button>
<br/>
audio: <select id="audioSelect">
</select>
<br/>
video: <select id="videoSelect">
</select>
<br />
<button id='startAudioButton' class='hidden' onclick="rc.produce(RoomClient.mediaType.audio, audioSelect.value)">audio</button>
<button id='stopAudioButton' class='hidden' onclick="rc.closeProducer(RoomClient.mediaType.audio)">close
audio</button>
<button id='startVideoButton' class='hidden' onclick="rc.produce(RoomClient.mediaType.video, videoSelect.value)">video</button>
<button id='stopVideoButton' class='hidden' onclick="rc.closeProducer(RoomClient.mediaType.video)">close
video</button>
<button id='startScreenButton' class='hidden' onclick="rc.produce(RoomClient.mediaType.screen)">screen</button>
<button id='stopScreenButton' class='hidden' onclick="rc.closeProducer(RoomClient.mediaType.screen)">close
screen</button>
<br />
</div>
<div id='videoMedia' class='hidden'>
<h2>------local------</h2>
<div id="localMedia"></div>
<!--<video id="localVideo" autoplay inline class="vid"></video>-->
<!--<video id="localScreen" autoplay inline class="vid"></video>-->
<h2>-----remote-----</h2>
<div id="remoteVideos" class="container">
</div>
<div id="remoteAudios"></div>
</div>
</body>
<footer>
<script src="index.js"></script>
</footer>
</html>
Kindly note that the only files I've made changes to are the ones mentioned above. All other files remain identical to those in the GitHub repository for the demo (linked in the introduction).
It would greatly appreciate any guidance provided to help me uncover the root cause of this predicament. If the presence of URL parameters is what's affecting the room connections, then why does inserting them directly into the URL seem to yield such different outcomes?
Thank you sincerely for your time and any support you can offer! :)