mirror of
https://github.com/R0m1k3/LiveFlow.git
synced 2026-10-19 05:07:44 +02:00
feat: sélecteur de microphone dans l'interface
- Select dropdown peuplé via enumerateDevices() au chargement - Mise à jour automatique quand un périphérique est branché/débranché (devicechange) - Le deviceId sélectionné est passé à getUserMedia() via exact constraint - Option 'Micro par défaut' pour le comportement d'origine
This commit is contained in:
1 parent
284011428a
commit
86f94fc22c
3 files changed
+48
-3
No files matched your search
+31
-3
@@ -28,13 +28,37 @@ function getSpeakerColorIndex(speaker) {
|
|||||||
return speakerMap[speaker];
|
return speakerMap[speaker];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------- sélection micro
|
||||||
|
|
||||||
|
async function populateMicList() {
|
||||||
|
const sel = $('mic-select');
|
||||||
|
try {
|
||||||
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
|
const mics = devices.filter((d) => d.kind === 'audioinput');
|
||||||
|
// Garder la sélection courante si possible
|
||||||
|
const current = sel.value;
|
||||||
|
sel.innerHTML = '<option value="">Micro par défaut</option>';
|
||||||
|
for (const mic of mics) {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = mic.deviceId;
|
||||||
|
opt.textContent = mic.label || `Micro ${sel.options.length}`;
|
||||||
|
sel.appendChild(opt);
|
||||||
|
}
|
||||||
|
if (current) sel.value = current;
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Impossible d\'énumérer les micros :', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------- enregistrement
|
// ----------------------------------------------------------- enregistrement
|
||||||
|
|
||||||
async function startRecording() {
|
async function startRecording() {
|
||||||
|
const audioConstraints = { echoCancellation: true, noiseSuppression: true, autoGainControl: true };
|
||||||
|
const selectedMic = $('mic-select').value;
|
||||||
|
if (selectedMic) audioConstraints.deviceId = { exact: selectedMic };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
state.mediaStream = await navigator.mediaDevices.getUserMedia({
|
state.mediaStream = await navigator.mediaDevices.getUserMedia({ audio: audioConstraints });
|
||||||
audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true },
|
|
||||||
});
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const causes = {
|
const causes = {
|
||||||
NotAllowedError: "Permission refusée. Autorisez le micro pour ce site (icône à gauche de l'adresse), et vérifiez que la page est servie en HTTPS.",
|
NotAllowedError: "Permission refusée. Autorisez le micro pour ce site (icône à gauche de l'adresse), et vérifiez que la page est servie en HTTPS.",
|
||||||
@@ -240,3 +264,7 @@ $('record-btn').onclick = () => (state.recording ? stopRecording() : startRecord
|
|||||||
$('copy-btn').onclick = copyTranscript;
|
$('copy-btn').onclick = copyTranscript;
|
||||||
$('delete-btn').onclick = deleteCurrentMeeting;
|
$('delete-btn').onclick = deleteCurrentMeeting;
|
||||||
loadMeetings();
|
loadMeetings();
|
||||||
|
|
||||||
|
// Peupler la liste des micros au chargement (et quand un périphérique change)
|
||||||
|
populateMicList();
|
||||||
|
navigator.mediaDevices?.addEventListener('devicechange', populateMicList);
|
||||||
@@ -22,6 +22,9 @@
|
|||||||
<main>
|
<main>
|
||||||
<section class="controls">
|
<section class="controls">
|
||||||
<input id="title" type="text" placeholder="Titre de la réunion (optionnel)">
|
<input id="title" type="text" placeholder="Titre de la réunion (optionnel)">
|
||||||
|
<select id="mic-select" title="Choisir le microphone">
|
||||||
|
<option value="">Micro par défaut</option>
|
||||||
|
</select>
|
||||||
<button id="record-btn" class="record">● Démarrer</button>
|
<button id="record-btn" class="record">● Démarrer</button>
|
||||||
<span id="timer">00:00</span>
|
<span id="timer">00:00</span>
|
||||||
<label id="diarization-toggle" class="toggle" title="Identifier les locuteurs">
|
<label id="diarization-toggle" class="toggle" title="Identifier les locuteurs">
|
||||||
|
|||||||
@@ -79,6 +79,20 @@ main { flex: 1; display: flex; flex-direction: column; min-width: 0; padding: 20
|
|||||||
}
|
}
|
||||||
.controls input:focus { outline: none; border-color: var(--accent); }
|
.controls input:focus { outline: none; border-color: var(--accent); }
|
||||||
|
|
||||||
|
#mic-select {
|
||||||
|
background: var(--panel-2);
|
||||||
|
border: 1px solid #2c3245;
|
||||||
|
color: var(--text);
|
||||||
|
padding: 10px 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
cursor: pointer;
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
#mic-select:focus { outline: none; border-color: var(--accent); }
|
||||||
|
#mic-select option { background: var(--panel); color: var(--text); }
|
||||||
|
|
||||||
|
|
||||||
button, .controls a {
|
button, .controls a {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
|
|||||||
Reference in new issue
Block a user