• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2013 João Paulo Rechi Vita
5 
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10 
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15 
16   You should have received a copy of the GNU Lesser General Public
17   License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18 ***/
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #include <errno.h>
25 #include <poll.h>
26 
27 #include <pulsecore/core-util.h>
28 #include <pulsecore/dbus-shared.h>
29 #include <pulsecore/shared.h>
30 #include <pulsecore/core-error.h>
31 
32 #include "bluez5-util.h"
33 
34 #define HFP_AUDIO_CODEC_CVSD    0x01
35 #define HFP_AUDIO_CODEC_MSBC    0x02
36 
37 #define OFONO_SERVICE "org.ofono"
38 #define HF_AUDIO_AGENT_INTERFACE OFONO_SERVICE ".HandsfreeAudioAgent"
39 #define HF_AUDIO_MANAGER_INTERFACE OFONO_SERVICE ".HandsfreeAudioManager"
40 
41 #define HF_AUDIO_AGENT_PATH "/HandsfreeAudioAgent"
42 
43 #define HF_AUDIO_AGENT_XML                                          \
44     DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
45     "<node>"                                                        \
46     "  <interface name=\"org.freedesktop.DBus.Introspectable\">"    \
47     "    <method name=\"Introspect\">"                              \
48     "      <arg direction=\"out\" type=\"s\" />"                    \
49     "    </method>"                                                 \
50     "  </interface>"                                                \
51     "  <interface name=\"org.ofono.HandsfreeAudioAgent\">"          \
52     "    <method name=\"Release\">"                                 \
53     "    </method>"                                                 \
54     "    <method name=\"NewConnection\">"                           \
55     "      <arg direction=\"in\"  type=\"o\" name=\"card_path\" />" \
56     "      <arg direction=\"in\"  type=\"h\" name=\"sco_fd\" />"    \
57     "      <arg direction=\"in\"  type=\"y\" name=\"codec\" />"     \
58     "    </method>"                                                 \
59     "  </interface>"                                                \
60     "</node>"
61 
62 struct hf_audio_card {
63     pa_bluetooth_backend *backend;
64     char *path;
65     char *remote_address;
66     char *local_address;
67 
68     bool connecting;
69     int fd;
70     int (*acquire)(struct hf_audio_card *card);
71 
72     pa_bluetooth_transport *transport;
73     pa_hook_slot *device_unlink_slot;
74 };
75 
76 struct pa_bluetooth_backend {
77     pa_core *core;
78     pa_bluetooth_discovery *discovery;
79     pa_dbus_connection *connection;
80     pa_hashmap *cards;
81     char *ofono_bus_id;
82 
83     PA_LLIST_HEAD(pa_dbus_pending, pending);
84 };
85 
hf_dbus_send_and_add_to_pending(pa_bluetooth_backend * backend,DBusMessage * m,DBusPendingCallNotifyFunction func,void * call_data)86 static pa_dbus_pending* hf_dbus_send_and_add_to_pending(pa_bluetooth_backend *backend, DBusMessage *m,
87                                                     DBusPendingCallNotifyFunction func, void *call_data) {
88     pa_dbus_pending *p;
89     DBusPendingCall *call;
90 
91     pa_assert(backend);
92     pa_assert(m);
93 
94     pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(backend->connection), m, &call, -1));
95 
96     p = pa_dbus_pending_new(pa_dbus_connection_get(backend->connection), m, call, backend, call_data);
97     PA_LLIST_PREPEND(pa_dbus_pending, backend->pending, p);
98     dbus_pending_call_set_notify(call, func, p, NULL);
99 
100     return p;
101 }
102 
card_send(struct hf_audio_card * card,const char * method,DBusError * err)103 static DBusMessage *card_send(struct hf_audio_card *card, const char *method, DBusError *err)
104 {
105     pa_bluetooth_transport *t = card->transport;
106     DBusMessage *m, *r;
107 
108     pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.ofono.HandsfreeAudioCard", method));
109     r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(card->backend->connection), m, -1, err);
110     dbus_message_unref(m);
111 
112     return r;
113 }
114 
card_connect(struct hf_audio_card * card)115 static int card_connect(struct hf_audio_card *card) {
116     DBusMessage *r;
117     DBusError err;
118 
119     if (card->connecting)
120         return -EAGAIN;
121 
122     card->connecting = true;
123 
124     dbus_error_init(&err);
125     r = card_send(card, "Connect", &err);
126 
127     if (!r) {
128         pa_log_error("Failed to connect %s: %s", err.name, err.message);
129         card->connecting = false;
130         dbus_error_free(&err);
131         return -1;
132     }
133 
134     dbus_message_unref(r);
135 
136     if (card->connecting)
137         return -EAGAIN;
138 
139     return 0;
140 }
141 
card_acquire(struct hf_audio_card * card)142 static int card_acquire(struct hf_audio_card *card) {
143     int fd;
144     uint8_t codec;
145     DBusMessage *r;
146     DBusError err;
147 
148     /* Try acquiring the stream first which was introduced in 1.21 */
149     dbus_error_init(&err);
150     r = card_send(card, "Acquire", &err);
151 
152     if (!r) {
153         if (!pa_streq(err.name, DBUS_ERROR_UNKNOWN_METHOD)) {
154             pa_log_error("Failed to acquire %s: %s", err.name, err.message);
155             dbus_error_free(&err);
156             return -1;
157         }
158         dbus_error_free(&err);
159         /* Fallback to Connect as this might be an old version of ofono */
160         card->acquire = card_connect;
161         return card_connect(card);
162     }
163 
164     if ((dbus_message_get_args(r, NULL, DBUS_TYPE_UNIX_FD, &fd,
165                                       DBUS_TYPE_BYTE, &codec,
166                                       DBUS_TYPE_INVALID) == true)) {
167         dbus_message_unref(r);
168         if (codec != HFP_AUDIO_CODEC_CVSD) {
169             pa_log_error("Invalid codec: %u", codec);
170             /* shutdown to make sure connection is dropped immediately */
171             shutdown(fd, SHUT_RDWR);
172             close(fd);
173             return -1;
174         }
175         card->transport->codec = codec;
176         card->fd = fd;
177         return 0;
178     }
179 
180     pa_log_error("Unable to acquire");
181     dbus_message_unref(r);
182     return -1;
183 }
184 
185 static void hf_audio_agent_card_removed(pa_bluetooth_backend *backend, const char *path);
186 
device_unlink_cb(pa_bluetooth_discovery * y,const pa_bluetooth_device * d,struct hf_audio_card * card)187 static pa_hook_result_t device_unlink_cb(pa_bluetooth_discovery *y, const pa_bluetooth_device *d, struct hf_audio_card *card) {
188     pa_assert(d);
189     pa_assert(card);
190 
191     hf_audio_agent_card_removed(card->backend, card->path);
192 
193     return PA_HOOK_OK;
194 }
195 
hf_audio_card_new(pa_bluetooth_backend * backend,const char * path)196 static struct hf_audio_card *hf_audio_card_new(pa_bluetooth_backend *backend, const char *path) {
197     struct hf_audio_card *card = pa_xnew0(struct hf_audio_card, 1);
198 
199     card->path = pa_xstrdup(path);
200     card->backend = backend;
201     card->fd = -1;
202     card->acquire = card_acquire;
203 
204     card->device_unlink_slot = pa_hook_connect(pa_bluetooth_discovery_hook(backend->discovery, PA_BLUETOOTH_HOOK_DEVICE_UNLINK),
205                                                PA_HOOK_NORMAL, (pa_hook_cb_t) device_unlink_cb, card);
206 
207     return card;
208 }
209 
hf_audio_card_free(struct hf_audio_card * card)210 static void hf_audio_card_free(struct hf_audio_card *card) {
211     pa_assert(card);
212 
213     if (card->device_unlink_slot)
214         pa_hook_slot_free(card->device_unlink_slot);
215 
216     if (card->transport)
217         pa_bluetooth_transport_free(card->transport);
218 
219     pa_xfree(card->path);
220     pa_xfree(card->remote_address);
221     pa_xfree(card->local_address);
222     pa_xfree(card);
223 }
224 
socket_accept(int sock)225 static int socket_accept(int sock)
226 {
227     char c;
228     struct pollfd pfd;
229 
230     if (sock < 0)
231         return -ENOTCONN;
232 
233     memset(&pfd, 0, sizeof(pfd));
234     pfd.fd = sock;
235     pfd.events = POLLOUT;
236 
237     if (poll(&pfd, 1, 0) < 0)
238         return -errno;
239 
240     /*
241      * If socket already writable then it is not in defer setup state,
242      * otherwise it needs to be read to authorize the connection.
243      */
244     if ((pfd.revents & POLLOUT))
245         return 0;
246 
247     /* Enable socket by reading 1 byte */
248     if (read(sock, &c, 1) < 0)
249         return -errno;
250 
251     return 0;
252 }
253 
hf_audio_agent_transport_acquire(pa_bluetooth_transport * t,bool optional,size_t * imtu,size_t * omtu)254 static int hf_audio_agent_transport_acquire(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) {
255     struct hf_audio_card *card = t->userdata;
256     int err;
257 
258     pa_assert(card);
259 
260     if (!optional && card->fd < 0) {
261         err = card->acquire(card);
262         if (err < 0)
263             return err;
264     }
265 
266     /* The correct block size should take into account the SCO MTU from
267      * the Bluetooth adapter and (for adapters in the USB bus) the MxPS
268      * value from the Isoc USB endpoint in use by btusb and should be
269      * made available to userspace by the Bluetooth kernel subsystem.
270      * Meanwhile the empiric value 48 will be used. */
271     if (imtu)
272         *imtu = 48;
273     if (omtu)
274         *omtu = 48;
275 
276     err = socket_accept(card->fd);
277     if (err < 0) {
278         pa_log_error("Deferred setup failed on fd %d: %s", card->fd, pa_cstrerror(-err));
279         return -1;
280     }
281 
282     return card->fd;
283 }
284 
hf_audio_agent_transport_release(pa_bluetooth_transport * t)285 static void hf_audio_agent_transport_release(pa_bluetooth_transport *t) {
286     struct hf_audio_card *card = t->userdata;
287 
288     pa_assert(card);
289 
290     if (card->fd < 0) {
291         pa_log_info("Transport %s already released", t->path);
292         return;
293     }
294 
295     /* shutdown to make sure connection is dropped immediately */
296     shutdown(card->fd, SHUT_RDWR);
297     close(card->fd);
298     card->fd = -1;
299 }
300 
hf_audio_agent_card_found(pa_bluetooth_backend * backend,const char * path,DBusMessageIter * props_i)301 static void hf_audio_agent_card_found(pa_bluetooth_backend *backend, const char *path, DBusMessageIter *props_i) {
302     DBusMessageIter i, value_i;
303     const char *key, *value;
304     struct hf_audio_card *card;
305     pa_bluetooth_device *d;
306     pa_bluetooth_profile_t p = PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY;
307 
308     pa_assert(backend);
309     pa_assert(path);
310     pa_assert(props_i);
311 
312     pa_log_debug("New HF card found: %s", path);
313 
314     card = hf_audio_card_new(backend, path);
315 
316     while (dbus_message_iter_get_arg_type(props_i) != DBUS_TYPE_INVALID) {
317         char c;
318 
319         dbus_message_iter_recurse(props_i, &i);
320 
321         dbus_message_iter_get_basic(&i, &key);
322         dbus_message_iter_next(&i);
323         dbus_message_iter_recurse(&i, &value_i);
324 
325         if ((c = dbus_message_iter_get_arg_type(&value_i)) != DBUS_TYPE_STRING) {
326             pa_log_error("Invalid properties for %s: expected 's', received '%c'", path, c);
327             goto fail;
328         }
329 
330         dbus_message_iter_get_basic(&value_i, &value);
331 
332         if (pa_streq(key, "RemoteAddress")) {
333             pa_xfree(card->remote_address);
334             card->remote_address = pa_xstrdup(value);
335         } else if (pa_streq(key, "LocalAddress")) {
336             pa_xfree(card->local_address);
337             card->local_address = pa_xstrdup(value);
338         } else if (pa_streq(key, "Type")) {
339             if (pa_streq(value, "gateway"))
340                 p = PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT;
341         }
342 
343         pa_log_debug("%s: %s", key, value);
344 
345         dbus_message_iter_next(props_i);
346     }
347 
348     d = pa_bluetooth_discovery_get_device_by_address(backend->discovery, card->remote_address, card->local_address);
349     if (!d) {
350         pa_log_error("Device doesnt exist for %s", path);
351         goto fail;
352     }
353 
354     card->transport = pa_bluetooth_transport_new(d, backend->ofono_bus_id, path, p, NULL, 0);
355     card->transport->acquire = hf_audio_agent_transport_acquire;
356     card->transport->release = hf_audio_agent_transport_release;
357     card->transport->userdata = card;
358 
359     pa_bluetooth_transport_put(card->transport);
360     pa_hashmap_put(backend->cards, card->path, card);
361 
362     return;
363 
364 fail:
365     hf_audio_card_free(card);
366 }
367 
hf_audio_agent_card_removed(pa_bluetooth_backend * backend,const char * path)368 static void hf_audio_agent_card_removed(pa_bluetooth_backend *backend, const char *path) {
369     struct hf_audio_card *card;
370 
371     pa_assert(backend);
372     pa_assert(path);
373 
374     pa_log_debug("HF card removed: %s", path);
375 
376     card = pa_hashmap_remove(backend->cards, path);
377     if (!card)
378         return;
379 
380     hf_audio_card_free(card);
381 }
382 
hf_audio_agent_get_cards_reply(DBusPendingCall * pending,void * userdata)383 static void hf_audio_agent_get_cards_reply(DBusPendingCall *pending, void *userdata) {
384     DBusMessage *r;
385     pa_dbus_pending *p;
386     pa_bluetooth_backend *backend;
387     DBusMessageIter i, array_i, struct_i, props_i;
388 
389     pa_assert_se(p = userdata);
390     pa_assert_se(backend = p->context_data);
391     pa_assert_se(r = dbus_pending_call_steal_reply(pending));
392 
393     if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
394         pa_log_error("Failed to get a list of handsfree audio cards from ofono: %s: %s",
395                      dbus_message_get_error_name(r), pa_dbus_get_error_message(r));
396         goto finish;
397     }
398 
399     if (!dbus_message_iter_init(r, &i) || !pa_streq(dbus_message_get_signature(r), "a(oa{sv})")) {
400         pa_log_error("Invalid arguments in GetCards() reply");
401         goto finish;
402     }
403 
404     dbus_message_iter_recurse(&i, &array_i);
405     while (dbus_message_iter_get_arg_type(&array_i) != DBUS_TYPE_INVALID) {
406         const char *path;
407 
408         dbus_message_iter_recurse(&array_i, &struct_i);
409         dbus_message_iter_get_basic(&struct_i, &path);
410         dbus_message_iter_next(&struct_i);
411 
412         dbus_message_iter_recurse(&struct_i, &props_i);
413 
414         hf_audio_agent_card_found(backend, path, &props_i);
415 
416         dbus_message_iter_next(&array_i);
417     }
418 
419 finish:
420     dbus_message_unref(r);
421 
422     PA_LLIST_REMOVE(pa_dbus_pending, backend->pending, p);
423     pa_dbus_pending_free(p);
424 }
425 
hf_audio_agent_get_cards(pa_bluetooth_backend * hf)426 static void hf_audio_agent_get_cards(pa_bluetooth_backend *hf) {
427     DBusMessage *m;
428 
429     pa_assert(hf);
430 
431     pa_assert_se(m = dbus_message_new_method_call(OFONO_SERVICE, "/", HF_AUDIO_MANAGER_INTERFACE, "GetCards"));
432     hf_dbus_send_and_add_to_pending(hf, m, hf_audio_agent_get_cards_reply, NULL);
433 }
434 
ofono_bus_id_destroy(pa_bluetooth_backend * backend)435 static void ofono_bus_id_destroy(pa_bluetooth_backend *backend) {
436     pa_hashmap_remove_all(backend->cards);
437 
438     if (backend->ofono_bus_id) {
439         pa_xfree(backend->ofono_bus_id);
440         backend->ofono_bus_id = NULL;
441         pa_bluetooth_discovery_set_ofono_running(backend->discovery, false);
442     }
443 }
444 
hf_audio_agent_register_reply(DBusPendingCall * pending,void * userdata)445 static void hf_audio_agent_register_reply(DBusPendingCall *pending, void *userdata) {
446     DBusMessage *r;
447     pa_dbus_pending *p;
448     pa_bluetooth_backend *backend;
449 
450     pa_assert_se(p = userdata);
451     pa_assert_se(backend = p->context_data);
452     pa_assert_se(r = dbus_pending_call_steal_reply(pending));
453 
454     if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
455         pa_log_info("Failed to register as a handsfree audio agent with ofono: %s: %s",
456                     dbus_message_get_error_name(r), pa_dbus_get_error_message(r));
457         goto finish;
458     }
459 
460     backend->ofono_bus_id = pa_xstrdup(dbus_message_get_sender(r));
461 
462     hf_audio_agent_get_cards(backend);
463 
464 finish:
465     dbus_message_unref(r);
466 
467     PA_LLIST_REMOVE(pa_dbus_pending, backend->pending, p);
468     pa_dbus_pending_free(p);
469 
470     pa_bluetooth_discovery_set_ofono_running(backend->discovery, backend->ofono_bus_id != NULL);
471 }
472 
hf_audio_agent_register(pa_bluetooth_backend * hf)473 static void hf_audio_agent_register(pa_bluetooth_backend *hf) {
474     DBusMessage *m;
475     uint8_t codecs[2];
476     const uint8_t *pcodecs = codecs;
477     int ncodecs = 0;
478     const char *path = HF_AUDIO_AGENT_PATH;
479 
480     pa_assert(hf);
481 
482     pa_assert_se(m = dbus_message_new_method_call(OFONO_SERVICE, "/", HF_AUDIO_MANAGER_INTERFACE, "Register"));
483 
484     codecs[ncodecs++] = HFP_AUDIO_CODEC_CVSD;
485 
486     pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pcodecs, ncodecs,
487                                           DBUS_TYPE_INVALID));
488 
489     hf_dbus_send_and_add_to_pending(hf, m, hf_audio_agent_register_reply, NULL);
490 }
491 
hf_audio_agent_unregister(pa_bluetooth_backend * backend)492 static void hf_audio_agent_unregister(pa_bluetooth_backend *backend) {
493     DBusMessage *m;
494     const char *path = HF_AUDIO_AGENT_PATH;
495 
496     pa_assert(backend);
497     pa_assert(backend->connection);
498 
499     if (backend->ofono_bus_id) {
500         pa_assert_se(m = dbus_message_new_method_call(backend->ofono_bus_id, "/", HF_AUDIO_MANAGER_INTERFACE, "Unregister"));
501         pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID));
502         pa_assert_se(dbus_connection_send(pa_dbus_connection_get(backend->connection), m, NULL));
503 
504         ofono_bus_id_destroy(backend);
505     }
506 }
507 
filter_cb(DBusConnection * bus,DBusMessage * m,void * data)508 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *data) {
509     const char *sender;
510     DBusError err;
511     pa_bluetooth_backend *backend = data;
512 
513     pa_assert(bus);
514     pa_assert(m);
515     pa_assert(backend);
516 
517     sender = dbus_message_get_sender(m);
518     if (!pa_safe_streq(backend->ofono_bus_id, sender) && !pa_streq("org.freedesktop.DBus", sender))
519         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
520 
521     dbus_error_init(&err);
522 
523     if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) {
524         const char *name, *old_owner, *new_owner;
525 
526         if (!dbus_message_get_args(m, &err,
527                                    DBUS_TYPE_STRING, &name,
528                                    DBUS_TYPE_STRING, &old_owner,
529                                    DBUS_TYPE_STRING, &new_owner,
530                                    DBUS_TYPE_INVALID)) {
531             pa_log_error("Failed to parse org.freedesktop.DBus.NameOwnerChanged: %s", err.message);
532             goto fail;
533         }
534 
535         if (pa_streq(name, OFONO_SERVICE)) {
536 
537             if (old_owner && *old_owner) {
538                 pa_log_debug("oFono disappeared");
539                 ofono_bus_id_destroy(backend);
540             }
541 
542             if (new_owner && *new_owner) {
543                 pa_log_debug("oFono appeared");
544                 hf_audio_agent_register(backend);
545             }
546         }
547 
548     } else if (dbus_message_is_signal(m, "org.ofono.HandsfreeAudioManager", "CardAdded")) {
549         const char *p;
550         DBusMessageIter arg_i, props_i;
551 
552         if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oa{sv}")) {
553             pa_log_error("Failed to parse org.ofono.HandsfreeAudioManager.CardAdded");
554             goto fail;
555         }
556 
557         dbus_message_iter_get_basic(&arg_i, &p);
558 
559         pa_assert_se(dbus_message_iter_next(&arg_i));
560         pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_ARRAY);
561 
562         dbus_message_iter_recurse(&arg_i, &props_i);
563 
564         hf_audio_agent_card_found(backend, p, &props_i);
565     } else if (dbus_message_is_signal(m, "org.ofono.HandsfreeAudioManager", "CardRemoved")) {
566         const char *p;
567 
568         if (!dbus_message_get_args(m, &err, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_INVALID)) {
569             pa_log_error("Failed to parse org.ofono.HandsfreeAudioManager.CardRemoved: %s", err.message);
570             goto fail;
571         }
572 
573         hf_audio_agent_card_removed(backend, p);
574     }
575 
576 fail:
577     dbus_error_free(&err);
578     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
579 }
580 
hf_audio_agent_release(DBusConnection * c,DBusMessage * m,void * data)581 static DBusMessage *hf_audio_agent_release(DBusConnection *c, DBusMessage *m, void *data) {
582     DBusMessage *r;
583     const char *sender;
584     pa_bluetooth_backend *backend = data;
585 
586     pa_assert(backend);
587 
588     sender = dbus_message_get_sender(m);
589     if (!pa_safe_streq(backend->ofono_bus_id, sender)) {
590         pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.NotAllowed", "Operation is not allowed by this sender"));
591         return r;
592     }
593 
594     pa_log_debug("HF audio agent has been unregistered by oFono (%s)", backend->ofono_bus_id);
595 
596     ofono_bus_id_destroy(backend);
597 
598     pa_assert_se(r = dbus_message_new_method_return(m));
599 
600     return r;
601 }
602 
hf_audio_agent_new_connection(DBusConnection * c,DBusMessage * m,void * data)603 static DBusMessage *hf_audio_agent_new_connection(DBusConnection *c, DBusMessage *m, void *data) {
604     DBusMessage *r;
605     const char *sender, *path;
606     int fd;
607     uint8_t codec;
608     struct hf_audio_card *card;
609     pa_bluetooth_backend *backend = data;
610 
611     pa_assert(backend);
612 
613     sender = dbus_message_get_sender(m);
614     if (!pa_safe_streq(backend->ofono_bus_id, sender)) {
615         pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.NotAllowed", "Operation is not allowed by this sender"));
616         return r;
617     }
618 
619     if (dbus_message_get_args(m, NULL,
620                               DBUS_TYPE_OBJECT_PATH, &path,
621                               DBUS_TYPE_UNIX_FD, &fd,
622                               DBUS_TYPE_BYTE, &codec,
623                               DBUS_TYPE_INVALID) == FALSE) {
624         pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.InvalidArguments", "Invalid arguments in method call"));
625         return r;
626     }
627 
628     card = pa_hashmap_get(backend->cards, path);
629 
630     if (!card || codec != HFP_AUDIO_CODEC_CVSD || card->fd >= 0) {
631         pa_log_warn("New audio connection invalid arguments (path=%s fd=%d, codec=%d)", path, fd, codec);
632         pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.InvalidArguments", "Invalid arguments in method call"));
633         shutdown(fd, SHUT_RDWR);
634         close(fd);
635         return r;
636     }
637 
638     pa_log_debug("New audio connection on card %s (fd=%d, codec=%d)", path, fd, codec);
639 
640     card->connecting = false;
641     card->fd = fd;
642     card->transport->codec = codec;
643 
644     pa_bluetooth_transport_set_state(card->transport, PA_BLUETOOTH_TRANSPORT_STATE_PLAYING);
645 
646     pa_assert_se(r = dbus_message_new_method_return(m));
647 
648     return r;
649 }
650 
hf_audio_agent_handler(DBusConnection * c,DBusMessage * m,void * data)651 static DBusHandlerResult hf_audio_agent_handler(DBusConnection *c, DBusMessage *m, void *data) {
652     pa_bluetooth_backend *backend = data;
653     DBusMessage *r = NULL;
654     const char *path, *interface, *member;
655 
656     pa_assert(backend);
657 
658     path = dbus_message_get_path(m);
659     interface = dbus_message_get_interface(m);
660     member = dbus_message_get_member(m);
661 
662     if (!pa_streq(path, HF_AUDIO_AGENT_PATH))
663         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
664 
665     pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
666 
667     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
668         const char *xml = HF_AUDIO_AGENT_XML;
669 
670         pa_assert_se(r = dbus_message_new_method_return(m));
671         pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
672 
673     } else if (dbus_message_is_method_call(m, HF_AUDIO_AGENT_INTERFACE, "NewConnection"))
674         r = hf_audio_agent_new_connection(c, m, data);
675     else if (dbus_message_is_method_call(m, HF_AUDIO_AGENT_INTERFACE, "Release"))
676         r = hf_audio_agent_release(c, m, data);
677     else
678         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
679 
680     if (r) {
681         pa_assert_se(dbus_connection_send(pa_dbus_connection_get(backend->connection), r, NULL));
682         dbus_message_unref(r);
683     }
684 
685     return DBUS_HANDLER_RESULT_HANDLED;
686 }
687 
pa_bluetooth_ofono_backend_new(pa_core * c,pa_bluetooth_discovery * y)688 pa_bluetooth_backend *pa_bluetooth_ofono_backend_new(pa_core *c, pa_bluetooth_discovery *y) {
689     pa_bluetooth_backend *backend;
690     DBusError err;
691     static const DBusObjectPathVTable vtable_hf_audio_agent = {
692         .message_function = hf_audio_agent_handler,
693     };
694 
695     pa_assert(c);
696 
697     backend = pa_xnew0(pa_bluetooth_backend, 1);
698     backend->core = c;
699     backend->discovery = y;
700     backend->cards = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
701                                          (pa_free_cb_t) hf_audio_card_free);
702 
703     dbus_error_init(&err);
704 
705     if (!(backend->connection = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &err))) {
706         pa_log("Failed to get D-Bus connection: %s", err.message);
707         dbus_error_free(&err);
708         pa_xfree(backend);
709         return NULL;
710     }
711 
712     /* dynamic detection of handsfree audio cards */
713     if (!dbus_connection_add_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend, NULL)) {
714         pa_log_error("Failed to add filter function");
715         pa_dbus_connection_unref(backend->connection);
716         pa_xfree(backend);
717         return NULL;
718     }
719 
720     if (pa_dbus_add_matches(pa_dbus_connection_get(backend->connection), &err,
721             "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',"
722             "arg0='" OFONO_SERVICE "'",
723             "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardAdded'",
724             "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardRemoved'",
725             NULL) < 0) {
726         pa_log("Failed to add oFono D-Bus matches: %s", err.message);
727         dbus_connection_remove_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend);
728         pa_dbus_connection_unref(backend->connection);
729         pa_xfree(backend);
730         return NULL;
731     }
732 
733     pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(backend->connection), HF_AUDIO_AGENT_PATH,
734                                                       &vtable_hf_audio_agent, backend));
735 
736     hf_audio_agent_register(backend);
737 
738     return backend;
739 }
740 
pa_bluetooth_ofono_backend_free(pa_bluetooth_backend * backend)741 void pa_bluetooth_ofono_backend_free(pa_bluetooth_backend *backend) {
742     pa_assert(backend);
743 
744     pa_dbus_free_pending_list(&backend->pending);
745 
746     hf_audio_agent_unregister(backend);
747 
748     dbus_connection_unregister_object_path(pa_dbus_connection_get(backend->connection), HF_AUDIO_AGENT_PATH);
749 
750     pa_dbus_remove_matches(pa_dbus_connection_get(backend->connection),
751             "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',"
752             "arg0='" OFONO_SERVICE "'",
753             "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardAdded'",
754             "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardRemoved'",
755             NULL);
756 
757     dbus_connection_remove_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend);
758 
759     pa_dbus_connection_unref(backend->connection);
760 
761     pa_hashmap_free(backend->cards);
762 
763     pa_xfree(backend);
764 }
765