Skip to content

Commit 5920784

Browse files
committed
Wait for app capture sink asynchronously
This avoids calling iterate from within the callbacks (which are called from iterate themselves) and infinite loops in case the capture sink fails
1 parent 45121a9 commit 5920784

File tree

1 file changed

+53
-53
lines changed

1 file changed

+53
-53
lines changed

src/pipewire-audio-capture-app.c

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,52 @@ static void link_node_to_sink(struct obs_pw_audio_capture_app *pwac, struct targ
388388
/** The app capture sink is created when there
389389
* is info about the system's default sink.
390390
* See the on_metadata and on_default_sink callbacks */
391+
static void destroy_sink_links(struct obs_pw_audio_capture_app *pwac)
392+
{
393+
obs_pw_audio_proxy_list_clear(&pwac->sink.links);
394+
}
395+
396+
static void connect_targets(struct obs_pw_audio_capture_app *pwac)
397+
{
398+
if (!pwac->sink.proxy) {
399+
return;
400+
}
401+
402+
destroy_sink_links(pwac);
403+
404+
if (pwac->selections.num == 0) {
405+
return;
406+
}
407+
408+
struct obs_pw_audio_proxy_list_iter iter;
409+
obs_pw_audio_proxy_list_iter_init(&iter, &pwac->nodes);
410+
411+
struct target_node *node;
412+
while (obs_pw_audio_proxy_list_iter_next(&iter, (void **)&node)) {
413+
if (node_is_targeted(pwac, node)) {
414+
link_node_to_sink(pwac, node);
415+
}
416+
}
417+
}
418+
419+
static void finalize_capture_sink(struct obs_pw_audio_capture_app *pwac)
420+
{
421+
if (!pwac->sink.proxy || pwac->sink.id == SPA_ID_INVALID || pwac->sink.serial == SPA_ID_INVALID ||
422+
pwac->sink.ports.num != pwac->sink.channels) {
423+
return;
424+
}
425+
426+
blog(LOG_DEBUG, "[pipewire-audio] App capture sink ready");
427+
428+
connect_targets(pwac);
429+
430+
pwac->sink.autoconnect_targets = true;
431+
432+
if (obs_pw_audio_stream_connect(&pwac->pw.audio, pwac->sink.id, pwac->sink.serial, pwac->sink.channels) < 0) {
433+
blog(LOG_WARNING, "[pipewire-audio] Error connecting stream %p to app capture sink %u",
434+
pwac->pw.audio.stream, pwac->sink.id);
435+
}
436+
}
391437

392438
static void on_sink_proxy_bound_cb(void *data, uint32_t global_id)
393439
{
@@ -444,40 +490,16 @@ static const struct pw_proxy_events sink_proxy_events = {
444490

445491
static void register_capture_sink_port(struct obs_pw_audio_capture_app *pwac, uint32_t global_id, const char *channel)
446492
{
493+
blog(LOG_DEBUG, "[pipewire-audio] Registering app capture sink port %u", global_id);
494+
447495
struct capture_sink_port *port = da_push_back_new(pwac->sink.ports);
448496
port->channel = bstrdup(channel);
449497
port->id = global_id;
450-
}
451498

452-
static void destroy_sink_links(struct obs_pw_audio_capture_app *pwac)
453-
{
454-
obs_pw_audio_proxy_list_clear(&pwac->sink.links);
499+
finalize_capture_sink(pwac);
455500
}
456501

457-
static void connect_targets(struct obs_pw_audio_capture_app *pwac)
458-
{
459-
if (!pwac->sink.proxy) {
460-
return;
461-
}
462-
463-
destroy_sink_links(pwac);
464-
465-
if (pwac->selections.num == 0) {
466-
return;
467-
}
468-
469-
struct obs_pw_audio_proxy_list_iter iter;
470-
obs_pw_audio_proxy_list_iter_init(&iter, &pwac->nodes);
471-
472-
struct target_node *node;
473-
while (obs_pw_audio_proxy_list_iter_next(&iter, (void **)&node)) {
474-
if (node_is_targeted(pwac, node)) {
475-
link_node_to_sink(pwac, node);
476-
}
477-
}
478-
}
479-
480-
static bool make_capture_sink(struct obs_pw_audio_capture_app *pwac, uint32_t channels, const char *position)
502+
static void make_capture_sink(struct obs_pw_audio_capture_app *pwac, uint32_t channels, const char *position)
481503
{
482504
/* HACK: In order to hide the app capture sink from PulseAudio applications, for example to prevent them from intentionally outputting
483505
* to it, or to not fill up desktop audio control menus with sinks, the media class is set to Audio/Sink/Internal.
@@ -502,7 +524,7 @@ static bool make_capture_sink(struct obs_pw_audio_capture_app *pwac, uint32_t ch
502524

503525
if (!pwac->sink.proxy) {
504526
blog(LOG_WARNING, "[pipewire-audio] Failed to create app capture sink");
505-
return false;
527+
return;
506528
}
507529

508530
pwac->sink.channels = channels;
@@ -513,30 +535,7 @@ static bool make_capture_sink(struct obs_pw_audio_capture_app *pwac, uint32_t ch
513535

514536
pw_proxy_add_listener(pwac->sink.proxy, &pwac->sink.proxy_listener, &sink_proxy_events, pwac);
515537

516-
while (pwac->sink.id == SPA_ID_INVALID || pwac->sink.serial == SPA_ID_INVALID ||
517-
pwac->sink.ports.num != channels) {
518-
/* Iterate until the sink is bound and all the ports are registered */
519-
pw_loop_iterate(pw_thread_loop_get_loop(pwac->pw.thread_loop), -1);
520-
}
521-
522-
if (pwac->sink.serial == 0) {
523-
pw_proxy_destroy(pwac->sink.proxy);
524-
return false;
525-
}
526-
527-
blog(LOG_INFO, "[pipewire-audio] Created app capture sink %u with %u channels and position %s", pwac->sink.id,
528-
channels, position);
529-
530-
connect_targets(pwac);
531-
532-
pwac->sink.autoconnect_targets = true;
533-
534-
if (obs_pw_audio_stream_connect(&pwac->pw.audio, pwac->sink.id, pwac->sink.serial, channels) < 0) {
535-
blog(LOG_WARNING, "[pipewire-audio] Error connecting stream %p to app capture sink %u",
536-
pwac->pw.audio.stream, pwac->sink.id);
537-
}
538-
539-
return true;
538+
blog(LOG_DEBUG, "[pipewire-audio] Created app capture sink");
540539
}
541540

542541
static void destroy_capture_sink(struct obs_pw_audio_capture_app *pwac)
@@ -692,6 +691,7 @@ static void on_global_cb(void *data, uint32_t id, uint32_t permissions, const ch
692691
pwac->sink.serial = 0;
693692
} else {
694693
pwac->sink.serial = strtoul(ser, NULL, 10);
694+
finalize_capture_sink(pwac);
695695
}
696696
}
697697

0 commit comments

Comments
 (0)