openvibers/openvibe.live Commits

Go Live says what viewers will get before the button (#512)

OP OpenVibers committed 12 days ago · 0d6014b329 · 3 files, +61 −0

Above the button: the picture and the sound by device name (the setup card's own labels, kept current as a person
picks), or for a screen share that the browser asks which screen at the button; what can change once live (mute,
camera off, switch cameras) and what means a new stream (camera to screen); and the browsers it works in.

Changes

ddiff --git a/public/css/features/broadcast.css b/public/css/features/broadcast.css
iindex 6f4065d3..fdd873aa 100644
---- a/public/css/features/broadcast.css
++++ b/public/css/features/broadcast.css
@@@ -2964,6 +2964,15 @@ body.bc-golive-dock-on #page-broadcast { padding-bottom: calc(104px + var(--ovna
display: flex; align-items: center; justify-content: center; gap: 10px; width: 100%;
min-height: 52px; margin-top: 14px; padding: 12px 20px; border-radius: 14px; font-size: 1.02rem; font-weight: 700;
}
++/* What viewers will get, before the Go Live button (broadcast-workspace.js _wsPreflight). */
++.bc-preflight { margin: 12px 0 12px; padding: 10px 12px; border: 1px dashed color-mix(in srgb, var(--accent) 45%, var(--border)); border-radius: 12px; background: color-mix(in srgb, var(--accent) 5%, transparent); }
++.bc-preflight-h { margin: 0 0 6px; font-size: 0.72rem; font-weight: 800; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-muted); }
++.bc-preflight ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
++.bc-preflight li { display: flex; align-items: baseline; gap: 8px; font-size: 0.86rem; color: var(--text-secondary); min-width: 0; }
++.bc-preflight li i { flex: 0 0 16px; text-align: center; color: var(--accent); }
++.bc-preflight li span { min-width: 0; overflow-wrap: anywhere; }
++.bc-preflight li b { color: var(--text-primary); font-weight: 650; }
++.bc-preflight-note { margin: 8px 0 0; font-size: 0.76rem; line-height: 1.45; color: var(--text-muted); }
.bc-ws-golive-section .bc-create-reassurance { margin: 10px 0 0 !important; text-align: center; font-size: 0.78rem !important; color: var(--text-muted); overflow-wrap: anywhere; }
/* A wide panel keeps the setup and the button a readable width, centred under the two columns. */
@container bcws (min-width: 960px) {
ddiff --git a/public/js/broadcast-workspace.js b/public/js/broadcast-workspace.js
iindex 4fc48f86..66781b87 100644
---- a/public/js/broadcast-workspace.js
++++ b/public/js/broadcast-workspace.js
@@@ -620,6 +620,8 @@ function _wsRenderPanel() {
<select id="bc-screen-audio" style="display:none"><option value="default">Default</option></select>
<select id="bc-screen-camera" style="display:none"><option value="default">Default</option></select>
++ ${_wsPreflight(browserMode)}
++
<button class="btn btn-primary btn-lg bc-ws-golive-btn"
onclick="goLiveFromWorkspace()" id="bc-ws-golive-btn">
<i class="fa-solid fa-tower-broadcast"></i> Go Live
@@@ -1147,6 +1149,29 @@ function _wsPickHint(kind, id) {
}
/** The line over Allow …, before the browser may use the camera or microphone. */
++/**
++ * What viewers will get, said before the button (market outcome 6: a pre-flight summary of what will be captured; 5:
++ * what can and cannot change once live, and the browsers). The device names are the setup card's own: each
++ * [data-pick-for] here is kept current by _bcSyncPicks (broadcast-devices.js), like the card's rows.
++ */
++function _wsPreflight(mode) {
++ const cam = '<b data-pick-for="bc-create-camera">Default</b>';
++ const mic = '<b data-pick-for="bc-create-audio">Default</b>';
++ const rows = mode === 'mic_only' ? [['fa-microphone', `Sound from ${mic}`], ['fa-eye-slash', 'No picture']]
++ : mode === 'camera_only' ? [['fa-video', `Picture from ${cam}`], ['fa-volume-xmark', 'No sound']]
++ : mode === 'screen' ? [['fa-display', 'Your screen, a window or a tab: your browser asks which when you press Go Live'], ['fa-microphone', 'Your microphone and camera bubble, as set above']]
++ : [['fa-video', `Picture from ${cam}`], ['fa-microphone', `Sound from ${mic}`]];
++ const can = mode === 'screen' ? 'While live you can mute the microphone. Switching to your camera means a new stream.'
++ : mode === 'mic_only' ? 'While live you can mute the microphone. Adding a picture means a new stream.'
++ : mode === 'camera_only' ? 'While live you can turn the camera off or switch cameras. Sharing your screen instead means a new stream.'
++ : 'While live you can mute, turn the camera off or switch cameras. Sharing your screen instead means a new stream.';
++ return `<div class="bc-preflight" role="group" aria-labelledby="bc-preflight-h">
++ <p class="bc-preflight-h" id="bc-preflight-h">What viewers will get</p>
++ <ul>${rows.map(([icon, text]) => `<li><i class="fa-solid ${icon}" aria-hidden="true"></i><span>${text}</span></li>`).join('')}</ul>
++ <p class="bc-preflight-note">${can} Works in Chrome, Edge, Firefox and Safari.</p>
++ </div>`;
++}
++
function _wsPermHint(mode) {
return mode === 'mic_only' ? 'Let your browser use the microphone to choose one.'
: mode === 'camera_only' ? 'Let your browser use the camera to choose one.'
ddiff --git a/test/golive-preflight.test.js b/test/golive-preflight.test.js
nnew file mode 100644
iindex 00000000..d3310d92
---- /dev/null
++++ b/test/golive-preflight.test.js
@@@ -0,0 +1,27 @@
++'use strict';
++/**
++ * The Go Live section says what viewers will get before the button (market outcomes 5 and 6; broadcast-workspace.js
++ * _wsPreflight): the picture and sound by device name (the setup card's own [data-pick-for] labels, kept current by
++ * _bcSyncPicks), what can change once live and what means a new stream, and the browsers it works in.
++ */
++const assert = require('assert');
++const fs = require('fs');
++const path = require('path');
++
++const src = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'broadcast-workspace.js'), 'utf8');
++const start = src.indexOf('function _wsPreflight(mode)');
++const end = src.indexOf('\nfunction _wsPermHint', start);
++assert.ok(start > 0 && end > start, 'the function is there');
++const preflight = new Function(`${src.slice(start, end)}; return _wsPreflight;`)();
++
++const cam = preflight('camera');
++assert.ok(cam.includes('Picture from <b data-pick-for="bc-create-camera">') && cam.includes('Sound from <b data-pick-for="bc-create-audio">'), 'camera: the chosen devices by name');
++assert.ok(cam.includes('you can mute, turn the camera off or switch cameras') && cam.includes('Sharing your screen instead means a new stream'), 'what can change once live, and what cannot');
++assert.ok(cam.includes('Works in Chrome, Edge, Firefox and Safari.'), 'the browsers');
++assert.ok(preflight('screen').includes('your browser asks which when you press Go Live'), 'screen: what is captured is picked at the button');
++assert.ok(preflight('mic_only').includes('No picture') && !preflight('mic_only').includes('bc-create-camera'), 'sound only');
++assert.ok(preflight('camera_only').includes('No sound') && !preflight('camera_only').includes('bc-create-audio'), 'picture only');
++assert.ok(src.includes('${_wsPreflight(browserMode)}'), 'it sits in the Go Live section');
++const syncer = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'broadcast-devices.js'), 'utf8');
++assert.ok(syncer.includes("document.querySelectorAll('[data-pick-for]')"), 'and _bcSyncPicks keeps every [data-pick-for] current');
++console.log('golive-preflight: what viewers will get, said before the button');