diff --git a/src/modules/bluetooth/backend-ofono.c b/src/modules/bluetooth/backend-ofono.c index 2c51497f3..5f427043e 100644 --- a/src/modules/bluetooth/backend-ofono.c +++ b/src/modules/bluetooth/backend-ofono.c @@ -67,7 +67,7 @@ struct hf_audio_card { bool connecting; int fd; - uint8_t codec; + int (*acquire)(struct hf_audio_card *card); pa_bluetooth_transport *transport; }; @@ -99,12 +99,95 @@ static pa_dbus_pending* hf_dbus_send_and_add_to_pending(pa_bluetooth_backend *ba return p; } +static DBusMessage *card_send(struct hf_audio_card *card, const char *method, DBusError *err) +{ + pa_bluetooth_transport *t = card->transport; + DBusMessage *m, *r; + + pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.ofono.HandsfreeAudioCard", method)); + r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(card->backend->connection), m, -1, err); + dbus_message_unref(m); + + return r; +} + +static int card_connect(struct hf_audio_card *card) { + DBusMessage *r; + DBusError err; + + if (card->connecting) + return -EAGAIN; + + card->connecting = true; + + dbus_error_init(&err); + r = card_send(card, "Connect", &err); + + if (!r) { + pa_log_error("Failed to connect %s: %s", err.name, err.message); + card->connecting = false; + dbus_error_free(&err); + return -1; + } + + dbus_message_unref(r); + + if (card->connecting) + return -EAGAIN; + + return 0; +} + +static int card_acquire(struct hf_audio_card *card) { + int fd; + uint8_t codec; + DBusMessage *r; + DBusError err; + + /* Try acquiring the stream first which was introduced in 1.21 */ + dbus_error_init(&err); + r = card_send(card, "Acquire", &err); + + if (!r) { + if (!pa_streq(err.name, DBUS_ERROR_UNKNOWN_METHOD)) { + pa_log_error("Failed to acquire %s: %s", err.name, err.message); + dbus_error_free(&err); + return -1; + } + dbus_error_free(&err); + /* Fallback to Connect as this might be an old version of ofono */ + card->acquire = card_connect; + return card_connect(card); + } + + if ((dbus_message_get_args(r, NULL, DBUS_TYPE_UNIX_FD, &fd, + DBUS_TYPE_BYTE, &codec, + DBUS_TYPE_INVALID) == true)) { + dbus_message_unref(r); + if (codec != HFP_AUDIO_CODEC_CVSD) { + pa_log_error("Invalid codec: %u", codec); + /* shutdown to make sure connection is dropped immediately */ + shutdown(fd, SHUT_RDWR); + close(fd); + return -1; + } + card->transport->codec = codec; + card->fd = fd; + return 0; + } + + pa_log_error("Unable to acquire"); + dbus_message_unref(r); + return -1; +} + static struct hf_audio_card *hf_audio_card_new(pa_bluetooth_backend *backend, const char *path) { struct hf_audio_card *card = pa_xnew0(struct hf_audio_card, 1); card->path = pa_xstrdup(path); card->backend = backend; card->fd = -1; + card->acquire = card_acquire; return card; } @@ -157,28 +240,9 @@ static int hf_audio_agent_transport_acquire(pa_bluetooth_transport *t, bool opti pa_assert(card); if (!optional && card->fd < 0) { - DBusMessage *m, *r; - DBusError derr; - - if (card->connecting) - return -EAGAIN; - - card->connecting = true; - - dbus_error_init(&derr); - pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.ofono.HandsfreeAudioCard", "Connect")); - r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(card->backend->connection), m, -1, &derr); - dbus_message_unref(m); - m = NULL; - - if (!r) - return -1; - - dbus_message_unref(r); - r = NULL; - - if (card->connecting) - return -EAGAIN; + err = card->acquire(card); + if (err < 0) + return err; } /* The correct block size should take into account the SCO MTU from @@ -191,8 +255,6 @@ static int hf_audio_agent_transport_acquire(pa_bluetooth_transport *t, bool opti if (omtu) *omtu = 48; - t->codec = card->codec; - err = socket_accept(card->fd); if (err < 0) { pa_log_error("Deferred setup failed on fd %d: %s", card->fd, pa_cstrerror(-err));