Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add video codec and max bitrate settings #10

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
18 changes: 18 additions & 0 deletions frontend/html/client.html
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,24 @@ <h1>Waiting...</h1>
<label for="audioSource">🎙️ Microphone</label>
<select id="audioSource"></select>
<hr />
<label>Video codec</label>
<select id="videoSenderCodecSelect">
<option value="default">Default</option>
<option value="video/VP8">video/VP8</option>
<option value="video/VP9">video/VP9</option>
<option value="video/AVI">video/AV1</option>
<option value="video/H264">video/H264</option>
</select>
<label>Video max bitrate</label>
<select id="videoSenderMaxBitrateSelect">
<option value="default">Default</option>
<option value="16">16 Mbps</option>
<option value="8">8 Mbps</option>
<option value="4">4 Mbps</option>
<option value="2">2 Mbps</option>
<option value="1">1 Mbps</option>
</select>
<hr />
<table id="settingsTable">
<tr id="maxVideoQualityDiv">
<td><span>✨ Best quality</span></td>
Expand Down
72 changes: 72 additions & 0 deletions frontend/js/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ const pushToTalkDiv = document.getElementById('pushToTalkDiv');
const switchMaxVideoQuality = document.getElementById('switchMaxVideoQuality');
const switchKeepAspectRatio = document.getElementById('switchKeepAspectRatio');
const switchPushToTalk = document.getElementById('switchPushToTalk');
const videoSenderCodecSelect = document.getElementById('videoSenderCodecSelect');
const videoSenderMaxBitrateSelect = document.getElementById('videoSenderMaxBitrateSelect');
const sessionTime = document.getElementById('sessionTime');
const chat = document.getElementById('chat');
const chatOpenBtn = document.getElementById('chatOpenBtn');
Expand All @@ -56,6 +58,8 @@ const roomURL = window.location.origin + '/?room=' + roomId;

const config = {
forceToMaxVideoAndFps: window.localStorage.forceToMaxVideoAndFps == 'true' || false,
videoSenderCodec: window.localStorage.videoSenderCodec || 'default',
videoSenderMaxBitrate: window.localStorage.videoSenderMaxBitrate || 'default',
keepAspectRatio: window.localStorage.keepAspectRatio == 'true' || false,
};

Expand Down Expand Up @@ -231,6 +235,7 @@ function handleConnect() {
handleEvents();
showWaitingUser();
joinToChannel();
refreshCodecAndBitrate();
});
}
}
Expand Down Expand Up @@ -266,6 +271,57 @@ function handleServerInfo(config) {
redirectURL = config.redirectURL;
}

async function refreshCodecAndBitrate() {
try {
if (!thereIsPeerConnections()) return;
for (let peerId in peerConnections) {
let videoSelectCodecChanged = false;
let videoSenderMaxBitrateChanged = false;
let videoTransceiver = peerConnections[peerId]
.getTransceivers()
.find((s) => s.sender.track && s.sender.track.kind === 'video');
if (videoTransceiver) {
// Get the sender's parameters
const videoSender = videoTransceiver.sender;
const videoParameters = await videoSender.getParameters();
// Update codec in real time
if (config.videoSenderCodec !== 'default') {
const senderCapabilities = RTCRtpSender.getCapabilities(videoSender.track.kind);
const selectedCodec = senderCapabilities.codecs.find((codec) =>
Copy link
Contributor Author

@ZZYSonny ZZYSonny Sep 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if Array.find is enough. Codec may have other different property (like profiles). In the worst case, you might select a codec whose profile is not supported on the receiver, but the receiver may support other profiles.

The old way of setting codec (setCodecPreferences, although must before createAnswer/createOffer) accepts an array so there might be some negotiation going on.

codec.mimeType.includes(config.videoSenderCodec),
);
if (selectedCodec) {
await videoSender.replaceTrack(videoSender.track.clone(), {
codec: selectedCodec,
});
console.log(`Codec changed for ${peerId} to:`, selectedCodec);
videoSelectCodecChanged = true;
}
}
// Update max bitrate in real time
if (config.videoSenderMaxBitrate !== 'default') {
videoParameters.encodings[0].maxBitrate = config.videoSenderMaxBitrate * 1000000;
await videoSender.setParameters(videoParameters);
console.log(`Max bitrate changed for ${peerId} to:`, config.videoSenderMaxBitrate, 'Mbps');
videoSenderMaxBitrateChanged = true;
}
}
// Popup message
if (videoSelectCodecChanged || videoSenderMaxBitrateChanged) {
popupMessage(
'toast',
'Video Codec and max bitrate',
`Video codec changed to ${config.videoSenderCodec} and max bitrate to ${config.videoSenderMaxBitrate} Mbps`,
'top',
);
}
}
} catch (error) {
console.error('Error in refreshCodecAndBitrate:', error);
popupMessage('error', 'Refresh Codec And Bitrate Error', error.message);
}
}

function handleAddPeer(config) {
if (roomPeersCount > 2) {
return roomIsBusy();
Expand Down Expand Up @@ -295,6 +351,7 @@ function handleAddPeer(config) {
}
if (thereIsPeerConnections()) {
elemDisplay(waitingDivContainer, false);
refreshCodecAndBitrate();
}
handleBodyEvents();
playSound('join');
Expand Down Expand Up @@ -741,6 +798,7 @@ function handleEvents() {
};
videoSource.onchange = (e) => {
changeCamera(e.target.value);
refreshCodecAndBitrate();
};
videoQualitySelect.onchange = (e) => {
refreshVideoConstraints();
Expand All @@ -764,6 +822,20 @@ function handleEvents() {
}
playSound('switch');
};
videoSenderCodecSelect.value = config.videoSenderCodec;
videoSenderCodecSelect.onchange = (e) => {
config.videoSenderCodec = e.target.value;
window.localStorage.videoSenderCodec = e.target.value;
refreshCodecAndBitrate();
playSound('switch');
};
videoSenderMaxBitrateSelect.value = config.videoSenderMaxBitrate;
videoSenderMaxBitrateSelect.onchange = (e) => {
config.videoSenderMaxBitrate = e.target.value;
window.localStorage.videoSenderMaxBitrate = e.target.value;
refreshCodecAndBitrate();
playSound('switch');
};
switchKeepAspectRatio.checked = config.keepAspectRatio;
switchKeepAspectRatio.onchange = (e) => {
config.keepAspectRatio = e.currentTarget.checked;
Expand Down