diff --git a/.github/iwyu.imp b/.github/iwyu.imp index 798b970a7..83a17854f 100644 --- a/.github/iwyu.imp +++ b/.github/iwyu.imp @@ -29,6 +29,7 @@ { include: [ '', private, '', public ] }, { include: [ '"gobject/gclosure.h"', private, '', public ] }, { include: [ '"gio/gdbusinterfaceskeleton.h"', private, '', public ] }, + { include: [ '"gio/gdbusobjectmanager.h"', private, '', public ] }, { include: [ '"gio/gdbusobjectmanagerserver.h"', private, '', public ] }, { include: [ '"gio/gdbusobjectskeleton.h"', private, '', public ] }, diff --git a/src/asound/bluealsa-ctl.c b/src/asound/bluealsa-ctl.c index 4a4b827f1..451704013 100644 --- a/src/asound/bluealsa-ctl.c +++ b/src/asound/bluealsa-ctl.c @@ -545,7 +545,7 @@ static void bluealsa_elem_set_name(struct bluealsa_ctl *ctl, struct ctl_elem *el if (name != NULL) { /* multi-device mixer - include device alias in control names */ - const int name_len = strlen(name); + const size_t name_len = strlen(name); /* max name length with reserved space for ALSA suffix */ int len = sizeof(elem->name) - 16 - 1; char no[16] = ""; @@ -556,7 +556,7 @@ static void bluealsa_elem_set_name(struct bluealsa_ctl *ctl, struct ctl_elem *el } /* get the longest possible element label */ - int label_max_len = sizeof(" A2DP") - 1; + size_t label_max_len = sizeof(" A2DP") - 1; if (ctl->show_bt_transport) label_max_len = sizeof(" SCO-HFP-AG") - 1; if (ctl->show_vol_mode) diff --git a/src/asound/bluealsa-pcm.c b/src/asound/bluealsa-pcm.c index 3b38a8404..2f230c5b4 100644 --- a/src/asound/bluealsa-pcm.c +++ b/src/asound/bluealsa-pcm.c @@ -1271,7 +1271,7 @@ static bool bluealsa_select_pcm_codec(struct bluealsa_pcm *pcm, const char *code const char *config_hex; /* split the given string into name and configuration components */ if ((config_hex = strchr(codec, ':')) != NULL) { - name_len = MIN(name_len, config_hex - codec); + name_len = MIN(name_len, (size_t)(config_hex - codec)); config_hex++; size_t config_hex_len; diff --git a/src/bluez.c b/src/bluez.c index 010925e1b..06bf630e6 100644 --- a/src/bluez.c +++ b/src/bluez.c @@ -1310,8 +1310,9 @@ static void bluez_register(void) { size_t i; struct ba_adapter *a; for (i = 0; i < ARRAYSIZE(adapters); i++) - if (adapters[i] && - (a = ba_adapter_new(i)) != NULL) { + if (adapters[i] && ( + (a = ba_adapter_lookup(i)) != NULL || + (a = ba_adapter_new(i)) != NULL)) { for (size_t ii = 0; ii < ARRAYSIZE(uuids); ii++) if (uuids[ii].enabled && !uuids[ii].global && adapters_profiles[i] & uuids[ii].profile) @@ -1406,8 +1407,9 @@ static void bluez_signal_interfaces_added(GDBusConnection *conn, const char *sen g_variant_iter_free(interfaces); struct ba_adapter *a; - if (hci_dev_id != -1 && - (a = ba_adapter_new(hci_dev_id)) != NULL) { + if (hci_dev_id != -1 && ( + (a = ba_adapter_lookup(hci_dev_id)) != NULL || + (a = ba_adapter_new(hci_dev_id)) != NULL)) { bluez_adapter_new(a); } @@ -1620,7 +1622,7 @@ static unsigned int bluez_bus_watch_id = 0; /** * Subscribe to BlueZ signals. */ -void bluez_signals_subscribe(void) { +static void bluez_signals_subscribe(void) { bluez_sig_sub_id_iface_added = g_dbus_connection_signal_subscribe(config.dbus, BLUEZ_SERVICE, DBUS_IFACE_OBJECT_MANAGER, "InterfacesAdded", NULL, NULL, diff --git a/src/shared/dbus-client-pcm.c b/src/shared/dbus-client-pcm.c index 901f94a88..55746a7f0 100644 --- a/src/shared/dbus-client-pcm.c +++ b/src/shared/dbus-client-pcm.c @@ -246,7 +246,7 @@ static dbus_bool_t ba_dbus_message_iter_pcm_codec_get_props_cb(const char *key, dbus_message_iter_recurse(&variant, &iter); dbus_message_iter_get_fixed_array(&iter, &data, &len); - codec->data_len = MIN(len, sizeof(codec->data)); + codec->data_len = MIN((size_t)len, sizeof(codec->data)); memcpy(codec->data, data, codec->data_len); } @@ -725,7 +725,7 @@ static dbus_bool_t dbus_message_iter_get_ba_pcm_props_cb(const char *key, dbus_message_iter_recurse(&variant, &iter); dbus_message_iter_get_fixed_array(&iter, &data, &len); - pcm->codec.data_len = MIN(len, sizeof(pcm->codec.data)); + pcm->codec.data_len = MIN((size_t)len, sizeof(pcm->codec.data)); memcpy(pcm->codec.data, data, pcm->codec.data_len); } diff --git a/test/mock/mock-bluealsa.c b/test/mock/mock-bluealsa.c index 2153a0f45..3242f61aa 100644 --- a/test/mock/mock-bluealsa.c +++ b/test/mock/mock-bluealsa.c @@ -46,11 +46,13 @@ #include "bluealsa-dbus.h" #include "bluez.h" #include "codec-sbc.h" +#include "hci.h" #include "hfp.h" #include "io.h" #include "midi.h" #include "storage.h" #include "shared/a2dp-codecs.h" +#include "shared/bluetooth.h" #include "shared/defs.h" #include "shared/log.h" #include "shared/rt.h" @@ -94,8 +96,6 @@ static const a2dp_faststream_t config_faststream_44100_16000 = { }; #endif -void bluez_signals_subscribe(void); - int ofono_call_volume_update(struct ba_transport *transport) { debug("%s: %p", __func__, transport); (void)transport; @@ -167,156 +167,86 @@ void *a2dp_aptx_hd_dec_thread(struct ba_transport_pcm *t_pcm) { return mock_dec( void *a2dp_faststream_dec_thread(struct ba_transport_pcm *t_pcm) { return mock_dec(t_pcm); } void *sco_dec_thread(struct ba_transport_pcm *t_pcm) { return mock_dec(t_pcm); } -static void *mock_bt_dump_thread(void *userdata) { - - int bt_fd = GPOINTER_TO_INT(userdata); - FILE *f_output = NULL; - uint8_t buffer[1024]; - ssize_t len; - - if (mock_dump_output) - f_output = fopen("bluealsa-mock.dump", "w"); - - debug("IO loop: START: %s", __func__); - while ((len = read(bt_fd, buffer, sizeof(buffer))) > 0) { - fprintf(stderr, "#"); - - if (!mock_dump_output) - continue; - - for (ssize_t i = 0; i < len; i++) - fprintf(f_output, "%02x", buffer[i]); - fprintf(f_output, "\n"); - - } - - debug("IO loop: EXIT: %s", __func__); - if (f_output != NULL) - fclose(f_output); - close(bt_fd); - return NULL; -} - -static int mock_transport_set_a2dp_state_active(struct ba_transport *t) { - ba_transport_set_a2dp_state(t, BLUEZ_A2DP_TRANSPORT_STATE_ACTIVE); - return G_SOURCE_REMOVE; -} - -static int mock_transport_acquire_bt(struct ba_transport *t) { +static struct ba_adapter *ba_adapter = NULL; +static struct ba_device *ba_device_1 = NULL; +static struct ba_device *ba_device_2 = NULL; - int bt_fds[2]; - assert(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, bt_fds) == 0); - - t->bt_fd = bt_fds[0]; - t->mtu_read = 256; - t->mtu_write = 256; - - if (t->profile & BA_TRANSPORT_PROFILE_MASK_SCO) - t->mtu_read = t->mtu_write = 48; - - debug("New transport: %d (MTU: R:%zu W:%zu)", t->bt_fd, t->mtu_read, t->mtu_write); - - g_thread_unref(g_thread_new(NULL, mock_bt_dump_thread, GINT_TO_POINTER(bt_fds[1]))); - - if (t->profile & BA_TRANSPORT_PROFILE_MASK_A2DP) - /* Emulate asynchronous transport activation by BlueZ. */ - g_timeout_add(10, G_SOURCE_FUNC(mock_transport_set_a2dp_state_active), t); - - return bt_fds[0]; +static struct ba_adapter *mock_adapter_new(int dev_id) { + struct ba_adapter *a; + if ((a = ba_adapter_new(dev_id)) == NULL) + return NULL; + /* make dummy test HCI mSBC-ready */ + a->hci.features[2] = LMP_TRSP_SCO; + a->hci.features[3] = LMP_ESCO; + return a; } -static struct ba_device *mock_device_new(const char *btmac) { +static struct ba_device *mock_device_new(struct ba_adapter *a, const char *address) { + struct ba_device *d; bdaddr_t addr; - str2ba(btmac, &addr); - struct ba_adapter *a; - if ((a = ba_adapter_lookup(MOCK_ADAPTER_ID)) == NULL) { - a = ba_adapter_new(MOCK_ADAPTER_ID); - /* make dummy test HCI mSBC-ready */ - a->hci.features[2] = LMP_TRSP_SCO; - a->hci.features[3] = LMP_ESCO; - } + str2ba(address, &addr); + if ((d = ba_device_new(a, &addr)) == NULL) + return NULL; - struct ba_device *d; - if ((d = ba_device_lookup(a, &addr)) == NULL) { - d = ba_device_new(a, &addr); - storage_device_clear(d); - d->battery.charge = 75; - } + storage_device_clear(d); + d->battery.charge = 75; - ba_adapter_unref(a); return d; } -static struct ba_transport *mock_transport_new_a2dp(const char *device_btmac, - uint16_t profile, const char *dbus_path, const struct a2dp_codec *codec, - const void *configuration) { +static struct ba_transport *mock_transport_new_a2dp(struct ba_device *d, + const char *uuid, const struct a2dp_codec *codec, const void *configuration) { usleep(mock_fuzzing_ms * 1000); - struct ba_device *d = mock_device_new(device_btmac); - const char *dbus_owner = g_dbus_connection_get_unique_name(config.dbus); - struct ba_transport *t = ba_transport_new_a2dp(d, profile, dbus_owner, dbus_path, - codec, configuration); - t->acquire = mock_transport_acquire_bt; + char transport_path[128]; + const int index = (strcmp(uuid, BT_UUID_A2DP_SINK) == 0) ? 1 : 2; + sprintf(transport_path, "%s/fd%u", d->bluez_dbus_path, index); - fprintf(stderr, "BLUEALSA_READY=A2DP:%s:%s\n", device_btmac, - a2dp_codecs_codec_id_to_string(ba_transport_get_codec(t))); + g_autoptr(GAsyncQueue) sem = g_async_queue_new(); + assert(mock_bluez_device_media_set_configuration(d->bluez_dbus_path, transport_path, + uuid, codec->codec_id, configuration, codec->capabilities_size, sem) == 0); + mock_sem_wait(sem); - ba_transport_set_a2dp_state(t, BLUEZ_A2DP_TRANSPORT_STATE_PENDING); + char device[18]; + ba2str(&d->addr, device); + fprintf(stderr, "BLUEALSA_READY=A2DP:%s:%s\n", device, + a2dp_codecs_codec_id_to_string(codec->codec_id)); - ba_device_unref(d); + struct ba_transport *t; + assert((t = ba_transport_lookup(d, transport_path)) != NULL); return t; } -static void *mock_transport_rfcomm_thread(void *userdata) { +static int mock_transport_acquire_bt_sco(struct ba_transport *t) { - static const struct { - const char *command; - const char *response; - } responses[] = { - /* accept HFP codec selection */ - { "\r\n+BCS:1\r\n", "AT+BCS=1\r" }, - { "\r\n+BCS:2\r\n", "AT+BCS=2\r" }, - { "\r\n+BCS:3\r\n", "AT+BCS=3\r" }, - }; - - int rfcomm_fd = GPOINTER_TO_INT(userdata); - char buffer[1024]; - ssize_t len; - - while ((len = read(rfcomm_fd, buffer, sizeof(buffer))) > 0) { - hexdump("RFCOMM", buffer, len, true); + int bt_fds[2]; + assert(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, bt_fds) == 0); - for (size_t i = 0; i < ARRAYSIZE(responses); i++) { - if (strncmp(buffer, responses[i].command, len) != 0) - continue; - len = strlen(responses[i].response); - if (write(rfcomm_fd, responses[i].response, len) != len) - warn("Couldn't write RFCOMM response: %s", strerror(errno)); - break; - } + t->bt_fd = bt_fds[0]; + t->mtu_read = 48; + t->mtu_write = 48; - } + debug("New SCO link: %s: %d", batostr_(&t->d->addr), t->bt_fd); + g_thread_unref(mock_bt_dump_thread_new(bt_fds[1])); - close(rfcomm_fd); - return NULL; + return bt_fds[0]; } -static struct ba_transport *mock_transport_new_sco(const char *device_btmac, - uint16_t profile, const char *dbus_path) { +static struct ba_transport *mock_transport_new_sco(struct ba_device *d, + const char *uuid) { usleep(mock_fuzzing_ms * 1000); - struct ba_device *d = mock_device_new(device_btmac); - const char *dbus_owner = g_dbus_connection_get_unique_name(config.dbus); + g_autoptr(GAsyncQueue) sem = g_async_queue_new(); + assert(mock_bluez_device_profile_new_connection(d->bluez_dbus_path, uuid, sem) == 0); + mock_sem_wait(sem); - int fds[2]; - socketpair(AF_UNIX, SOCK_STREAM, 0, fds); - g_thread_unref(g_thread_new(NULL, mock_transport_rfcomm_thread, GINT_TO_POINTER(fds[1]))); + struct ba_transport *t; + assert((t = ba_transport_lookup(d, d->bluez_dbus_path)) != NULL); - struct ba_transport *t = ba_transport_new_sco(d, profile, dbus_owner, dbus_path, fds[0]); t->sco.rfcomm->state = HFP_SLC_CONNECTED; t->sco.rfcomm->ag_codecs.cvsd = true; t->sco.rfcomm->hf_codecs.cvsd = true; @@ -332,26 +262,23 @@ static struct ba_transport *mock_transport_new_sco(const char *device_btmac, t->sco.rfcomm->ag_codecs.lc3_swb = true; t->sco.rfcomm->hf_codecs.lc3_swb = true; #endif - t->acquire = mock_transport_acquire_bt; + t->acquire = mock_transport_acquire_bt_sco; - fprintf(stderr, "BLUEALSA_READY=SCO:%s:%s\n", device_btmac, + char device[18]; + ba2str(&d->addr, device); + fprintf(stderr, "BLUEALSA_READY=SCO:%s:%s\n", device, hfp_codec_id_to_string(ba_transport_get_codec(t))); - ba_device_unref(d); return t; } #if ENABLE_MIDI -static struct ba_transport *mock_transport_new_midi(const char *device_btmac, - uint16_t profile, const char *dbus_path) { +static struct ba_transport *mock_transport_new_midi(const char *path) { usleep(mock_fuzzing_ms * 1000); - struct ba_device *d = mock_device_new(device_btmac); - struct ba_transport *t = ba_transport_new_midi(d, profile, ":0", dbus_path); - - ba_transport_acquire(t); - ba_transport_start(t); + struct ba_device *d = ba_device_lookup(ba_adapter, &ba_adapter->hci.bdaddr); + struct ba_transport *t = ba_transport_lookup(d, path); int fds[2]; socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, fds); @@ -362,7 +289,9 @@ static struct ba_transport *mock_transport_new_midi(const char *device_btmac, midi_transport_start_watch_ble_midi(t); - fprintf(stderr, "BLUEALSA_READY=MIDI:%s\n", device_btmac); + char device[18]; + ba2str(&d->addr, device); + fprintf(stderr, "BLUEALSA_READY=MIDI:%s\n", device); ba_device_unref(d); return t; @@ -371,67 +300,65 @@ static struct ba_transport *mock_transport_new_midi(const char *device_btmac, void mock_bluealsa_run(void) { + if (config.profile.a2dp_source || config.profile.a2dp_sink) + mock_sem_wait(mock_sem_ready); + if (config.profile.hfp_ag) + mock_sem_wait(mock_sem_ready); + if (config.profile.hsp_ag) + mock_sem_wait(mock_sem_ready); + GPtrArray *tt = g_ptr_array_new(); if (config.profile.a2dp_source) { if (a2dp_sbc_source.enabled) - g_ptr_array_add(tt, mock_transport_new_a2dp(MOCK_DEVICE_1, - BA_TRANSPORT_PROFILE_A2DP_SOURCE, MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_1, + g_ptr_array_add(tt, mock_transport_new_a2dp(ba_device_1, BT_UUID_A2DP_SOURCE, &a2dp_sbc_source, &config_sbc_44100_stereo)); #if ENABLE_APTX if (a2dp_aptx_source.enabled) - g_ptr_array_add(tt, mock_transport_new_a2dp(MOCK_DEVICE_2, - BA_TRANSPORT_PROFILE_A2DP_SOURCE, MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_2, + g_ptr_array_add(tt, mock_transport_new_a2dp(ba_device_2, BT_UUID_A2DP_SOURCE, &a2dp_aptx_source, &config_aptx_44100_stereo)); else #endif #if ENABLE_APTX_HD if (a2dp_aptx_hd_source.enabled) - g_ptr_array_add(tt, mock_transport_new_a2dp(MOCK_DEVICE_2, - BA_TRANSPORT_PROFILE_A2DP_SOURCE, MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_2, + g_ptr_array_add(tt, mock_transport_new_a2dp(ba_device_2, BT_UUID_A2DP_SOURCE, &a2dp_aptx_hd_source, &config_aptx_hd_48000_stereo)); else #endif #if ENABLE_FASTSTREAM if (a2dp_faststream_source.enabled) - g_ptr_array_add(tt, mock_transport_new_a2dp(MOCK_DEVICE_2, - BA_TRANSPORT_PROFILE_A2DP_SOURCE, MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_2, + g_ptr_array_add(tt, mock_transport_new_a2dp(ba_device_2, BT_UUID_A2DP_SOURCE, &a2dp_faststream_source, &config_faststream_44100_16000)); else #endif if (a2dp_sbc_source.enabled) - g_ptr_array_add(tt, mock_transport_new_a2dp(MOCK_DEVICE_2, - BA_TRANSPORT_PROFILE_A2DP_SOURCE, MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_2, + g_ptr_array_add(tt, mock_transport_new_a2dp(ba_device_2, BT_UUID_A2DP_SOURCE, &a2dp_sbc_source, &config_sbc_44100_stereo)); } if (config.profile.a2dp_sink) { -#if ENABLE_APTX_HD - if (a2dp_aptx_hd_sink.enabled) - g_ptr_array_add(tt, mock_transport_new_a2dp(MOCK_DEVICE_1, - BA_TRANSPORT_PROFILE_A2DP_SINK, MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_1, - &a2dp_aptx_hd_sink, &config_aptx_hd_48000_stereo)); - else -#endif #if ENABLE_APTX if (a2dp_aptx_sink.enabled) - g_ptr_array_add(tt, mock_transport_new_a2dp(MOCK_DEVICE_1, - BA_TRANSPORT_PROFILE_A2DP_SINK, MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_1, + g_ptr_array_add(tt, mock_transport_new_a2dp(ba_device_1, BT_UUID_A2DP_SINK, &a2dp_aptx_sink, &config_aptx_44100_stereo)); else +#endif +#if ENABLE_APTX_HD + if (a2dp_aptx_hd_sink.enabled) + g_ptr_array_add(tt, mock_transport_new_a2dp(ba_device_1, BT_UUID_A2DP_SINK, + &a2dp_aptx_hd_sink, &config_aptx_hd_48000_stereo)); + else #endif if (a2dp_sbc_sink.enabled) - g_ptr_array_add(tt, mock_transport_new_a2dp(MOCK_DEVICE_1, - BA_TRANSPORT_PROFILE_A2DP_SINK, MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_1, + g_ptr_array_add(tt, mock_transport_new_a2dp(ba_device_1, BT_UUID_A2DP_SINK, &a2dp_sbc_sink, &config_sbc_44100_stereo)); if (a2dp_sbc_sink.enabled) - g_ptr_array_add(tt, mock_transport_new_a2dp(MOCK_DEVICE_2, - BA_TRANSPORT_PROFILE_A2DP_SINK, MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_2, + g_ptr_array_add(tt, mock_transport_new_a2dp(ba_device_2, BT_UUID_A2DP_SINK, &a2dp_sbc_sink, &config_sbc_44100_stereo)); } @@ -439,8 +366,7 @@ void mock_bluealsa_run(void) { if (config.profile.hfp_ag) { struct ba_transport *t; - g_ptr_array_add(tt, t = mock_transport_new_sco(MOCK_DEVICE_1, - BA_TRANSPORT_PROFILE_HFP_AG, MOCK_BLUEZ_SCO_PATH_1)); + g_ptr_array_add(tt, t = mock_transport_new_sco(ba_device_1, BT_UUID_HFP_AG)); /* In case of fuzzing, select available codecs * one by one with some delay in between. */ @@ -459,16 +385,12 @@ void mock_bluealsa_run(void) { } - if (config.profile.hsp_ag) { - g_ptr_array_add(tt, mock_transport_new_sco(MOCK_DEVICE_2, - BA_TRANSPORT_PROFILE_HSP_AG, MOCK_BLUEZ_SCO_PATH_2)); - } + if (config.profile.hsp_ag) + g_ptr_array_add(tt, mock_transport_new_sco(ba_device_2, BT_UUID_HSP_AG)); #if ENABLE_MIDI - if (config.profile.midi) { - g_ptr_array_add(tt, mock_transport_new_midi(MOCK_DEVICE_1, - BA_TRANSPORT_PROFILE_MIDI, MOCK_BLUEZ_MIDI_PATH_1)); - } + if (config.profile.midi) + g_ptr_array_add(tt, mock_transport_new_midi(MOCK_BLUEZ_MIDI_PATH_1)); #endif mock_sem_wait(mock_sem_timeout); @@ -492,10 +414,15 @@ static void mock_ba_dbus_name_acquired(G_GNUC_UNUSED GDBusConnection *conn, /* initialize codec capabilities */ a2dp_codecs_init(); + /* create mock devices attached to the mock adapter */ + ba_adapter = mock_adapter_new(MOCK_ADAPTER_ID); + ba_device_1 = mock_device_new(ba_adapter, MOCK_DEVICE_1); + ba_device_2 = mock_device_new(ba_adapter, MOCK_DEVICE_2); + /* register D-Bus interfaces */ bluealsa_dbus_register(); - /* subscribe for BlueZ signals */ - bluez_signals_subscribe(); + /* setup BlueZ integration */ + bluez_init(); fprintf(stderr, "BLUEALSA_DBUS_SERVICE_NAME=%s\n", name); mock_sem_signal(userdata); @@ -504,6 +431,7 @@ static void mock_ba_dbus_name_acquired(G_GNUC_UNUSED GDBusConnection *conn, static GThread *mock_ba_thread = NULL; static GMainLoop *mock_ba_main_loop = NULL; +static unsigned int mock_ba_owner_id = 0; static void *mock_ba_loop_run(void *userdata) { @@ -511,9 +439,9 @@ static void *mock_ba_loop_run(void *userdata) { mock_ba_main_loop = g_main_loop_new(context, FALSE); g_main_context_push_thread_default(context); - g_assert(g_bus_own_name_on_connection(config.dbus, mock_ba_service_name, - G_BUS_NAME_OWNER_FLAGS_NONE, mock_ba_dbus_name_acquired, NULL, - userdata, NULL) != 0); + g_assert((mock_ba_owner_id = g_bus_own_name_on_connection(config.dbus, + mock_ba_service_name, G_BUS_NAME_OWNER_FLAGS_NONE, + mock_ba_dbus_name_acquired, NULL, userdata, NULL)) != 0); g_main_loop_run(mock_ba_main_loop); @@ -528,7 +456,15 @@ void mock_bluealsa_service_start(void) { } void mock_bluealsa_service_stop(void) { + + g_bus_unown_name(mock_ba_owner_id); + g_main_loop_quit(mock_ba_main_loop); g_main_loop_unref(mock_ba_main_loop); g_thread_join(mock_ba_thread); + + ba_device_unref(ba_device_1); + ba_device_unref(ba_device_2); + ba_adapter_destroy(ba_adapter); + } diff --git a/test/mock/mock-bluez-iface.xml b/test/mock/mock-bluez-iface.xml index cd4038547..94bf898ad 100644 --- a/test/mock/mock-bluez-iface.xml +++ b/test/mock/mock-bluez-iface.xml @@ -23,10 +23,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/mock/mock-bluez.c b/test/mock/mock-bluez.c index 0480f1136..88c9b67b0 100644 --- a/test/mock/mock-bluez.c +++ b/test/mock/mock-bluez.c @@ -10,17 +10,25 @@ #include "mock.h" +#include +#include +#include #include #include +#include +#include #include +#include #include #include #include "ba-config.h" #include "bluez-iface.h" -#include "dbus.h" +#include "shared/a2dp-codecs.h" +#include "shared/bluetooth.h" #include "shared/defs.h" +#include "shared/log.h" #include "mock-bluez-iface.h" @@ -29,6 +37,11 @@ static const char * devices[8] = { NULL }; /* Global BlueZ mock server object manager. */ static GDBusObjectManagerServer *server = NULL; +/* Client manager for registered media applications. */ +static GDBusObjectManager *media_app_client = NULL; +/* Mapping between profile UUID and its proxy object. */ +static GHashTable *profiles = NULL; + int mock_bluez_device_name_mapping_add(const char *mapping) { for (size_t i = 0; i < ARRAYSIZE(devices); i++) if (devices[i] == NULL) { @@ -38,21 +51,90 @@ int mock_bluez_device_name_mapping_add(const char *mapping) { return -1; } -static void mock_bluez_adapter_add(const char *path, const char *address) { +static void mock_bluez_profile_proxy_finish(G_GNUC_UNUSED GObject *source, + GAsyncResult *result, void *userdata) { + MockBluezProfile1 *profile = mock_bluez_profile1_proxy_new_finish(result, NULL); + g_hash_table_insert(profiles, userdata, profile); + mock_sem_signal(mock_sem_ready); +} + +static gboolean mock_bluez_register_profile_handler(MockBluezProfileManager1 *manager, + GDBusMethodInvocation *invocation, const char *path, const char *uuid, + G_GNUC_UNUSED GVariant *options, G_GNUC_UNUSED void *userdata) { + + GDBusConnection *conn = g_dbus_method_invocation_get_connection(invocation); + const char *sender = g_dbus_method_invocation_get_sender(invocation); + mock_bluez_profile1_proxy_new(conn, G_DBUS_PROXY_FLAGS_NONE, sender, path, + NULL, mock_bluez_profile_proxy_finish, g_strdup(uuid)); + + mock_bluez_profile_manager1_complete_register_profile(manager, invocation); + return TRUE; +} + +static void mock_bluez_profile_manager_add(const char *path) { + + g_autoptr(MockBluezProfileManager1) manager = mock_bluez_profile_manager1_skeleton_new(); + g_signal_connect(manager, "handle-register-profile", + G_CALLBACK(mock_bluez_register_profile_handler), NULL); + + g_autoptr(GDBusObjectSkeleton) skeleton = g_dbus_object_skeleton_new(path); + g_dbus_object_skeleton_add_interface(skeleton, G_DBUS_INTERFACE_SKELETON(manager)); + g_dbus_object_manager_server_export(server, skeleton); + +} + +static gboolean mock_bluez_gatt_register_application_handler(MockBluezGattManager1 *gatt, + GDBusMethodInvocation *invocation, G_GNUC_UNUSED const char *root, + G_GNUC_UNUSED GVariant *options, G_GNUC_UNUSED void *userdata) { + mock_bluez_gatt_manager1_complete_register_application(gatt, invocation); + return TRUE; +} + +static void mock_bluez_media_application_client_finish(G_GNUC_UNUSED GObject *source, + GAsyncResult *result, G_GNUC_UNUSED void *userdata) { + media_app_client = mock_object_manager_client_new_finish(result, NULL); + mock_sem_signal(mock_sem_ready); +} + +static gboolean mock_bluez_media_register_application_handler(MockBluezMedia1 *media, + GDBusMethodInvocation *invocation, const char *root, G_GNUC_UNUSED GVariant *options, + G_GNUC_UNUSED void *userdata) { + + GDBusConnection *conn = g_dbus_method_invocation_get_connection(invocation); + const char *sender = g_dbus_method_invocation_get_sender(invocation); + mock_object_manager_client_new(conn, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, + sender, root, NULL, mock_bluez_media_application_client_finish, NULL); + + mock_bluez_media1_complete_register_application(media, invocation); + return TRUE; +} + +static void mock_bluez_adapter_add(const char *adapter_path, const char *address) { g_autoptr(MockBluezAdapter1) adapter = mock_bluez_adapter1_skeleton_new(); mock_bluez_adapter1_set_address(adapter, address); - g_autoptr(GDBusObjectSkeleton) skeleton = g_dbus_object_skeleton_new(path); + g_autoptr(MockBluezGattManager1) gatt = mock_bluez_gatt_manager1_skeleton_new(); + g_signal_connect(gatt, "handle-register-application", + G_CALLBACK(mock_bluez_gatt_register_application_handler), NULL); + + g_autoptr(MockBluezMedia1) media = mock_bluez_media1_skeleton_new(); + g_signal_connect(media, "handle-register-application", + G_CALLBACK(mock_bluez_media_register_application_handler), NULL); + + g_autoptr(GDBusObjectSkeleton) skeleton = g_dbus_object_skeleton_new(adapter_path); g_dbus_object_skeleton_add_interface(skeleton, G_DBUS_INTERFACE_SKELETON(adapter)); + g_dbus_object_skeleton_add_interface(skeleton, G_DBUS_INTERFACE_SKELETON(gatt)); + g_dbus_object_skeleton_add_interface(skeleton, G_DBUS_INTERFACE_SKELETON(media)); g_dbus_object_manager_server_export(server, skeleton); } -static void mock_bluez_device_add(const char *path, const char *adapter, const char *address) { +static void mock_bluez_device_add(const char *device_path, const char *adapter_path, + const char *address) { g_autoptr(MockBluezDevice1) device = mock_bluez_device1_skeleton_new(); - mock_bluez_device1_set_adapter(device, adapter); + mock_bluez_device1_set_adapter(device, adapter_path); mock_bluez_device1_set_alias(device, address); mock_bluez_device1_set_icon(device, "audio-card"); @@ -61,52 +143,176 @@ static void mock_bluez_device_add(const char *path, const char *adapter, const c strncmp(devices[i], address, strlen(address)) == 0) mock_bluez_device1_set_alias(device, &devices[i][strlen(address) + 1]); - g_autoptr(GDBusObjectSkeleton) skeleton = g_dbus_object_skeleton_new(path); + g_autoptr(GDBusObjectSkeleton) skeleton = g_dbus_object_skeleton_new(device_path); g_dbus_object_skeleton_add_interface(skeleton, G_DBUS_INTERFACE_SKELETON(device)); g_dbus_object_manager_server_export(server, skeleton); } -static gboolean mock_bluez_media_transport_release_handler(MockBluezMediaTransport1 *transport, +static gboolean mock_bluez_media_transport_acquire_handler(MockBluezMediaTransport1 *transport, GDBusMethodInvocation *invocation, G_GNUC_UNUSED void *userdata) { - mock_bluez_media_transport1_complete_release(transport, invocation); - GVariantBuilder props; - g_variant_builder_init(&props, G_VARIANT_TYPE("a{sv}")); - g_variant_builder_add(&props, "{sv}", "State", g_variant_new_string("idle")); - GDBusConnection *conn = g_dbus_method_invocation_get_connection(invocation); - const char *path = g_dbus_method_invocation_get_object_path(invocation); - const char *iface = g_dbus_method_invocation_get_interface_name(invocation); - g_dbus_connection_emit_properties_changed(conn, path, iface, - g_variant_builder_end(&props), NULL, NULL); + int fds[2]; + socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds); + + g_autoptr(GUnixFDList) fd_list = g_unix_fd_list_new_from_array(&fds[0], 1); + mock_bluez_media_transport1_complete_try_acquire(transport, invocation, + fd_list, g_variant_new_handle(0), 256, 256); + + g_thread_unref(mock_bt_dump_thread_new(fds[1])); + mock_bluez_media_transport1_set_state(transport, "active"); return TRUE; } -static void mock_bluez_media_transport_add(const char *path, const char *device) { +static gboolean mock_bluez_media_transport_release_handler(MockBluezMediaTransport1 *transport, + GDBusMethodInvocation *invocation, G_GNUC_UNUSED void *userdata) { + mock_bluez_media_transport1_complete_release(transport, invocation); + mock_bluez_media_transport1_set_state(transport, "idle"); + return TRUE; +} + +static MockBluezMediaTransport1 * mock_bluez_media_transport_add(const char *transport_path, + const char *device_path) { - g_autoptr(MockBluezMediaTransport1) transport = mock_bluez_media_transport1_skeleton_new(); - mock_bluez_media_transport1_set_device(transport, device); + MockBluezMediaTransport1 *transport = mock_bluez_media_transport1_skeleton_new(); + mock_bluez_media_transport1_set_device(transport, device_path); + mock_bluez_media_transport1_set_state(transport, "idle"); + g_signal_connect(transport, "handle-acquire", + G_CALLBACK(mock_bluez_media_transport_acquire_handler), NULL); + g_signal_connect(transport, "handle-try-acquire", + G_CALLBACK(mock_bluez_media_transport_acquire_handler), NULL); g_signal_connect(transport, "handle-release", G_CALLBACK(mock_bluez_media_transport_release_handler), NULL); - g_autoptr(GDBusObjectSkeleton) skeleton = g_dbus_object_skeleton_new(path); + g_autoptr(GDBusObjectSkeleton) skeleton = g_dbus_object_skeleton_new(transport_path); g_dbus_object_skeleton_add_interface(skeleton, G_DBUS_INTERFACE_SKELETON(transport)); g_dbus_object_manager_server_export(server, skeleton); + return transport; +} + +static void *mock_bluez_rfcomm_thread(void *userdata) { + + static const struct { + const char *command; + const char *response; + } responses[] = { + /* accept HFP codec selection */ + { "\r\n+BCS:1\r\n", "AT+BCS=1\r" }, + { "\r\n+BCS:2\r\n", "AT+BCS=2\r" }, + { "\r\n+BCS:3\r\n", "AT+BCS=3\r" }, + }; + + int rfcomm_fd = GPOINTER_TO_INT(userdata); + char buffer[1024]; + ssize_t len; + + while ((len = read(rfcomm_fd, buffer, sizeof(buffer))) > 0) { + hexdump("RFCOMM", buffer, len, true); + + for (size_t i = 0; i < ARRAYSIZE(responses); i++) { + if (strncmp(buffer, responses[i].command, len) != 0) + continue; + len = strlen(responses[i].response); + if (write(rfcomm_fd, responses[i].response, len) != len) + warn("Couldn't write RFCOMM response: %s", strerror(errno)); + break; + } + + } + + close(rfcomm_fd); + return NULL; +} + +static void mock_bluez_profile_new_connection_finish(GObject *source, + GAsyncResult *result, G_GNUC_UNUSED void *userdata) { + MockBluezProfile1 *profile = MOCK_BLUEZ_PROFILE1(source); + mock_bluez_profile1_call_new_connection_finish(profile, NULL, result, NULL); + mock_sem_signal(userdata); +} + +int mock_bluez_device_profile_new_connection(const char *device_path, + const char *uuid, GAsyncQueue *sem_ready) { + + int fds[2]; + socketpair(AF_UNIX, SOCK_STREAM, 0, fds); + + g_autoptr(GUnixFDList) fd_list = g_unix_fd_list_new_from_array(&fds[0], 1); + mock_bluez_profile1_call_new_connection(g_hash_table_lookup(profiles, uuid), + device_path, g_variant_new_handle(0), g_variant_new("a{sv}", NULL), + fd_list, NULL, mock_bluez_profile_new_connection_finish, sem_ready); + + g_thread_unref(g_thread_new(NULL, mock_bluez_rfcomm_thread, GINT_TO_POINTER(fds[1]))); + + return 0; +} + +static void mock_bluez_media_endpoint_set_configuration_finish(GObject *source, + GAsyncResult *result, G_GNUC_UNUSED void *userdata) { + MockBluezMediaEndpoint1 *endpoint = MOCK_BLUEZ_MEDIA_ENDPOINT1(source); + mock_bluez_media_endpoint1_call_set_configuration_finish(endpoint, result, NULL); + mock_sem_signal(userdata); +} + +int mock_bluez_device_media_set_configuration(const char *device_path, + const char *transport_path, const char *uuid, uint32_t codec_id, + const void *configuration, size_t configuration_size, + GAsyncQueue *sem_ready) { + + const uint8_t codec = codec_id < A2DP_CODEC_VENDOR ? codec_id : A2DP_CODEC_VENDOR; + const uint32_t vendor = codec_id < A2DP_CODEC_VENDOR ? 0 : codec_id; + int rv = -1; + + GList *endpoints = g_dbus_object_manager_get_objects(media_app_client); + for (GList *elem = endpoints; elem != NULL; elem = elem->next) { + MockBluezMediaEndpoint1 *ep = mock_object_get_bluez_media_endpoint1(elem->data); + if (mock_bluez_media_endpoint1_get_device(ep) == NULL && + strcmp(mock_bluez_media_endpoint1_get_uuid(ep), uuid) == 0 && + mock_bluez_media_endpoint1_get_codec(ep) == codec && + mock_bluez_media_endpoint1_get_vendor(ep) == vendor) { + + g_autoptr(MockBluezMediaTransport1) transport; + transport = mock_bluez_media_transport_add(transport_path, device_path); + + g_autoptr(GVariantBuilder) props = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(props, "{sv}", "Device", g_variant_new_object_path( + mock_bluez_media_transport1_get_device(transport))); + g_variant_builder_add(props, "{sv}", "Configuration", g_variant_new_fixed_array( + G_VARIANT_TYPE_BYTE, configuration, configuration_size, sizeof(uint8_t))); + g_variant_builder_add(props, "{sv}", "State", g_variant_new_string( + mock_bluez_media_transport1_get_state(transport))); + + mock_bluez_media_endpoint1_call_set_configuration(ep, transport_path, + g_variant_builder_end(props), NULL, + mock_bluez_media_endpoint_set_configuration_finish, sem_ready); + + /* In case of A2DP Sink profile, activate the transport right away. */ + if (strcmp(uuid, BT_UUID_A2DP_SINK) == 0) + mock_bluez_media_transport1_set_state(transport, "pending"); + + rv = 0; + break; + } + } + + g_list_free_full(endpoints, g_object_unref); + return rv; } static void mock_bluez_dbus_name_acquired(GDBusConnection *conn, G_GNUC_UNUSED const char *name, void *userdata) { server = g_dbus_object_manager_server_new("/"); + profiles = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref); + mock_bluez_profile_manager_add("/org/bluez"); mock_bluez_adapter_add(MOCK_BLUEZ_ADAPTER_PATH, "00:00:11:11:22:22"); + mock_bluez_device_add(MOCK_BLUEZ_DEVICE_PATH_1, MOCK_BLUEZ_ADAPTER_PATH, MOCK_DEVICE_1); - mock_bluez_media_transport_add(MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_1, MOCK_BLUEZ_DEVICE_PATH_1); mock_bluez_device_add(MOCK_BLUEZ_DEVICE_PATH_2, MOCK_BLUEZ_ADAPTER_PATH, MOCK_DEVICE_2); - mock_bluez_media_transport_add(MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_2, MOCK_BLUEZ_DEVICE_PATH_2); g_dbus_object_manager_server_set_connection(server, conn); mock_sem_signal(userdata); @@ -115,6 +321,7 @@ static void mock_bluez_dbus_name_acquired(GDBusConnection *conn, static GThread *mock_bluez_thread = NULL; static GMainLoop *mock_bluez_main_loop = NULL; +static unsigned int mock_bluez_owner_id = 0; static void *mock_bluez_loop_run(void *userdata) { @@ -122,9 +329,9 @@ static void *mock_bluez_loop_run(void *userdata) { mock_bluez_main_loop = g_main_loop_new(context, FALSE); g_main_context_push_thread_default(context); - g_assert(g_bus_own_name_on_connection(config.dbus, BLUEZ_SERVICE, - G_BUS_NAME_OWNER_FLAGS_NONE, mock_bluez_dbus_name_acquired, NULL, - userdata, NULL) != 0); + g_assert((mock_bluez_owner_id = g_bus_own_name_on_connection(config.dbus, + BLUEZ_SERVICE, G_BUS_NAME_OWNER_FLAGS_NONE, + mock_bluez_dbus_name_acquired, NULL, userdata, NULL)) != 0); g_main_loop_run(mock_bluez_main_loop); @@ -139,7 +346,16 @@ void mock_bluez_service_start(void) { } void mock_bluez_service_stop(void) { + + g_bus_unown_name(mock_bluez_owner_id); + g_main_loop_quit(mock_bluez_main_loop); g_main_loop_unref(mock_bluez_main_loop); g_thread_join(mock_bluez_thread); + + g_hash_table_unref(profiles); + if (media_app_client != NULL) + g_object_unref(media_app_client); + g_object_unref(server); + } diff --git a/test/mock/mock.c b/test/mock/mock.c index a4b6bd520..fffd916e3 100644 --- a/test/mock/mock.c +++ b/test/mock/mock.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ #define TEST_BLUEALSA_STORAGE_DIR "/tmp/bluealsa-mock-storage" +GAsyncQueue *mock_sem_ready = NULL; GAsyncQueue *mock_sem_timeout = NULL; char mock_ba_service_name[32] = BLUEALSA_SERVICE; bool mock_dump_output = false; @@ -56,6 +58,40 @@ void mock_sem_wait(GAsyncQueue *sem) { g_async_queue_pop(sem); } +static void *mock_bt_dump_thread(void *userdata) { + + int bt_fd = GPOINTER_TO_INT(userdata); + FILE *f_output = NULL; + uint8_t buffer[1024]; + ssize_t len; + + if (mock_dump_output) + f_output = fopen("bluealsa-mock.dump", "w"); + + debug("IO loop: START: %s", __func__); + while ((len = read(bt_fd, buffer, sizeof(buffer))) > 0) { + fprintf(stderr, "#"); + + if (!mock_dump_output) + continue; + + for (ssize_t i = 0; i < len; i++) + fprintf(f_output, "%02x", buffer[i]); + fprintf(f_output, "\n"); + + } + + debug("IO loop: EXIT: %s", __func__); + if (f_output != NULL) + fclose(f_output); + close(bt_fd); + return NULL; +} + +GThread *mock_bt_dump_thread_new(int fd) { + return g_thread_new(NULL, mock_bt_dump_thread, GINT_TO_POINTER(fd)); +} + static void *mock_main_loop_run(void *userdata) { g_main_loop_run((GMainLoop *)userdata); return NULL; @@ -177,7 +213,7 @@ int main(int argc, char *argv[]) { assert(storage_init(TEST_BLUEALSA_STORAGE_DIR) == 0); atexit(storage_destroy); - GTestDBus *dbus = g_test_dbus_new(G_TEST_DBUS_NONE); + g_autoptr(GTestDBus) dbus = g_test_dbus_new(G_TEST_DBUS_NONE); g_test_dbus_up(dbus); fprintf(stderr, "DBUS_SYSTEM_BUS_ADDRESS=%s\n", g_test_dbus_get_bus_address(dbus)); @@ -191,10 +227,11 @@ int main(int argc, char *argv[]) { struct sigaction sigact = { .sa_handler = SIG_IGN }; sigaction(SIGPIPE, &sigact, NULL); - /* thread synchronization queue (semaphore) */ + /* thread synchronization queues (semaphores) */ + mock_sem_ready = g_async_queue_new(); mock_sem_timeout = g_async_queue_new(); - /* main loop with graceful termination handlers */ + /* Set up main loop with graceful termination handlers. */ g_autoptr(GMainLoop) loop = g_main_loop_new(NULL, FALSE); GThread *loop_th = g_thread_new(NULL, mock_main_loop_run, loop); g_timeout_add(timeout_ms, mock_sem_signal_handler, mock_sem_timeout); @@ -204,11 +241,12 @@ int main(int argc, char *argv[]) { mock_bluez_service_start(); mock_bluealsa_service_start(); - /* run mock until timeout or SIGINT/SIGTERM */ + /* Run mock until timeout or SIGINT/SIGTERM signal. */ mock_bluealsa_run(); - mock_bluealsa_service_stop(); + /* Simulate BlueZ termination while BlueALSA is still running. */ mock_bluez_service_stop(); + mock_bluealsa_service_stop(); g_main_loop_quit(loop); g_thread_join(loop_th); diff --git a/test/mock/mock.h b/test/mock/mock.h index 670829442..95cbeb096 100644 --- a/test/mock/mock.h +++ b/test/mock/mock.h @@ -13,6 +13,8 @@ #endif #include +#include +#include #include @@ -23,12 +25,11 @@ #define MOCK_BLUEZ_ADAPTER_PATH "/org/bluez/hci0" #define MOCK_BLUEZ_DEVICE_PATH_1 MOCK_BLUEZ_ADAPTER_PATH "/dev_12_34_56_78_9A_BC" #define MOCK_BLUEZ_DEVICE_PATH_2 MOCK_BLUEZ_ADAPTER_PATH "/dev_23_45_67_89_AB_CD" -#define MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_1 MOCK_BLUEZ_DEVICE_PATH_1 "/fdX" -#define MOCK_BLUEZ_MEDIA_TRANSPORT_PATH_2 MOCK_BLUEZ_DEVICE_PATH_2 "/fdX" -#define MOCK_BLUEZ_MIDI_PATH_1 MOCK_BLUEZ_DEVICE_PATH_1 "/midi" +#define MOCK_BLUEZ_MIDI_PATH_1 MOCK_BLUEZ_ADAPTER_PATH "/MIDI" #define MOCK_BLUEZ_SCO_PATH_1 MOCK_BLUEZ_DEVICE_PATH_1 "/sco" #define MOCK_BLUEZ_SCO_PATH_2 MOCK_BLUEZ_DEVICE_PATH_2 "/sco" +extern GAsyncQueue *mock_sem_ready; extern GAsyncQueue *mock_sem_timeout; extern char mock_ba_service_name[32]; extern bool mock_dump_output; @@ -42,5 +43,14 @@ int mock_bluez_device_name_mapping_add(const char *mapping); void mock_bluez_service_start(void); void mock_bluez_service_stop(void); +int mock_bluez_device_profile_new_connection(const char *device_path, + const char *uuid, GAsyncQueue *sem_ready); +int mock_bluez_device_media_set_configuration(const char *device_path, + const char *transport_path, const char *uuid, uint32_t codec_id, + const void *configuration, size_t configuration_size, + GAsyncQueue *sem_ready); + void mock_sem_signal(GAsyncQueue *sem); void mock_sem_wait(GAsyncQueue *sem); + +GThread *mock_bt_dump_thread_new(int fd); diff --git a/utils/aplay/aplay.c b/utils/aplay/aplay.c index 213c0d64b..a1a0fad9d 100644 --- a/utils/aplay/aplay.c +++ b/utils/aplay/aplay.c @@ -1189,6 +1189,10 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } + struct sigaction sigact = { .sa_handler = main_loop_stop }; + sigaction(SIGTERM, &sigact, NULL); + sigaction(SIGINT, &sigact, NULL); + DBusError err = DBUS_ERROR_INIT; if (!ba_dbus_connection_ctx_init(&dbus_ctx, dbus_ba_service, &err)) { error("Couldn't initialize D-Bus context: %s", err.message); @@ -1280,10 +1284,6 @@ int main(int argc, char *argv[]) { for (size_t i = 0; i < ba_pcms_count; i++) supervise_io_worker(&ba_pcms[i]); - struct sigaction sigact = { .sa_handler = main_loop_stop }; - sigaction(SIGTERM, &sigact, NULL); - sigaction(SIGINT, &sigact, NULL); - debug("Starting main loop"); while (main_loop_on) {