Skip to content

Instantly share code, notes, and snippets.

@dimtpap
Last active December 3, 2022 22:22
Show Gist options
  • Save dimtpap/a9b52906046a091d137236461c471f3a to your computer and use it in GitHub Desktop.
Save dimtpap/a9b52906046a091d137236461c471f3a to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <unistd.h>
#include <pipewire/pipewire.h>
#include <spa/param/audio/format-utils.h>
#define SINKLATENCY "1024/48000"
//Change this according to the sink's quantum to stop the stream
//Assuming a sample rate of 48000
//For a quantum of 1024 that's ~21300us
//2048 is ~42600us
//and so on...
#define WAIT 21300
static void on_stream_process(void *data)
{
struct pw_stream *s = data;
struct pw_buffer *b = pw_stream_dequeue_buffer(s);
usleep(WAIT);
printf("Processed\n");
pw_stream_queue_buffer(s, b);
}
static void on_sink_bound(void *data, uint32_t global_id)
{
enum spa_audio_channel pos[2] = {SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR};
uint8_t buffer[2048];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
const struct spa_pod *params[1];
params[0] = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_FORMAT_mediaType,
SPA_POD_Id(SPA_MEDIA_TYPE_audio), SPA_FORMAT_mediaSubtype,
SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2),
SPA_FORMAT_AUDIO_position,
SPA_POD_Array(sizeof(enum spa_audio_channel), SPA_TYPE_Id, 2, pos),
SPA_FORMAT_AUDIO_format,
SPA_POD_CHOICE_ENUM_Id(4, SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_S16_LE,
SPA_AUDIO_FORMAT_S32_LE, SPA_AUDIO_FORMAT_F32_LE));
pw_stream_connect(data, PW_DIRECTION_INPUT, global_id,
PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_DONT_RECONNECT | PW_STREAM_FLAG_MAP_BUFFERS, params,
1);
}
int main(void)
{
struct pw_thread_loop *loop;
struct pw_context *context;
struct pw_core *core;
pw_init(NULL, NULL);
loop = pw_thread_loop_new("Loop", NULL);
context = pw_context_new(pw_thread_loop_get_loop(loop), NULL, 0);
pw_thread_loop_lock(loop);
pw_thread_loop_start(loop);
core = pw_context_connect(context, NULL, 0);
struct pw_properties *stream_props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Audio", PW_KEY_MEDIA_CATEGORY, "Capture",
PW_KEY_MEDIA_ROLE, "Production", PW_KEY_STREAM_CAPTURE_SINK,
"true", PW_KEY_NODE_LATENCY, SINKLATENCY, NULL);
struct spa_hook stream_listener;
spa_zero(stream_listener);
struct pw_stream *stream = pw_stream_new(core, "Stream", stream_props);
pw_stream_add_listener(stream, &stream_listener,
&(const struct pw_stream_events){PW_VERSION_STREAM_EVENTS, .process = on_stream_process},
stream);
struct pw_properties *sink_props = pw_properties_new(PW_KEY_NODE_NAME, "Sink", PW_KEY_FACTORY_NAME,
"support.null-audio-sink", PW_KEY_MEDIA_CLASS, "Audio/Sink",
PW_KEY_NODE_VIRTUAL, "true", "audio.position", "FL,FR",
PW_KEY_AUDIO_CHANNELS, "2", NULL);
struct spa_hook sink_listener;
spa_zero(sink_listener);
struct pw_proxy *sink =
pw_core_create_object(core, "adapter", PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, &sink_props->dict, 0);
pw_proxy_add_listener(sink, &sink_listener,
&(const struct pw_proxy_events){PW_VERSION_PROXY_EVENTS, .bound = on_sink_bound}, stream);
pw_thread_loop_unlock(loop);
for (;;)
;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment