format pipewire example

This commit is contained in:
Emile Clark-Boman 2025-09-03 14:52:45 +10:00
parent eabd640e2d
commit 1fa7625679

View file

@ -1,114 +1,108 @@
#include <math.h> #include <math.h>
#include <spa/param/audio/format-utils.h> #include <spa/param/audio/format-utils.h>
#include <pipewire/pipewire.h> #include <pipewire/pipewire.h>
#define M_PI_M2 ( M_PI + M_PI ) #define M_PI_M2 (M_PI + M_PI)
#define DEFAULT_RATE 44100 #define DEFAULT_RATE 44100
#define DEFAULT_CHANNELS 2 #define DEFAULT_CHANNELS 2
#define DEFAULT_VOLUME 0.7 #define DEFAULT_VOLUME 0.7
#define PWSTREAM_NAME "Dorne"
struct data { struct data {
struct pw_main_loop *loop; struct pw_main_loop *loop;
struct pw_stream *stream; struct pw_stream *stream;
double accumulator; double accumulator;
}; };
/* [on_process] */ /* [on_process] */
static void on_process(void *userdata) static void on_process(void *userdata) {
{ struct data *data = userdata;
struct data *data = userdata; struct pw_buffer *b;
struct pw_buffer *b; struct spa_buffer *buf;
struct spa_buffer *buf; int i, c, n_frames, stride;
int i, c, n_frames, stride; int16_t *dst, val;
int16_t *dst, val;
if ((b = pw_stream_dequeue_buffer(data->stream)) == NULL) {
if ((b = pw_stream_dequeue_buffer(data->stream)) == NULL) { pw_log_warn("out of buffers: %m");
pw_log_warn("out of buffers: %m"); return;
return; }
}
buf = b->buffer;
buf = b->buffer; if ((dst = buf->datas[0].data) == NULL)
if ((dst = buf->datas[0].data) == NULL) return;
return;
stride = sizeof(int16_t) * DEFAULT_CHANNELS;
stride = sizeof(int16_t) * DEFAULT_CHANNELS; n_frames = buf->datas[0].maxsize / stride;
n_frames = buf->datas[0].maxsize / stride; if (b->requested)
if (b->requested) n_frames = SPA_MIN(b->requested, n_frames);
n_frames = SPA_MIN(b->requested, n_frames);
for (i = 0; i < n_frames; i++) {
for (i = 0; i < n_frames; i++) { data->accumulator += M_PI_M2 * 440 / DEFAULT_RATE;
data->accumulator += M_PI_M2 * 440 / DEFAULT_RATE; if (data->accumulator >= M_PI_M2)
if (data->accumulator >= M_PI_M2) data->accumulator -= M_PI_M2;
data->accumulator -= M_PI_M2;
/* sin() gives a value between -1.0 and 1.0, we first apply
/* sin() gives a value between -1.0 and 1.0, we first apply * the volume and then scale with 32767.0 to get a 16 bits value
* the volume and then scale with 32767.0 to get a 16 bits value * between [-32767 32767].
* between [-32767 32767]. * Another common method to convert a double to
* Another common method to convert a double to * 16 bits is to multiple by 32768.0 and then clamp to
* 16 bits is to multiple by 32768.0 and then clamp to * [-32768 32767] to get the full 16 bits range. */
* [-32768 32767] to get the full 16 bits range. */ val = sin(data->accumulator) * DEFAULT_VOLUME * 32767.0;
val = sin(data->accumulator) * DEFAULT_VOLUME * 32767.0; for (c = 0; c < DEFAULT_CHANNELS; c++)
for (c = 0; c < DEFAULT_CHANNELS; c++) *dst++ = val;
*dst++ = val; }
}
buf->datas[0].chunk->offset = 0;
buf->datas[0].chunk->offset = 0; buf->datas[0].chunk->stride = stride;
buf->datas[0].chunk->stride = stride; buf->datas[0].chunk->size = n_frames * stride;
buf->datas[0].chunk->size = n_frames * stride;
pw_stream_queue_buffer(data->stream, b);
pw_stream_queue_buffer(data->stream, b);
} }
/* [on_process] */ /* [on_process] */
static const struct pw_stream_events stream_events = { static const struct pw_stream_events stream_events = {
PW_VERSION_STREAM_EVENTS, PW_VERSION_STREAM_EVENTS,
.process = on_process, .process = on_process,
}; };
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{ struct data data = {
struct data data = { 0, }; 0,
const struct spa_pod *params[1]; };
uint8_t buffer[1024]; const struct spa_pod *params[1];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); uint8_t buffer[1024];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
pw_init(&argc, &argv);
pw_init(&argc, &argv);
data.loop = pw_main_loop_new(NULL);
data.loop = pw_main_loop_new(NULL);
data.stream = pw_stream_new_simple(
pw_main_loop_get_loop(data.loop), data.stream = pw_stream_new_simple(
"audio-src", pw_main_loop_get_loop(data.loop), PWSTREAM_NAME,
pw_properties_new( pw_properties_new(PW_KEY_MEDIA_TYPE, "Audio", PW_KEY_MEDIA_CATEGORY,
PW_KEY_MEDIA_TYPE, "Audio", "Playback", PW_KEY_MEDIA_ROLE, "Music", NULL),
PW_KEY_MEDIA_CATEGORY, "Playback", &stream_events, &data);
PW_KEY_MEDIA_ROLE, "Music",
NULL), params[0] = spa_format_audio_raw_build(
&stream_events, &b, SPA_PARAM_EnumFormat,
&data); &SPA_AUDIO_INFO_RAW_INIT(.format = SPA_AUDIO_FORMAT_S16,
.channels = DEFAULT_CHANNELS,
params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, .rate = DEFAULT_RATE));
&SPA_AUDIO_INFO_RAW_INIT(
.format = SPA_AUDIO_FORMAT_S16, pw_stream_connect(data.stream, PW_DIRECTION_OUTPUT, PW_ID_ANY,
.channels = DEFAULT_CHANNELS, PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS |
.rate = DEFAULT_RATE )); PW_STREAM_FLAG_RT_PROCESS,
params, 1);
pw_stream_connect(data.stream,
PW_DIRECTION_OUTPUT, pw_main_loop_run(data.loop);
PW_ID_ANY,
PW_STREAM_FLAG_AUTOCONNECT | pw_stream_destroy(data.stream);
PW_STREAM_FLAG_MAP_BUFFERS | pw_main_loop_destroy(data.loop);
PW_STREAM_FLAG_RT_PROCESS,
params, 1); return 0;
pw_main_loop_run(data.loop);
pw_stream_destroy(data.stream);
pw_main_loop_destroy(data.loop);
return 0;
} }
/* [code] */ /* [code] */