restore browser video codec defaults
This commit is contained in:
1 parent
2888a54259
commit
25bc94a3a1
3 files changed
+19
-21
No files matched your search
@@ -24,6 +24,8 @@ PORT=8081 npm start
|
|||||||
and periodic packet-loss, jitter, and RTT quality diagnostics.
|
and periodic packet-loss, jitter, and RTT quality diagnostics.
|
||||||
- Audio input has manual gain control and a live signal/clipping meter in the
|
- Audio input has manual gain control and a live signal/clipping meter in the
|
||||||
settings dialog; microphone processing is split into `public/audio-manager.js`.
|
settings dialog; microphone processing is split into `public/audio-manager.js`.
|
||||||
|
- Screen sharing uses the browser's default codec negotiation, with selectable
|
||||||
|
`detail` (text/UI) or `motion` (gameplay) content hints.
|
||||||
|
|
||||||
## ICE configuration (server side)
|
## ICE configuration (server side)
|
||||||
|
|
||||||
|
|||||||
+9
-21
@@ -37,6 +37,7 @@ const FALLBACK_ICE = { iceServers: [{ urls: ['stun:turn.k6n.net:3478', 'stun:stu
|
|||||||
const LS_NAME = 'voicepoc.nick';
|
const LS_NAME = 'voicepoc.nick';
|
||||||
const LS_ICE = 'voicepoc.iceOverride';
|
const LS_ICE = 'voicepoc.iceOverride';
|
||||||
const LS_AUDIO_INPUT = 'voicepoc.audioInput';
|
const LS_AUDIO_INPUT = 'voicepoc.audioInput';
|
||||||
|
const LS_SCREEN_HINT = 'voicepoc.screenHint';
|
||||||
|
|
||||||
const S = {
|
const S = {
|
||||||
ws: null,
|
ws: null,
|
||||||
@@ -159,26 +160,6 @@ function preferOpus(pc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function preferH264(pc) {
|
|
||||||
const capabilities = globalThis.RTCRtpReceiver?.getCapabilities?.('video');
|
|
||||||
const codecs = capabilities?.codecs || [];
|
|
||||||
const rank = (codec) => {
|
|
||||||
const mime = codec.mimeType?.toLowerCase() || '';
|
|
||||||
if (mime === 'video/h264') return 0;
|
|
||||||
if (mime === 'video/vp8') return 1;
|
|
||||||
if (mime === 'video/vp9') return 2;
|
|
||||||
return 3;
|
|
||||||
};
|
|
||||||
const ordered = [...codecs].sort((a, b) => rank(a) - rank(b));
|
|
||||||
for (const transceiver of pc.getTransceivers()) {
|
|
||||||
if (transceiver.receiver?.track?.kind === 'video' || transceiver.sender?.track?.kind === 'video') {
|
|
||||||
try { transceiver.setCodecPreferences(ordered); } catch (err) {
|
|
||||||
captureRumIssue('Could not prefer H.264 video codec', 'WARNING', { error: err?.message || String(err) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function monitorPeerQuality(peer) {
|
function monitorPeerQuality(peer) {
|
||||||
if (peer.qualityTimer) clearInterval(peer.qualityTimer);
|
if (peer.qualityTimer) clearInterval(peer.qualityTimer);
|
||||||
peer.qualityTimer = setInterval(async () => {
|
peer.qualityTimer = setInterval(async () => {
|
||||||
@@ -1035,6 +1016,8 @@ async function startScreenShare() {
|
|||||||
for (const peer of S.peers.values()) addScreenToPeer(peer);
|
for (const peer of S.peers.values()) addScreenToPeer(peer);
|
||||||
const videoTrack = stream.getVideoTracks()[0];
|
const videoTrack = stream.getVideoTracks()[0];
|
||||||
if (videoTrack) {
|
if (videoTrack) {
|
||||||
|
const screenHint = localStorage.getItem(LS_SCREEN_HINT) || '';
|
||||||
|
if ('contentHint' in videoTrack) videoTrack.contentHint = screenHint;
|
||||||
videoTrack.addEventListener('ended', () => stopScreenShare(stream));
|
videoTrack.addEventListener('ended', () => stopScreenShare(stream));
|
||||||
}
|
}
|
||||||
renderScreens();
|
renderScreens();
|
||||||
@@ -1057,7 +1040,6 @@ function addScreenToPeer(peer) {
|
|||||||
}
|
}
|
||||||
peerSenders.set(streamId, senders);
|
peerSenders.set(streamId, senders);
|
||||||
}
|
}
|
||||||
preferH264(peer.pc);
|
|
||||||
S.screenSenders.set(peer.id, peerSenders); // renegotiation fires automatically
|
S.screenSenders.set(peer.id, peerSenders); // renegotiation fires automatically
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2199,6 +2181,8 @@ function openSettings() {
|
|||||||
const gain = $('#mic-gain');
|
const gain = $('#mic-gain');
|
||||||
if (gain) gain.value = S.audioManager.gain;
|
if (gain) gain.value = S.audioManager.gain;
|
||||||
updateMicGainUi();
|
updateMicGainUi();
|
||||||
|
const screenHint = $('#screen-hint');
|
||||||
|
if (screenHint) screenHint.value = localStorage.getItem(LS_SCREEN_HINT) || '';
|
||||||
const override = localStorage.getItem(LS_ICE);
|
const override = localStorage.getItem(LS_ICE);
|
||||||
$('#override-enabled').checked = !!override;
|
$('#override-enabled').checked = !!override;
|
||||||
const current = override ? JSON.parse(override) : effectiveIce();
|
const current = override ? JSON.parse(override) : effectiveIce();
|
||||||
@@ -2220,6 +2204,10 @@ $('#mic-gain').oninput = (ev) => {
|
|||||||
S.audioManager.setGain(ev.target.value);
|
S.audioManager.setGain(ev.target.value);
|
||||||
updateMicGainUi();
|
updateMicGainUi();
|
||||||
};
|
};
|
||||||
|
$('#screen-hint').onchange = (ev) => {
|
||||||
|
localStorage.setItem(LS_SCREEN_HINT, ev.target.value);
|
||||||
|
toast('Screen-share hint saved — applies next time you share', 'ok');
|
||||||
|
};
|
||||||
$('#audio-input').onchange = (ev) => switchAudioInput(ev.target.value);
|
$('#audio-input').onchange = (ev) => switchAudioInput(ev.target.value);
|
||||||
$('#ice-cancel').onclick = () => $('#modal-backdrop').classList.add('hidden');
|
$('#ice-cancel').onclick = () => $('#modal-backdrop').classList.add('hidden');
|
||||||
$('#modal-backdrop').onclick = (ev) => {
|
$('#modal-backdrop').onclick = (ev) => {
|
||||||
|
|||||||
@@ -150,6 +150,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<p id="mic-clipping" class="hint hidden">Clipping detected — reduce microphone gain.</p>
|
<p id="mic-clipping" class="hint hidden">Clipping detected — reduce microphone gain.</p>
|
||||||
<p class="hint">Changes apply immediately when connected, or the next time you join.</p>
|
<p class="hint">Changes apply immediately when connected, or the next time you join.</p>
|
||||||
|
<h3>Screen sharing</h3>
|
||||||
|
<label class="field-label" for="screen-hint">Optimization</label>
|
||||||
|
<select id="screen-hint" class="settings-select">
|
||||||
|
<option value="">Browser default</option>
|
||||||
|
<option value="detail">Details / text editor / terminal</option>
|
||||||
|
<option value="motion">Gameplay / motion</option>
|
||||||
|
</select>
|
||||||
|
<p class="hint">Details favors sharp text; motion favors smoother movement.</p>
|
||||||
<p class="hint">Overrides the server-provided ICE configuration (stored in <code>localStorage</code>, applied on next join).</p>
|
<p class="hint">Overrides the server-provided ICE configuration (stored in <code>localStorage</code>, applied on next join).</p>
|
||||||
<label class="toggle-row">
|
<label class="toggle-row">
|
||||||
<input type="checkbox" id="override-enabled" />
|
<input type="checkbox" id="override-enabled" />
|
||||||
|
|||||||
Reference in new issue
Block a user