57#define MOD_NAME "[PW acap] "
86 struct pw_buffer *b = pw_stream_dequeue_buffer(s->stream.get());
88 pw_log_warn(
"out of buffers: %m");
91 struct spa_buffer *buf = b->buffer;
93 char *src =
static_cast<char *
>(buf->datas[0].data);
97 assert(buf->datas[0].chunk->offset == 0);
100 pw_stream_queue_buffer(s->stream.get(), b);
105 spa_audio_info audio_params;
107 if(!
param ||
id != SPA_PARAM_Format)
110 int res = spa_format_parse(
param, &audio_params.media_type, &audio_params.media_subtype);
112 || audio_params.media_type != SPA_MEDIA_TYPE_audio
113 || audio_params.media_subtype != SPA_MEDIA_SUBTYPE_raw)
118 spa_format_audio_raw_parse(
param, &audio_params.info.raw);
121 spa_debug_type_find_short_name(spa_type_audio_format, audio_params.info.raw.format),
122 audio_params.info.raw.channels,
123 audio_params.info.raw.rate);
131 s->frame.ch_count = audio_params.info.raw.channels;
133 s->frame.sample_rate = audio_params.info.raw.rate;
134 s->frame.max_size = s->frame.ch_count * s->frame.bps * s->frame.sample_rate;
135 s->frame_data.resize(s->frame.max_size);
136 s->frame.data = s->frame_data.data();
138 std::byte buffer[1024];
139 auto pod_builder = SPA_POD_BUILDER_INIT(buffer,
sizeof(buffer));
141 unsigned buffer_size = (s->buf_len_ms * s->frame.sample_rate / 1000) * s->frame.ch_count * s->frame.bps;
145 spa_pod *new_params = (spa_pod *) spa_pod_builder_add_object(&pod_builder,
146 SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
147 SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
148 SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int(
buffer_size, 0, INT32_MAX),
149 SPA_PARAM_BUFFERS_stride, SPA_POD_Int(s->frame.ch_count * s->frame.bps));
156 if (pw_stream_update_params(s->stream.get(),
const_cast<const spa_pod **
>(&new_params), 1) < 0) {
162static void on_state_changed(
void *
state,
enum pw_stream_state old,
enum pw_stream_state new_state,
const char *error)
166 pw_stream_state_as_string(old),
167 pw_stream_state_as_string(new_state));
173 pw_thread_loop_signal(s->pw.pipewire_loop.get(),
false);
178 .version = PW_VERSION_STREAM_EVENTS,
181 .control_info =
nullptr,
182 .io_changed =
nullptr,
184 .add_buffer =
nullptr,
185 .remove_buffer =
nullptr,
188#if PW_MAJOR > 0 || PW_MINOR > 3 || (PW_MINOR == 3 && PW_MICRO > 39)
190 .trigger_done =
nullptr,
206 auto s = std::make_unique<state_pipewire_cap>();
208 std::string_view cfg_sv(cfg);
209 while(!cfg_sv.empty()){
210 auto tok =
tokenize(cfg_sv,
':',
'"');
218 }
else if(
key ==
"target"){
220 }
else if(
key ==
"channels"){
222 }
else if(
key ==
"buffer-len"){
224 }
else if(
key ==
"sample-rate"){
234 auto props = pw_properties_new(
235 PW_KEY_MEDIA_TYPE,
"Audio",
236 PW_KEY_MEDIA_CATEGORY,
"Capture",
237 PW_KEY_MEDIA_ROLE,
"Communication",
238 PW_KEY_APP_NAME,
"UltraGrid",
239 PW_KEY_APP_ICON_NAME,
"ultragrid",
240 PW_KEY_NODE_NAME,
"ug capture",
247 pw_properties_setf(props, PW_KEY_NODE_LATENCY,
"%u/%u", s->quant, s->sample_rate);
249 std::byte buffer[1024];
250 auto pod_builder = SPA_POD_BUILDER_INIT(buffer,
sizeof(buffer));
252 auto audio_info = SPA_AUDIO_INFO_RAW_INIT(
254 .rate = s->sample_rate,
255 .channels = s->ch_count,
258 const spa_pod *
params = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_EnumFormat,
266 s->stream.reset(pw_stream_new(
267 s->pw.pipewire_core.get(),
271 pw_stream_add_listener(
273 &s->stream_listener.get(),
277 int ring_size = s->bps * s->ch_count * (s->sample_rate * s->buf_len_ms * 2 / 1000);
280 pw_stream_connect(s->stream.get(),
283 static_cast<pw_stream_flags
>(
284 PW_STREAM_FLAG_AUTOCONNECT |
285 PW_STREAM_FLAG_MAP_BUFFERS |
286 PW_STREAM_FLAG_RT_PROCESS),
290 pw_thread_loop_wait(s->pw.pipewire_loop.get());
291 const char *error =
nullptr;
292 auto stream_state = pw_stream_get_state(s->stream.get(), &error);
293 if(stream_state == PW_STREAM_STATE_STREAMING){
296 if(stream_state == PW_STREAM_STATE_ERROR){
310 if(!s->frame.data_len){
311 timespec
ts{0, 1000000};
312 nanosleep(&
ts,
nullptr);
322 pw_thread_loop_stop(s->pw.pipewire_loop.get());
330 strcpy((*available_devices)[0].dev,
"");
331 strcpy((*available_devices)[0].
name,
"Default pipewire capture");
int void(** deleter)(void *))
static void audio_cap_pipewire_done(void *state)
static void on_state_changed(void *state, enum pw_stream_state old, enum pw_stream_state new_state, const char *error)
static const pw_stream_events stream_events
static void on_process(void *state)
static void audio_cap_pw_help()
static void on_param_changed(void *state, uint32_t id, const struct spa_pod *param)
static void audio_cap_pipewire_probe(struct device_info **available_devices, int *count, void(**deleter)(void *))
static void * audio_cap_pipewire_init(struct module *parent, const char *cfg)
static const struct audio_capture_info acap_pipewire_info
static struct audio_frame * audio_cap_pipewire_read(void *state)
This file contains definition of some common audio types.
#define AUDIO_CAPTURE_ABI_VERSION
int color_printf(const char *format,...)
void log_msg(int level, const char *format,...)
#define LOG_LEVEL_NOTICE
information that may be interesting
#define LOG_LEVEL_INFO
normal reporting
#define LOG_LEVEL_ERROR
general errors
#define LOG_LEVEL_VERBOSE
static int buffer_size(int sock, int optname, int size)
@ LIBRARY_CLASS_AUDIO_CAPTURE
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
void print_devices(std::string_view media_class)
bool initialize_pw_common(pipewire_state_common &s, int fd)
raii_uniq_handle< pw_stream, pw_stream_destroy > pw_stream_uniq
spa_audio_format get_pw_format_from_bps(unsigned bps)
#define STREAM_TARGET_PROPERTY_KEY
unsigned get_bps_from_pw_format(spa_audio_format fmt)
struct ring_buffer * ring_buffer_init(int size)
int ring_buffer_read(struct ring_buffer *ring, char *out, int max_len)
void ring_buffer_write(struct ring_buffer *ring, const char *in, int len)
std::unique_ptr< ring_buffer, ring_buf_deleter > ring_buffer_uniq
std::string_view tokenize(std::string_view &str, char delim, char quot)
Tokenizer for string_view.
bool parse_num(std::string_view sv, T &res, int base=10)
struct used to comunicate with audio capture/playback device
spa_hook_uniq stream_listener
ring_buffer_uniq ring_buf
std::vector< char > frame_data