diff options
author | xegineering <me@xegineering.eu> | 2024-11-17 12:51:15 +0100 |
---|---|---|
committer | xegineering <me@xegineering.eu> | 2024-12-08 18:22:10 +0100 |
commit | 06c4f8b0120f5598f9d179b8c0fea33df35659a8 (patch) | |
tree | cd29e3526c5394cd5daeb8da889c9b56ad2873f3 /soundbox/pipewire-binding.c | |
parent | 4513eb614707d129824e60270bd45cdee9f04d06 (diff) | |
download | soundbox-go-06c4f8b0120f5598f9d179b8c0fea33df35659a8.tar soundbox-go-06c4f8b0120f5598f9d179b8c0fea33df35659a8.tar.zst soundbox-go-06c4f8b0120f5598f9d179b8c0fea33df35659a8.zip |
pipewire: Add experimental PipeWire support
This implements a PipeWire capture device which can be used as an input
source instead of the already available URL input.
Known issues with the current PipeWire support are:
- user has to connect the monitor of the default audio sink to the
capture device manually
- correct shutdown has to be tested
- multiple instances do not work
- medium code quality requires refactoring
Since this is nevertheless usable and possible unknown bugs should be
figured out in practise soon this implementation is already added.
Bugfixes and refactoring might follow.
Diffstat (limited to 'soundbox/pipewire-binding.c')
-rw-r--r-- | soundbox/pipewire-binding.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/soundbox/pipewire-binding.c b/soundbox/pipewire-binding.c new file mode 100644 index 0000000..bb10e31 --- /dev/null +++ b/soundbox/pipewire-binding.c @@ -0,0 +1,105 @@ +#include <pipewire/pipewire.h> +#include <spa/param/audio/format-utils.h> + +#include "pipewire-binding.h" + + +#define SAMPLING_RATE 48000 +#define CHANNELS 2 +#define VOLUME 0.7 +#define NODE_NAME "soundbox" +#define STRIDE sizeof(int16_t) * CHANNELS + + +static void on_process(void *userdata) +{ + struct pw_stream *stream = *(struct pw_stream **)userdata; + struct pw_buffer *pw_buf; + struct spa_buffer *spa_buf; + int n_frames; + int16_t *src; + + if ((pw_buf = pw_stream_dequeue_buffer(stream)) == NULL) { + return; + } + + spa_buf = pw_buf->buffer; + if ((src = spa_buf->datas[0].data) == NULL) { + return; + } + + n_frames = spa_buf->datas[0].chunk->size / STRIDE; + if (pw_buf->requested) { + n_frames = SPA_MIN(pw_buf->requested, n_frames); + } + + size_t len = spa_buf->datas[0].chunk->size; + + goHandleData(src, len); + + spa_buf->datas[0].chunk->offset = 0; + spa_buf->datas[0].chunk->stride = STRIDE; + spa_buf->datas[0].chunk->size = n_frames * STRIDE; + + pw_stream_queue_buffer(stream, pw_buf); +} + + +static const struct pw_stream_events stream_events = { + PW_VERSION_STREAM_EVENTS, + .process = on_process, +}; + + +void pw_stdout(void) +{ + pw_init(NULL, NULL); + + struct pw_main_loop *loop = pw_main_loop_new(NULL); + + struct pw_stream *stream = NULL; + stream = pw_stream_new_simple( + pw_main_loop_get_loop(loop), + NODE_NAME, + pw_properties_new( + PW_KEY_MEDIA_TYPE, "Audio", + PW_KEY_CONFIG_NAME, "client-rt.conf", + PW_KEY_MEDIA_CATEGORY, "Capture", + PW_KEY_MEDIA_ROLE, "Music", + NULL + ), + &stream_events, + &stream + ); + + uint8_t buffer[1024]; + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); + const struct spa_pod *params[] = { + spa_format_audio_raw_build( + &b, + SPA_PARAM_EnumFormat, + &SPA_AUDIO_INFO_RAW_INIT( + .format = SPA_AUDIO_FORMAT_S16, + .channels = CHANNELS, + .rate = SAMPLING_RATE + ) + ) + }; + + pw_stream_connect( + stream, + PW_DIRECTION_INPUT, + PW_ID_ANY, + PW_STREAM_FLAG_AUTOCONNECT | + PW_STREAM_FLAG_MAP_BUFFERS | + PW_STREAM_FLAG_RT_PROCESS, + params, + sizeof(params) / sizeof(params[0]) + ); + + pw_main_loop_run(loop); + + pw_stream_destroy(stream); + pw_main_loop_destroy(loop); + pw_deinit(); +} |