From 409f627cf80b7a00752085b4321e590d8e2c8cfc Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Tue, 14 May 2024 12:19:55 +0200 Subject: [PATCH] portaudio: allow to select sink/source audio device --- platform/posix/btstack_audio_portaudio.c | 84 +++++++++++++++++++----- src/btstack_audio.h | 4 ++ 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/platform/posix/btstack_audio_portaudio.c b/platform/posix/btstack_audio_portaudio.c index 5683f0e64..44d1c6c1e 100644 --- a/platform/posix/btstack_audio_portaudio.c +++ b/platform/posix/btstack_audio_portaudio.c @@ -64,6 +64,9 @@ static int num_channels_source; static int num_bytes_per_sample_sink; static int num_bytes_per_sample_source; +static const char * sink_device_name; +static const char * source_device_name = "4-chan"; + // portaudio static int portaudio_initialized; @@ -227,24 +230,42 @@ static int btstack_audio_portaudio_sink_init( portaudio_initialized = 1; } - /* -- setup output -- */ - PaStreamParameters theOutputParameters; - theOutputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ - theOutputParameters.channelCount = channels; - theOutputParameters.sampleFormat = PA_SAMPLE_TYPE; - theOutputParameters.suggestedLatency = Pa_GetDeviceInfo( theOutputParameters.device )->defaultHighOutputLatency; - theOutputParameters.hostApiSpecificStreamInfo = NULL; + /* -- find output device by name if requested -- */ + PaDeviceIndex device_index = -1; + const PaDeviceInfo *output_device_info; + if (sink_device_name != NULL){ + int num_devices = Pa_GetDeviceCount(); + for (int i = 0; i < num_devices; i++) { + output_device_info = Pa_GetDeviceInfo(i); + // Match device by prefix + if (strncmp(output_device_info->name, sink_device_name, strlen(sink_device_name)) == 0) { + device_index = i; + break; + } + } + } - const PaDeviceInfo *outputDeviceInfo; - outputDeviceInfo = Pa_GetDeviceInfo( theOutputParameters.device ); - log_info("PortAudio: sink device: %s", outputDeviceInfo->name); - UNUSED(outputDeviceInfo); + /* -- use default device otherwise -- */ + if (device_index < 0){ + device_index = Pa_GetDefaultOutputDevice(); + output_device_info = Pa_GetDeviceInfo(device_index ); + } + /* -- setup output -- */ + PaStreamParameters output_parameters; + output_parameters.device = device_index; + output_parameters.channelCount = channels; + output_parameters.sampleFormat = PA_SAMPLE_TYPE; + output_parameters.suggestedLatency = output_device_info->defaultHighOutputLatency; + output_parameters.hostApiSpecificStreamInfo = NULL; + + log_info("PortAudio: sink device: %s", output_device_info->name); + UNUSED(output_device_info); /* -- setup stream -- */ err = Pa_OpenStream( &stream_sink, NULL, - &theOutputParameters, + &output_parameters, samplerate, NUM_FRAMES_PER_PA_BUFFER, paClipOff, /* we won't output out of range samples so don't bother clipping them */ @@ -300,18 +321,37 @@ static int btstack_audio_portaudio_source_init( portaudio_initialized = 1; } + /* -- find input device by name if requested -- */ + PaDeviceIndex device_index = -1; + const PaDeviceInfo *input_device_info; + if (source_device_name != NULL){ + int num_devices = Pa_GetDeviceCount(); + for (int i = 0; i < num_devices; i++) { + input_device_info = Pa_GetDeviceInfo(i); + // Match device by prefix + if (strncmp(input_device_info->name, source_device_name, strlen(source_device_name)) == 0) { + device_index = i; + break; + } + } + } + + /* -- use default device otherwise -- */ + if (device_index < 0){ + device_index = Pa_GetDefaultInputDevice(); + input_device_info = Pa_GetDeviceInfo(device_index ); + } + /* -- setup input -- */ PaStreamParameters theInputParameters; - theInputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ + theInputParameters.device = device_index; theInputParameters.channelCount = channels; theInputParameters.sampleFormat = PA_SAMPLE_TYPE; - theInputParameters.suggestedLatency = Pa_GetDeviceInfo( theInputParameters.device )->defaultHighInputLatency; + theInputParameters.suggestedLatency = input_device_info->defaultHighInputLatency; theInputParameters.hostApiSpecificStreamInfo = NULL; - const PaDeviceInfo *inputDeviceInfo; - inputDeviceInfo = Pa_GetDeviceInfo( theInputParameters.device ); - log_info("PortAudio: source device: %s", inputDeviceInfo->name); - UNUSED(inputDeviceInfo); + log_info("PortAudio: source device: %s", input_device_info->name); + UNUSED(input_device_info); /* -- setup stream -- */ err = Pa_OpenStream( @@ -512,4 +552,12 @@ const btstack_audio_source_t * btstack_audio_portaudio_source_get_instance(void) return &btstack_audio_portaudio_source; } +void btstack_audio_portaudio_sink_set_device(const char * device_name){ + sink_device_name = device_name; +} + +void btstack_audio_portaudio_source_set_device(const char * device_name){ + source_device_name = device_name; +} + #endif diff --git a/src/btstack_audio.h b/src/btstack_audio.h index 6c669ac2c..e19099837 100644 --- a/src/btstack_audio.h +++ b/src/btstack_audio.h @@ -177,6 +177,10 @@ const btstack_audio_source_t * btstack_audio_embedded_source_get_instance(void); const btstack_audio_sink_t * btstack_audio_esp32_sink_get_instance(void); const btstack_audio_source_t * btstack_audio_esp32_source_get_instance(void); +// platform-specific extension +void btstack_audio_portaudio_sink_set_device(const char * device_name); +void btstack_audio_portaudio_source_set_device(const char * device_name); + /* API_END */ #if defined __cplusplus