Here are some ideas for a simple API
Device Enumeration
First make a new PipeWire simple instance. This will connect behind the scene etc.
struct pws *pws = pws_new();
Then we can enumerate devices. You specify with flags what types of devices you want.
struct pws_endpoint *endpoints[16];
enum pws_endpoint_flags flags = PWS_ENDPOINT_SOURCE | PWS_ENDPOINT_VIDEO | PWS_ENDPOINT_CAMERA;
n = pws_get_endpoints(pws, flags, endpoints, N_ELEMENTS(endpoints));
Now we have an array of endpoints, you should be able to get more info with something like:
const char *value = pws_endpoint_get_property(endpoint, "some.property.name");
We should also have something to enumerate the formats. Formats are always more complicated because they involve ranges and enumerations etc.
Simple Audio Playback
Create a simple audio playback object:
struct pws_audio_playback *play;
struct pws_audio_format *format;
format = pws_audio_format_new("s16le", 44100, 2);
play = pws_audio_playback_new(pws, /* pws instance */
NULL, /* optional target endpoint */
NULL, /* optional extra properties */
format, /* wanted format */
produce_samples, /* callback that produces samples */
user_data); /* user data passed to callback */
The samples are produced with a callback like this:
static int produce_samples(void *user_data, void *data, uint32_t n_frames, struct timespec *time)
{
uint32_t i;
int16_t *d = data;
for (i = 0; i < n_frames; i++)
d[i] = rand();
}
return n_frames;
}
You are supposed to keep track of the format (and channels, rate) to produce data in the function. The time argument tells you when this data will be played against the monotonic clock.
You start/stop playback with:
pws_audio_playback_start(play);
pws_audio_playback_stop(play);
Simple Audio Capture
Create a simple capture object:
struct pws_audio_capture *capture;
struct pws_audio_format *format;
format = pws_audio_format_new("s16le", 44100, 2);
capture = pws_audio_capture_new(pws, /* pws instance */
NULL, /* optional target endpoint */
NULL, /* optional extra properties */
format, /* wanted format */
consume_samples, /* callback that consumes samples */
user_data); /* user data passed to callback */
The samples are consumed with a callback like this:
static int consume_samples(void *user_data, const void *data, uint32_t n_frames, struct timespec *time)
{
uint32_t i;
int16_t *s = data;
for (i = 0; i < n_frames; i++)
printf("got sample %d\n", s[i]);
}
return n_frames;
}
You are supposed to keep track of the format (and channels, rate) to consume data in the function. The time argument tells you when this data was captured against the monotonic clock.
You start/stop capture with:
pws_audio_capture_start(capture);
pws_audio_capture_stop(capture);
Video Capture
Create a simple video capture object:
struct pws_video_capture *capture;
struct pws_video_format *format;
format = pws_video_format_new("I420", 320, 240, 25, 1);
capture = pws_video_capture_new(pws, /* pws instance */
NULL, /* optional target endpoint */
NULL, /* optional extra properties */
format, /* wanted format */
consume_frame, /* callback that consumes frames */
user_data); /* user data passed to callback */
The samples are consumed with a callback like this:
static int consume_frame(void *user_data, const pws_frame *frame, struct timespec *time)
{
/* frames allows you to access the video pixels */
}
It should also be possible to connect the video_capture with the toolkit so that video is streamed into it without callback.
GtkWidget *w = pws_video_capture_get_widget(capture);