fix: detection correcte des cartes son CoreAudio avec nombre de canaux reel
- Parse coreaudio_device_input/output depuis system_profiler (nombre canaux) - Ajoute sampleRate reel par device - Ajoute metadata: manufacturer, transport, isDefault - Filtre devices sans input ni output - Corrige l'API pour exposer les 11 devices au lieu de 2
This commit is contained in:
@@ -81,7 +81,7 @@ define(['./workbox-290dd570'], (function (workbox) { 'use strict';
|
|||||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||||
}, {
|
}, {
|
||||||
"url": "index.html",
|
"url": "index.html",
|
||||||
"revision": "0.8iqdua7o88g"
|
"revision": "0.lemq4lha2l8"
|
||||||
}], {});
|
}], {});
|
||||||
workbox.cleanupOutdatedCaches();
|
workbox.cleanupOutdatedCaches();
|
||||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -301,6 +301,8 @@ export class AudioBridge extends EventEmitter {
|
|||||||
token: this.options.liveKitToken,
|
token: this.options.liveKitToken,
|
||||||
roomName: this.options.roomName,
|
roomName: this.options.roomName,
|
||||||
participantName: 'AudioBridge',
|
participantName: 'AudioBridge',
|
||||||
|
sampleRate: this.options.sampleRate,
|
||||||
|
channels: this.options.channels,
|
||||||
audioBitrate: this.opusEncoder.options.bitrate
|
audioBitrate: this.opusEncoder.options.bitrate
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -61,9 +61,27 @@ class AudioBridgeManager extends EventEmitter {
|
|||||||
// Import dynamique du AudioBridge
|
// Import dynamique du AudioBridge
|
||||||
const { AudioBridge } = await import('./AudioBridge.js');
|
const { AudioBridge } = await import('./AudioBridge.js');
|
||||||
|
|
||||||
|
// Préparer la config avec conversion explicite des valeurs numériques
|
||||||
|
const audioConfig = { ...config.audio };
|
||||||
|
|
||||||
|
// Conversion explicite des paramètres numériques (depuis YAML ils peuvent être strings)
|
||||||
|
if (audioConfig.sampleRate) audioConfig.sampleRate = parseInt(audioConfig.sampleRate, 10);
|
||||||
|
if (audioConfig.channels) audioConfig.channels = parseInt(audioConfig.channels, 10);
|
||||||
|
|
||||||
|
// frameSize en millisecondes → conversion en nombre d'échantillons
|
||||||
|
// Ex: 20ms à 48kHz = 960 échantillons
|
||||||
|
if (audioConfig.frameSize) {
|
||||||
|
const frameSizeMs = parseInt(audioConfig.frameSize, 10);
|
||||||
|
const sampleRate = audioConfig.sampleRate || 48000;
|
||||||
|
audioConfig.frameSize = Math.floor((frameSizeMs * sampleRate) / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioConfig.defaultBitrate) audioConfig.defaultBitrate = parseInt(audioConfig.defaultBitrate, 10);
|
||||||
|
if (audioConfig.customOpusBitrate) audioConfig.customOpusBitrate = parseInt(audioConfig.customOpusBitrate, 10);
|
||||||
|
|
||||||
// Créer l'instance avec la config
|
// Créer l'instance avec la config
|
||||||
this.bridge = new AudioBridge({
|
this.bridge = new AudioBridge({
|
||||||
...config.audio,
|
...audioConfig,
|
||||||
// Options LiveKit
|
// Options LiveKit
|
||||||
liveKitUrl: config.server?.livekit?.url || 'ws://localhost:7880',
|
liveKitUrl: config.server?.livekit?.url || 'ws://localhost:7880',
|
||||||
liveKitToken,
|
liveKitToken,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
* - Reconnexion automatique
|
* - Reconnexion automatique
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Room, RoomEvent, AudioSource, AudioFrame, LocalAudioTrack } from '@livekit/rtc-node';
|
import { Room, RoomEvent, AudioSource, AudioFrame, LocalAudioTrack, TrackSource } from '@livekit/rtc-node';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
export class LiveKitClient extends EventEmitter {
|
export class LiveKitClient extends EventEmitter {
|
||||||
@@ -86,20 +86,35 @@ export class LiveKitClient extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
async _createAudioSource() {
|
async _createAudioSource() {
|
||||||
try {
|
try {
|
||||||
// Création de l'AudioSource
|
// Debug: afficher les valeurs avant conversion
|
||||||
this.audioSource = new AudioSource(
|
const sampleRate = parseInt(this.options.sampleRate, 10);
|
||||||
this.options.sampleRate,
|
const channels = parseInt(this.options.channels, 10);
|
||||||
this.options.channels
|
|
||||||
);
|
console.log('🔍 DEBUG AudioSource:', {
|
||||||
|
sampleRateOriginal: this.options.sampleRate,
|
||||||
|
sampleRateType: typeof this.options.sampleRate,
|
||||||
|
sampleRateConverted: sampleRate,
|
||||||
|
sampleRateConvertedType: typeof sampleRate,
|
||||||
|
channelsOriginal: this.options.channels,
|
||||||
|
channelsType: typeof this.options.channels,
|
||||||
|
channelsConverted: channels,
|
||||||
|
channelsConvertedType: typeof channels
|
||||||
|
});
|
||||||
|
|
||||||
|
// Création de l'AudioSource (conversion en int32 explicite)
|
||||||
|
this.audioSource = new AudioSource(sampleRate, channels);
|
||||||
|
console.log('✓ AudioSource créée:', this.audioSource);
|
||||||
|
|
||||||
// Création du LocalAudioTrack depuis l'AudioSource
|
// Création du LocalAudioTrack depuis l'AudioSource
|
||||||
const localTrack = LocalAudioTrack.createAudioTrack('bridge-audio', this.audioSource);
|
const localTrack = LocalAudioTrack.createAudioTrack('bridge-audio', this.audioSource);
|
||||||
|
console.log('✓ LocalAudioTrack créé:', localTrack);
|
||||||
|
|
||||||
// Publication du track
|
// Publication du track
|
||||||
const options = {
|
const options = {
|
||||||
source: 'microphone' // Simule un microphone pour les clients
|
source: TrackSource.SOURCE_MICROPHONE // Simule un microphone pour les clients
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log('🔍 DEBUG publishTrack options:', options);
|
||||||
this.localAudioTrack = await this.room.localParticipant.publishTrack(
|
this.localAudioTrack = await this.room.localParticipant.publishTrack(
|
||||||
localTrack,
|
localTrack,
|
||||||
options
|
options
|
||||||
@@ -223,13 +238,13 @@ export class LiveKitClient extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Création d'un AudioFrame
|
// Création d'un AudioFrame (conversion en int32 explicite)
|
||||||
const samplesPerChannel = pcmData.length / 2 / this.options.channels;
|
const samplesPerChannel = Math.floor(pcmData.length / 2 / this.options.channels);
|
||||||
|
|
||||||
const frame = new AudioFrame(
|
const frame = new AudioFrame(
|
||||||
pcmData,
|
pcmData,
|
||||||
this.options.sampleRate,
|
parseInt(this.options.sampleRate, 10),
|
||||||
this.options.channels,
|
parseInt(this.options.channels, 10),
|
||||||
samplesPerChannel
|
samplesPerChannel
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -57,22 +57,29 @@ export class CoreAudioBackend extends EventEmitter {
|
|||||||
item._items.forEach(device => {
|
item._items.forEach(device => {
|
||||||
const name = device._name || 'Unknown Device';
|
const name = device._name || 'Unknown Device';
|
||||||
|
|
||||||
// Déterminer type (input/output)
|
// Les clés coreaudio_device_input/output contiennent le nombre de canaux
|
||||||
const isInput = name.toLowerCase().includes('input') ||
|
const inputChannels = parseInt(device.coreaudio_device_input) || 0;
|
||||||
name.toLowerCase().includes('microphone') ||
|
const outputChannels = parseInt(device.coreaudio_device_output) || 0;
|
||||||
name.toLowerCase().includes('mic');
|
const sampleRate = parseInt(device.coreaudio_device_srate) || 48000;
|
||||||
|
|
||||||
const isOutput = name.toLowerCase().includes('output') ||
|
// Ignorer les devices sans input ni output
|
||||||
name.toLowerCase().includes('speaker') ||
|
if (inputChannels === 0 && outputChannels === 0) {
|
||||||
name.toLowerCase().includes('headphone');
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
devices.push({
|
devices.push({
|
||||||
id: id++,
|
id: id++,
|
||||||
name: name,
|
name: name,
|
||||||
maxInputChannels: isInput ? 2 : 0,
|
maxInputChannels: inputChannels,
|
||||||
maxOutputChannels: isOutput ? 2 : 0,
|
maxOutputChannels: outputChannels,
|
||||||
defaultSampleRate: 48000,
|
defaultSampleRate: sampleRate,
|
||||||
hostAPIName: 'Core Audio'
|
hostAPIName: 'Core Audio',
|
||||||
|
manufacturer: device.coreaudio_device_manufacturer || 'Unknown',
|
||||||
|
transport: device.coreaudio_device_transport || 'unknown',
|
||||||
|
isDefault: {
|
||||||
|
input: device.coreaudio_default_audio_input_device === 'spaudio_yes',
|
||||||
|
output: device.coreaudio_default_audio_output_device === 'spaudio_yes'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user