Add live caller channel to audio settings
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -436,6 +436,7 @@ class AudioDeviceSettings(BaseModel):
|
|||||||
input_channel: Optional[int] = None
|
input_channel: Optional[int] = None
|
||||||
output_device: Optional[int] = None
|
output_device: Optional[int] = None
|
||||||
caller_channel: Optional[int] = None
|
caller_channel: Optional[int] = None
|
||||||
|
live_caller_channel: Optional[int] = None
|
||||||
music_channel: Optional[int] = None
|
music_channel: Optional[int] = None
|
||||||
sfx_channel: Optional[int] = None
|
sfx_channel: Optional[int] = None
|
||||||
phone_filter: Optional[bool] = None
|
phone_filter: Optional[bool] = None
|
||||||
@@ -471,6 +472,7 @@ async def set_audio_settings(settings: AudioDeviceSettings):
|
|||||||
input_channel=settings.input_channel,
|
input_channel=settings.input_channel,
|
||||||
output_device=settings.output_device,
|
output_device=settings.output_device,
|
||||||
caller_channel=settings.caller_channel,
|
caller_channel=settings.caller_channel,
|
||||||
|
live_caller_channel=settings.live_caller_channel,
|
||||||
music_channel=settings.music_channel,
|
music_channel=settings.music_channel,
|
||||||
sfx_channel=settings.sfx_channel,
|
sfx_channel=settings.sfx_channel,
|
||||||
phone_filter=settings.phone_filter
|
phone_filter=settings.phone_filter
|
||||||
@@ -832,9 +834,8 @@ async def caller_audio_stream(websocket: WebSocket):
|
|||||||
pcm_data = message["bytes"]
|
pcm_data = message["bytes"]
|
||||||
audio_buffer.extend(pcm_data)
|
audio_buffer.extend(pcm_data)
|
||||||
|
|
||||||
# Route to Loopback channel
|
# Route to configured live caller Loopback channel
|
||||||
channel = call_info["channel"]
|
audio_service.route_real_caller_audio(pcm_data, SAMPLE_RATE)
|
||||||
audio_service.route_real_caller_audio(pcm_data, channel, SAMPLE_RATE)
|
|
||||||
|
|
||||||
# Transcribe when we have enough audio
|
# Transcribe when we have enough audio
|
||||||
if len(audio_buffer) >= chunk_samples * 2:
|
if len(audio_buffer) >= chunk_samples * 2:
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class AudioService:
|
|||||||
|
|
||||||
self.output_device: Optional[int] = None # Single output device (multi-channel)
|
self.output_device: Optional[int] = None # Single output device (multi-channel)
|
||||||
self.caller_channel: int = 1 # Channel for caller TTS
|
self.caller_channel: int = 1 # Channel for caller TTS
|
||||||
|
self.live_caller_channel: int = 4 # Channel for live caller audio
|
||||||
self.music_channel: int = 2 # Channel for music
|
self.music_channel: int = 2 # Channel for music
|
||||||
self.sfx_channel: int = 3 # Channel for SFX
|
self.sfx_channel: int = 3 # Channel for SFX
|
||||||
self.phone_filter: bool = False # Phone filter on caller voices
|
self.phone_filter: bool = False # Phone filter on caller voices
|
||||||
@@ -69,10 +70,11 @@ class AudioService:
|
|||||||
self.input_channel = data.get("input_channel", 1)
|
self.input_channel = data.get("input_channel", 1)
|
||||||
self.output_device = data.get("output_device")
|
self.output_device = data.get("output_device")
|
||||||
self.caller_channel = data.get("caller_channel", 1)
|
self.caller_channel = data.get("caller_channel", 1)
|
||||||
|
self.live_caller_channel = data.get("live_caller_channel", 4)
|
||||||
self.music_channel = data.get("music_channel", 2)
|
self.music_channel = data.get("music_channel", 2)
|
||||||
self.sfx_channel = data.get("sfx_channel", 3)
|
self.sfx_channel = data.get("sfx_channel", 3)
|
||||||
self.phone_filter = data.get("phone_filter", False)
|
self.phone_filter = data.get("phone_filter", False)
|
||||||
print(f"Loaded audio settings: output={self.output_device}, channels={self.caller_channel}/{self.music_channel}/{self.sfx_channel}, phone_filter={self.phone_filter}")
|
print(f"Loaded audio settings: output={self.output_device}, channels={self.caller_channel}/{self.live_caller_channel}/{self.music_channel}/{self.sfx_channel}, phone_filter={self.phone_filter}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to load audio settings: {e}")
|
print(f"Failed to load audio settings: {e}")
|
||||||
|
|
||||||
@@ -84,6 +86,7 @@ class AudioService:
|
|||||||
"input_channel": self.input_channel,
|
"input_channel": self.input_channel,
|
||||||
"output_device": self.output_device,
|
"output_device": self.output_device,
|
||||||
"caller_channel": self.caller_channel,
|
"caller_channel": self.caller_channel,
|
||||||
|
"live_caller_channel": self.live_caller_channel,
|
||||||
"music_channel": self.music_channel,
|
"music_channel": self.music_channel,
|
||||||
"sfx_channel": self.sfx_channel,
|
"sfx_channel": self.sfx_channel,
|
||||||
"phone_filter": self.phone_filter,
|
"phone_filter": self.phone_filter,
|
||||||
@@ -114,6 +117,7 @@ class AudioService:
|
|||||||
input_channel: Optional[int] = None,
|
input_channel: Optional[int] = None,
|
||||||
output_device: Optional[int] = None,
|
output_device: Optional[int] = None,
|
||||||
caller_channel: Optional[int] = None,
|
caller_channel: Optional[int] = None,
|
||||||
|
live_caller_channel: Optional[int] = None,
|
||||||
music_channel: Optional[int] = None,
|
music_channel: Optional[int] = None,
|
||||||
sfx_channel: Optional[int] = None,
|
sfx_channel: Optional[int] = None,
|
||||||
phone_filter: Optional[bool] = None
|
phone_filter: Optional[bool] = None
|
||||||
@@ -127,6 +131,8 @@ class AudioService:
|
|||||||
self.output_device = output_device
|
self.output_device = output_device
|
||||||
if caller_channel is not None:
|
if caller_channel is not None:
|
||||||
self.caller_channel = caller_channel
|
self.caller_channel = caller_channel
|
||||||
|
if live_caller_channel is not None:
|
||||||
|
self.live_caller_channel = live_caller_channel
|
||||||
if music_channel is not None:
|
if music_channel is not None:
|
||||||
self.music_channel = music_channel
|
self.music_channel = music_channel
|
||||||
if sfx_channel is not None:
|
if sfx_channel is not None:
|
||||||
@@ -144,6 +150,7 @@ class AudioService:
|
|||||||
"input_channel": self.input_channel,
|
"input_channel": self.input_channel,
|
||||||
"output_device": self.output_device,
|
"output_device": self.output_device,
|
||||||
"caller_channel": self.caller_channel,
|
"caller_channel": self.caller_channel,
|
||||||
|
"live_caller_channel": self.live_caller_channel,
|
||||||
"music_channel": self.music_channel,
|
"music_channel": self.music_channel,
|
||||||
"sfx_channel": self.sfx_channel,
|
"sfx_channel": self.sfx_channel,
|
||||||
"phone_filter": self.phone_filter,
|
"phone_filter": self.phone_filter,
|
||||||
@@ -313,8 +320,8 @@ class AudioService:
|
|||||||
"""Stop any playing caller audio"""
|
"""Stop any playing caller audio"""
|
||||||
self._caller_stop_event.set()
|
self._caller_stop_event.set()
|
||||||
|
|
||||||
def route_real_caller_audio(self, pcm_data: bytes, channel: int, sample_rate: int):
|
def route_real_caller_audio(self, pcm_data: bytes, sample_rate: int):
|
||||||
"""Route real caller PCM audio to a specific Loopback channel"""
|
"""Route real caller PCM audio to the configured live caller Loopback channel"""
|
||||||
import librosa
|
import librosa
|
||||||
|
|
||||||
if self.output_device is None:
|
if self.output_device is None:
|
||||||
@@ -327,7 +334,7 @@ class AudioService:
|
|||||||
device_info = sd.query_devices(self.output_device)
|
device_info = sd.query_devices(self.output_device)
|
||||||
num_channels = device_info['max_output_channels']
|
num_channels = device_info['max_output_channels']
|
||||||
device_sr = int(device_info['default_samplerate'])
|
device_sr = int(device_info['default_samplerate'])
|
||||||
channel_idx = min(channel, num_channels) - 1
|
channel_idx = min(self.live_caller_channel, num_channels) - 1
|
||||||
|
|
||||||
# Resample to device sample rate if needed
|
# Resample to device sample rate if needed
|
||||||
if sample_rate != device_sr:
|
if sample_rate != device_sr:
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="channel-row">
|
<div class="channel-row">
|
||||||
<label>Caller Ch <input type="number" id="caller-channel" value="1" min="1" max="16" class="channel-input"></label>
|
<label>Caller Ch <input type="number" id="caller-channel" value="1" min="1" max="16" class="channel-input"></label>
|
||||||
|
<label>Live Ch <input type="number" id="live-caller-channel" value="4" min="1" max="16" class="channel-input"></label>
|
||||||
<label>Music Ch <input type="number" id="music-channel" value="2" min="1" max="16" class="channel-input"></label>
|
<label>Music Ch <input type="number" id="music-channel" value="2" min="1" max="16" class="channel-input"></label>
|
||||||
<label>SFX Ch <input type="number" id="sfx-channel" value="3" min="1" max="16" class="channel-input"></label>
|
<label>SFX Ch <input type="number" id="sfx-channel" value="3" min="1" max="16" class="channel-input"></label>
|
||||||
</div>
|
</div>
|
||||||
@@ -206,6 +207,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/app.js?v=10"></script>
|
<script src="/js/app.js?v=11"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -223,11 +223,13 @@ async function loadAudioDevices() {
|
|||||||
// Channel settings
|
// Channel settings
|
||||||
const inputCh = document.getElementById('input-channel');
|
const inputCh = document.getElementById('input-channel');
|
||||||
const callerCh = document.getElementById('caller-channel');
|
const callerCh = document.getElementById('caller-channel');
|
||||||
|
const liveCallerCh = document.getElementById('live-caller-channel');
|
||||||
const musicCh = document.getElementById('music-channel');
|
const musicCh = document.getElementById('music-channel');
|
||||||
const sfxCh = document.getElementById('sfx-channel');
|
const sfxCh = document.getElementById('sfx-channel');
|
||||||
|
|
||||||
if (inputCh) inputCh.value = settings.input_channel || 1;
|
if (inputCh) inputCh.value = settings.input_channel || 1;
|
||||||
if (callerCh) callerCh.value = settings.caller_channel || 1;
|
if (callerCh) callerCh.value = settings.caller_channel || 1;
|
||||||
|
if (liveCallerCh) liveCallerCh.value = settings.live_caller_channel || 4;
|
||||||
if (musicCh) musicCh.value = settings.music_channel || 2;
|
if (musicCh) musicCh.value = settings.music_channel || 2;
|
||||||
if (sfxCh) sfxCh.value = settings.sfx_channel || 3;
|
if (sfxCh) sfxCh.value = settings.sfx_channel || 3;
|
||||||
|
|
||||||
@@ -250,6 +252,7 @@ async function saveAudioDevices() {
|
|||||||
const outputDevice = document.getElementById('output-device')?.value;
|
const outputDevice = document.getElementById('output-device')?.value;
|
||||||
const inputChannel = document.getElementById('input-channel')?.value;
|
const inputChannel = document.getElementById('input-channel')?.value;
|
||||||
const callerChannel = document.getElementById('caller-channel')?.value;
|
const callerChannel = document.getElementById('caller-channel')?.value;
|
||||||
|
const liveCallerChannel = document.getElementById('live-caller-channel')?.value;
|
||||||
const musicChannel = document.getElementById('music-channel')?.value;
|
const musicChannel = document.getElementById('music-channel')?.value;
|
||||||
const sfxChannel = document.getElementById('sfx-channel')?.value;
|
const sfxChannel = document.getElementById('sfx-channel')?.value;
|
||||||
const phoneFilterChecked = document.getElementById('phone-filter')?.checked ?? false;
|
const phoneFilterChecked = document.getElementById('phone-filter')?.checked ?? false;
|
||||||
@@ -262,6 +265,7 @@ async function saveAudioDevices() {
|
|||||||
input_channel: inputChannel ? parseInt(inputChannel) : 1,
|
input_channel: inputChannel ? parseInt(inputChannel) : 1,
|
||||||
output_device: outputDevice ? parseInt(outputDevice) : null,
|
output_device: outputDevice ? parseInt(outputDevice) : null,
|
||||||
caller_channel: callerChannel ? parseInt(callerChannel) : 1,
|
caller_channel: callerChannel ? parseInt(callerChannel) : 1,
|
||||||
|
live_caller_channel: liveCallerChannel ? parseInt(liveCallerChannel) : 4,
|
||||||
music_channel: musicChannel ? parseInt(musicChannel) : 2,
|
music_channel: musicChannel ? parseInt(musicChannel) : 2,
|
||||||
sfx_channel: sfxChannel ? parseInt(sfxChannel) : 3,
|
sfx_channel: sfxChannel ? parseInt(sfxChannel) : 3,
|
||||||
phone_filter: phoneFilterChecked
|
phone_filter: phoneFilterChecked
|
||||||
|
|||||||
Reference in New Issue
Block a user