From 81e24e3824e60116dea43db346a44fca9cdee6d1 Mon Sep 17 00:00:00 2001 From: liamcottle Date: Mon, 24 Nov 2025 16:38:12 +1300 Subject: [PATCH] add ability to set audio devices before starting a call --- meshchat.py | 37 +++++++++ .../components/telephone/TelephonePage.vue | 75 ++++++++++++++++++- 2 files changed, 109 insertions(+), 3 deletions(-) diff --git a/meshchat.py b/meshchat.py index 34f4db6..11e26f9 100644 --- a/meshchat.py +++ b/meshchat.py @@ -410,6 +410,8 @@ class ReticulumMeshChat: # get path params identity_hash_hex = request.match_info.get("identity_hash", "") timeout_seconds = int(request.query.get("timeout", 15)) + input_device_name = request.query.get("input_device_name", None) + output_device_name = request.query.get("output_device_name", None) # convert hash to bytes identity_hash = bytes.fromhex(identity_hash_hex) @@ -455,6 +457,10 @@ class ReticulumMeshChat: "message": "Call Failed: Could not find path to destination.", }, status=503) + # set audio devices + self.telephone.set_microphone(input_device_name) + self.telephone.set_speaker(output_device_name) + # initiate call AsyncUtils.run_async(asyncio.to_thread(self.telephone.call, destination_identity, None)) @@ -462,6 +468,37 @@ class ReticulumMeshChat: "message": "Calling...", }) + # serve list of available input/output devices + @routes.get("/api/v1/telephone/audio-devices") + async def index(request): + + # get default input device + default_input_device = LXST.Sources.Backend().soundcard.default_microphone() + if default_input_device is not None: + default_input_device = default_input_device.name + + # get default output device + default_output_device = LXST.Sources.Backend().soundcard.default_speaker() + if default_output_device is not None: + default_output_device = default_output_device.name + + # get input devices + input_devices = [] + for input_device in LXST.Sources.Backend().soundcard.all_microphones(): + input_devices.append(input_device.name) + + # get output devices + output_devices = [] + for output_device in LXST.Sources.Backend().soundcard.all_speakers(): + output_devices.append(output_device.name) + + return web.json_response({ + "default_input_device": default_input_device, + "default_output_device": default_output_device, + "input_devices": input_devices, + "output_devices": output_devices, + }) + # fetch com ports @routes.get("/api/v1/comports") async def index(request): diff --git a/src/frontend/components/telephone/TelephonePage.vue b/src/frontend/components/telephone/TelephonePage.vue index dbcd1a5..e9b934e 100644 --- a/src/frontend/components/telephone/TelephonePage.vue +++ b/src/frontend/components/telephone/TelephonePage.vue @@ -85,16 +85,47 @@
Telephone
+
+ + + +
+
+
+
+ + + +
+
+ +
+
+
+
+ + + +
+
+ +
+
+
My Identity Hash
@@ -208,12 +239,19 @@ export default { destinationHash: null, isInitiatingCall: false, + selectedInputDevice: null, + selectedOutputDevice: null, + + inputDevices: [], + outputDevices: [], + }; }, mounted: function() { // update config this.getConfig(); + this.getAudioDevices(); this.getTelephoneStatus(); // update telephone status every second @@ -246,6 +284,18 @@ export default { return; } + // make sure input device provided + if(!this.selectedInputDevice) { + alert("Please select input microphone."); + return; + } + + // make sure output device provided + if(!this.selectedOutputDevice) { + alert("Please select output speakers."); + return; + } + // show loading this.isInitiatingCall = true; @@ -255,6 +305,8 @@ export default { await axios.get(`/api/v1/telephone/call/${destinationHash}`, { params: { timeout: 15, // how long to attempt to initiate call + input_device_name: this.selectedInputDevice, + output_device_name: this.selectedOutputDevice, }, }); @@ -318,6 +370,23 @@ export default { console.error(e); } }, + async getAudioDevices() { + try { + + // fetch audio devices + const response = await axios.get("/api/v1/telephone/audio-devices"); + + // update ui + this.selectedInputDevice = response.data.default_input_device; + this.selectedOutputDevice = response.data.default_output_device; + this.inputDevices = response.data.input_devices; + this.outputDevices = response.data.output_devices; + + } catch(e) { + // do nothing on error + console.error(e); + } + }, async getTelephoneStatus() { try {