Compare commits
3 Commits
05e7f69ffb
...
d908cf4ee6
| Author | SHA1 | Date | |
|---|---|---|---|
| d908cf4ee6 | |||
| 522a6255fe | |||
| 5784aa68e1 |
@@ -81,7 +81,7 @@ define(['./workbox-290dd570'], (function (workbox) { 'use strict';
|
||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||
}, {
|
||||
"url": "index.html",
|
||||
"revision": "0.lhgefe7plc8"
|
||||
"revision": "0.881sreuemg"
|
||||
}], {});
|
||||
workbox.cleanupOutdatedCaches();
|
||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||
|
||||
File diff suppressed because one or more lines are too long
+60
-33
@@ -679,39 +679,46 @@ router.get('/devices/list', async (req, res) => {
|
||||
|
||||
// Détection selon la plateforme
|
||||
if (process.platform === 'darwin') {
|
||||
// macOS : utiliser CoreAudio via sox
|
||||
const { exec } = await import('child_process');
|
||||
const { promisify } = await import('util');
|
||||
const execPromise = promisify(exec);
|
||||
|
||||
// macOS : utiliser CoreAudioBackend.getDevices()
|
||||
try {
|
||||
// Utiliser sox pour lister les devices audio
|
||||
const { stdout } = await execPromise('sox -V6 2>&1');
|
||||
const coreAudioDevices = CoreAudioBackend.getDevices();
|
||||
|
||||
// Parser la sortie sox pour extraire les devices
|
||||
// Format typique : "Input Device [0]: MacBook Pro Microphone"
|
||||
const inputMatches = stdout.matchAll(/Input Device \[(\d+)\]: (.+)/g);
|
||||
const outputMatches = stdout.matchAll(/Output Device \[(\d+)\]: (.+)/g);
|
||||
// Séparer inputs et outputs
|
||||
coreAudioDevices.forEach(device => {
|
||||
if (device.maxInputChannels > 0) {
|
||||
devices.inputs.push({
|
||||
id: device.name, // Utiliser le nom comme ID (compatible avec inputDeviceName)
|
||||
name: device.name,
|
||||
channels: device.maxInputChannels,
|
||||
sampleRate: device.defaultSampleRate,
|
||||
isDefault: device.isDefault?.input || false
|
||||
});
|
||||
}
|
||||
|
||||
for (const match of inputMatches) {
|
||||
devices.inputs.push({
|
||||
id: parseInt(match[1], 10),
|
||||
name: match[2].trim()
|
||||
});
|
||||
if (device.maxOutputChannels > 0) {
|
||||
devices.outputs.push({
|
||||
id: device.name, // Utiliser le nom comme ID (compatible avec outputDeviceName)
|
||||
name: device.name,
|
||||
channels: device.maxOutputChannels,
|
||||
sampleRate: device.defaultSampleRate,
|
||||
isDefault: device.isDefault?.output || false
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Fallback si aucun device trouvé
|
||||
if (devices.inputs.length === 0) {
|
||||
devices.inputs.push({ id: 'builtin-mic', name: 'Built-in Microphone', isDefault: true });
|
||||
}
|
||||
|
||||
for (const match of outputMatches) {
|
||||
devices.outputs.push({
|
||||
id: parseInt(match[1], 10),
|
||||
name: match[2].trim()
|
||||
});
|
||||
if (devices.outputs.length === 0) {
|
||||
devices.outputs.push({ id: 'builtin-output', name: 'Built-in Output', isDefault: true });
|
||||
}
|
||||
} catch (soxError) {
|
||||
console.warn('⚠️ sox non disponible, devices limités:', soxError.message);
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Détection CoreAudio échouée:', error.message);
|
||||
|
||||
// Fallback : devices par défaut macOS
|
||||
devices.inputs.push({ id: 0, name: 'Default Input (Built-in Microphone)', isDefault: true });
|
||||
devices.outputs.push({ id: 0, name: 'Default Output (Built-in Speakers)', isDefault: true });
|
||||
devices.inputs.push({ id: 'builtin-mic', name: 'Built-in Microphone', isDefault: true });
|
||||
devices.outputs.push({ id: 'builtin-output', name: 'Built-in Output', isDefault: true });
|
||||
}
|
||||
|
||||
} else if (process.platform === 'linux') {
|
||||
@@ -736,21 +743,41 @@ router.get('/devices/list', async (req, res) => {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Fallback : PipeWire via pactl
|
||||
// Fallback : PipeWire/PulseAudio via pactl
|
||||
const { stdout: paDevices } = await execPromise('pactl list short sources 2>/dev/null || echo ""');
|
||||
const { stdout: paSinks } = await execPromise('pactl list short sinks 2>/dev/null || echo ""');
|
||||
|
||||
// Helper pour obtenir une description lisible
|
||||
const getDeviceDescription = (deviceId) => {
|
||||
// Extraire une description plus lisible du nom technique
|
||||
if (deviceId.includes('alsa_input')) return deviceId.replace('alsa_input.', 'Input: ');
|
||||
if (deviceId.includes('alsa_output')) return deviceId.replace('alsa_output.', 'Output: ');
|
||||
return deviceId;
|
||||
};
|
||||
|
||||
if (paDevices.trim()) {
|
||||
paDevices.split('\n').filter(Boolean).forEach((line, idx) => {
|
||||
const name = line.split('\t')[1] || `Device ${idx}`;
|
||||
devices.inputs.push({ id: idx, name });
|
||||
paDevices.split('\n').filter(Boolean).forEach((line) => {
|
||||
const parts = line.split('\t');
|
||||
const deviceId = parts[1]; // Nom du device (ex: alsa_input.pci-...)
|
||||
if (deviceId && !deviceId.includes('.monitor')) { // Ignorer les monitors
|
||||
devices.inputs.push({
|
||||
id: deviceId,
|
||||
name: getDeviceDescription(deviceId)
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (paSinks.trim()) {
|
||||
paSinks.split('\n').filter(Boolean).forEach((line, idx) => {
|
||||
const name = line.split('\t')[1] || `Device ${idx}`;
|
||||
devices.outputs.push({ id: idx, name });
|
||||
paSinks.split('\n').filter(Boolean).forEach((line) => {
|
||||
const parts = line.split('\t');
|
||||
const deviceId = parts[1]; // Nom du device (ex: alsa_output.pci-...)
|
||||
if (deviceId) {
|
||||
devices.outputs.push({
|
||||
id: deviceId,
|
||||
name: getDeviceDescription(deviceId)
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,26 +372,6 @@ export class AudioBridge extends EventEmitter {
|
||||
|
||||
// Réception audio depuis les clients LiveKit de ce groupe
|
||||
client.on('audioData', ({ participantName, pcmData, sampleRate, channels }) => {
|
||||
// Log premier frame pour diagnostic
|
||||
if (!this._firstFrameLogged) {
|
||||
// Calculer RMS pour détecter silence
|
||||
let sumSquares = 0;
|
||||
for (let i = 0; i < Math.min(240, pcmData.length); i++) {
|
||||
sumSquares += pcmData[i] * pcmData[i];
|
||||
}
|
||||
const rms = Math.sqrt(sumSquares / Math.min(240, pcmData.length));
|
||||
const dbFS = 20 * Math.log10(rms / 32768.0);
|
||||
|
||||
console.log(`🔍 Diagnostic audio LiveKit:
|
||||
sampleRate: ${sampleRate}
|
||||
channels: ${channels || 1} (défaut: 1 si undefined)
|
||||
buffer size: ${pcmData.length} samples (${pcmData.length * 2} bytes)
|
||||
buffer type: ${pcmData.constructor.name}
|
||||
first 10 samples: [${Array.from(pcmData.slice(0, 10)).join(', ')}]
|
||||
RMS level: ${rms.toFixed(0)} (${dbFS.toFixed(1)} dBFS)`);
|
||||
this._firstFrameLogged = true;
|
||||
}
|
||||
|
||||
// Router vers le bon groupe
|
||||
this.emit('groupAudioIn', { groupName: groupId, pcmBuffer: pcmData });
|
||||
});
|
||||
|
||||
+249
-67
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user