feat: ajout APIs détection et configuration cartes son (Phase 2.5)

- GET /admin/audio/devices : énumération devices CoreAudio
- GET /admin/audio/device : récupération config actuelle
- POST /admin/audio/device : sélection carte son + sample rate
- Workaround naudiodon segfault avec devices fictifs
- Configuration sauvegardée dans config.yaml
This commit is contained in:
2026-05-25 09:40:43 +02:00
parent 55d777319b
commit 03b3f94824
3 changed files with 143 additions and 34 deletions
+84
View File
@@ -9,6 +9,7 @@ import { join } from 'path';
import YAML from 'yaml'; import YAML from 'yaml';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import { dirname } from 'path'; import { dirname } from 'path';
import { CoreAudioBackend } from '../bridge/backends/CoreAudioBackend.js';
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
const router = Router(); const router = Router();
@@ -473,4 +474,87 @@ router.put('/config/audio', (req, res) => {
} }
}); });
// ========== Routes Audio Devices (Phase 2.5) ==========
/**
* GET /admin/audio/devices
* Énumération de toutes les cartes son disponibles
*/
router.get('/audio/devices', (req, res) => {
try {
const devices = CoreAudioBackend.getDevices();
const defaultInput = CoreAudioBackend.getDefaultInputDevice();
const defaultOutput = CoreAudioBackend.getDefaultOutputDevice();
res.json({
devices,
defaultInput,
defaultOutput
});
} catch (error) {
console.error('Erreur GET /admin/audio/devices:', error);
res.status(500).json({ error: 'Failed to enumerate audio devices' });
}
});
/**
* GET /admin/audio/device
* Récupère la configuration actuelle de la carte son sélectionnée
*/
router.get('/audio/device', (req, res) => {
try {
const config = loadConfig();
const audioDevice = config.audio.device || {};
res.json({
device: audioDevice
});
} catch (error) {
console.error('Erreur GET /admin/audio/device:', error);
res.status(500).json({ error: 'Failed to load audio device config' });
}
});
/**
* POST /admin/audio/device
* Sélectionne et configure une carte son
* Body: { inputDeviceId?, outputDeviceId?, sampleRate?, bufferSize? }
*/
router.post('/audio/device', (req, res) => {
try {
const { inputDeviceId, outputDeviceId, sampleRate, bufferSize } = req.body;
const config = loadConfig();
// Initialiser la section device si elle n'existe pas
if (!config.audio.device) {
config.audio.device = {};
}
// Mettre à jour les paramètres fournis
if (inputDeviceId !== undefined) config.audio.device.inputDeviceId = inputDeviceId;
if (outputDeviceId !== undefined) config.audio.device.outputDeviceId = outputDeviceId;
if (sampleRate !== undefined) {
config.audio.device.sampleRate = sampleRate;
config.audio.sampleRate = sampleRate; // Sync avec config globale
}
if (bufferSize !== undefined) config.audio.device.bufferSize = bufferSize;
saveConfig(config);
addLog('info', 'Audio device configured', { inputDeviceId, outputDeviceId, sampleRate, bufferSize });
// TODO Phase 2.5 : Émettre événement pour reload du bridge audio
res.json({
message: 'Audio device configured',
device: config.audio.device
});
} catch (error) {
console.error('Erreur POST /admin/audio/device:', error);
res.status(500).json({ error: 'Failed to configure audio device' });
}
});
export default router; export default router;
+42 -9
View File
@@ -41,15 +41,48 @@ export class CoreAudioBackend extends EventEmitter {
*/ */
static getDevices() { static getDevices() {
try { try {
const devices = portAudio.getDevices(); // WORKAROUND: naudiodon a un bug connu qui cause un segfault
return devices.map((device, index) => ({ // On retourne des devices fictifs pour le développement
id: index, // TODO: Remplacer par un backend plus stable (node-portaudio ou JACK)
name: device.name, console.warn('⚠️ CoreAudio.getDevices(): utilisation de devices fictifs (naudiodon instable)');
maxInputChannels: device.maxInputChannels,
maxOutputChannels: device.maxOutputChannels, return [
defaultSampleRate: device.defaultSampleRate, {
hostAPIName: device.hostAPIName id: 0,
})); name: 'MacBook Pro Microphone',
maxInputChannels: 1,
maxOutputChannels: 0,
defaultSampleRate: 48000,
hostAPIName: 'Core Audio'
},
{
id: 1,
name: 'MacBook Pro Speakers',
maxInputChannels: 0,
maxOutputChannels: 2,
defaultSampleRate: 48000,
hostAPIName: 'Core Audio'
},
{
id: 2,
name: 'External Audio Interface',
maxInputChannels: 8,
maxOutputChannels: 8,
defaultSampleRate: 48000,
hostAPIName: 'Core Audio'
}
];
// Code original (commenté à cause du segfault)
// const devices = portAudio.getDevices();
// return devices.map((device, index) => ({
// id: index,
// name: device.name,
// maxInputChannels: device.maxInputChannels,
// maxOutputChannels: device.maxOutputChannels,
// defaultSampleRate: device.defaultSampleRate,
// hostAPIName: device.hostAPIName
// }));
} catch (error) { } catch (error) {
console.error('Erreur énumération devices CoreAudio:', error); console.error('Erreur énumération devices CoreAudio:', error);
return []; return [];
+17 -25
View File
@@ -1,50 +1,42 @@
# PTT Live - Configuration
# Format simplifié : nom du groupe + canaux (les IDs sont générés automatiquement)
# Configuration audio globale
audio: audio:
sampleRate: 48000 sampleRate: 48000
frameSize: 20 # ms frameSize: 20
defaultBitrate: 96 # kbps defaultBitrate: 96
jitterBufferMs: 40 jitterBufferMs: 40
device:
# Configuration des groupes inputDeviceId: 0
outputDeviceId: 2
sampleRate: 48000
groups: groups:
- name: "Production" - name: Production
audioBitrate: 96 audioBitrate: 96
channels: channels:
- name: "Principal" - name: Principal
audioInput: 0 audioInput: 0
audioOutput: 0 audioOutput: 0
- name: "Backup" - name: Backup
audioInput: 1 audioInput: 1
audioOutput: 1 audioOutput: 1
- name: Technique
- name: "Technique"
channels: channels:
- name: "Général" - name: Général
audioInput: 2 audioInput: 2
audioOutput: 2 audioOutput: 2
- name: Sonorisation
- name: "Sonorisation"
audioBitrate: 128 audioBitrate: 128
channels: channels:
- name: "Principal" - name: Principal
audioInput: 3 audioInput: 3
audioOutput: 3 audioOutput: 3
- name: "Retours" - name: Retours
audioInput: 4 audioInput: 4
audioOutput: 4 audioOutput: 4
# Configuration serveur
server: server:
host: "0.0.0.0" host: 0.0.0.0
port: 3000 port: 3000
livekit: livekit:
url: "ws://localhost:7880" url: ws://localhost:7880
# Logging
logging: logging:
level: "debug" level: debug
logLatency: true logLatency: true
logAudioStats: true logAudioStats: true