1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2014 Wim Taymans <wim.taymans at gmail.com>
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 <pulse/util.h>
25
26 #include <pulsecore/shared.h>
27 #include <pulsecore/core-error.h>
28 #include <pulsecore/core-util.h>
29 #include <pulsecore/dbus-shared.h>
30 #include <pulsecore/log.h>
31
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35
36 #include <bluetooth/bluetooth.h>
37 #include <bluetooth/sco.h>
38
39 #include "bluez5-util.h"
40 #include "bt-codec-msbc.h"
41 #include "upower.h"
42
43 #define MANDATORY_CALL_INDICATORS \
44 "(\"call\",(0-1))," \
45 "(\"callsetup\",(0-3))," \
46 "(\"callheld\",(0-2))" \
47
48 struct pa_bluetooth_backend {
49 pa_core *core;
50 pa_dbus_connection *connection;
51 pa_bluetooth_discovery *discovery;
52 pa_hook_slot *adapter_uuids_changed_slot;
53 pa_hook_slot *host_battery_level_changed_slot;
54 pa_upower_backend *upower;
55 bool enable_shared_profiles;
56 bool enable_hsp_hs;
57 bool enable_hfp_hf;
58 bool cmer_indicator_reporting_enabled;
59 uint32_t cind_enabled_indicators;
60
61 PA_LLIST_HEAD(pa_dbus_pending, pending);
62 };
63
64 struct transport_data {
65 int rfcomm_fd;
66 pa_io_event *rfcomm_io;
67 int sco_fd;
68 pa_io_event *sco_io;
69 pa_mainloop_api *mainloop;
70 pa_bluetooth_backend *backend;
71 };
72
73 struct hfp_config {
74 uint32_t capabilities;
75 int state;
76 bool support_codec_negotiation;
77 bool support_msbc;
78 bool supports_indicators;
79 int selected_codec;
80 };
81
82 /*
83 * the separate hansfree headset (HF) and Audio Gateway (AG) features
84 */
85 enum hfp_hf_features {
86 HFP_HF_EC_NR = 0,
87 HFP_HF_CALL_WAITING = 1,
88 HFP_HF_CLI = 2,
89 HFP_HF_VR = 3,
90 HFP_HF_RVOL = 4,
91 HFP_HF_ESTATUS = 5,
92 HFP_HF_ECALL = 6,
93 HFP_HF_CODECS = 7,
94 HFP_HF_INDICATORS = 8,
95 };
96
97 enum hfp_ag_features {
98 HFP_AG_THREE_WAY = 0,
99 HFP_AG_EC_NR = 1,
100 HFP_AG_VR = 2,
101 HFP_AG_RING = 3,
102 HFP_AG_NUM_TAG = 4,
103 HFP_AG_REJECT = 5,
104 HFP_AG_ESTATUS = 6,
105 HFP_AG_ECALL = 7,
106 HFP_AG_EERR = 8,
107 HFP_AG_CODECS = 9,
108 HFP_AG_INDICATORS = 10,
109 };
110
111 /*
112 * Always keep this struct in sync with indicator discovery of AT+CIND=?
113 * These indicators are used in bitflags and intentionally start at 1
114 * since AT+CIND indicators start at index 1.
115 */
116 typedef enum pa_bluetooth_ag_to_hf_indicators {
117 CIND_CALL_INDICATOR = 1,
118 CIND_CALL_SETUP_INDICATOR = 2,
119 CIND_CALL_HELD_INDICATOR = 3,
120 CIND_SERVICE_INDICATOR = 4,
121 CIND_BATT_CHG_INDICATOR = 5,
122 CIND_INDICATOR_MAX = 6
123 } pa_bluetooth_ag_to_hf_indicators_t;
124
125 /* gateway features we support, which is as little as we can get away with */
126 static uint32_t hfp_features =
127 /* HFP 1.6 requires this */
128 (1 << HFP_AG_ESTATUS ) | (1 << HFP_AG_CODECS) | (1 << HFP_AG_INDICATORS);
129
130 #define HSP_AG_PROFILE "/Profile/HSPAGProfile"
131 #define HFP_AG_PROFILE "/Profile/HFPAGProfile"
132 #define HSP_HS_PROFILE "/Profile/HSPHSProfile"
133
134 /* RFCOMM channel for HSP headset role
135 * The choice seems to be a bit arbitrary -- it looks like at least channels 2, 4 and 5 also work*/
136 #define HSP_HS_DEFAULT_CHANNEL 3
137
138 /* Total number of trying to reconnect */
139 #define SCO_RECONNECTION_COUNT 3
140
141 #define PROFILE_INTROSPECT_XML \
142 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
143 "<node>" \
144 " <interface name=\"" BLUEZ_PROFILE_INTERFACE "\">" \
145 " <method name=\"Release\">" \
146 " </method>" \
147 " <method name=\"RequestDisconnection\">" \
148 " <arg name=\"device\" direction=\"in\" type=\"o\"/>" \
149 " </method>" \
150 " <method name=\"NewConnection\">" \
151 " <arg name=\"device\" direction=\"in\" type=\"o\"/>" \
152 " <arg name=\"fd\" direction=\"in\" type=\"h\"/>" \
153 " <arg name=\"opts\" direction=\"in\" type=\"a{sv}\"/>" \
154 " </method>" \
155 " </interface>" \
156 " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">" \
157 " <method name=\"Introspect\">" \
158 " <arg name=\"data\" type=\"s\" direction=\"out\"/>" \
159 " </method>" \
160 " </interface>" \
161 "</node>"
162
hsp_gain_to_volume(uint16_t gain)163 static pa_volume_t hsp_gain_to_volume(uint16_t gain) {
164 pa_volume_t volume = (pa_volume_t) ((
165 gain * PA_VOLUME_NORM
166 /* Round to closest by adding half the denominator */
167 + HSP_MAX_GAIN / 2
168 ) / HSP_MAX_GAIN);
169
170 if (volume > PA_VOLUME_NORM)
171 volume = PA_VOLUME_NORM;
172
173 return volume;
174 }
175
volume_to_hsp_gain(pa_volume_t volume)176 static uint16_t volume_to_hsp_gain(pa_volume_t volume) {
177 uint16_t gain = volume * HSP_MAX_GAIN / PA_VOLUME_NORM;
178
179 if (gain > HSP_MAX_GAIN)
180 gain = HSP_MAX_GAIN;
181
182 return gain;
183 }
184
is_peer_audio_gateway(pa_bluetooth_profile_t peer_profile)185 static bool is_peer_audio_gateway(pa_bluetooth_profile_t peer_profile) {
186 switch(peer_profile) {
187 case PA_BLUETOOTH_PROFILE_HFP_HF:
188 case PA_BLUETOOTH_PROFILE_HSP_HS:
189 return false;
190 case PA_BLUETOOTH_PROFILE_HFP_AG:
191 case PA_BLUETOOTH_PROFILE_HSP_AG:
192 return true;
193 default:
194 pa_assert_not_reached();
195 }
196 }
197
is_pulseaudio_audio_gateway(pa_bluetooth_profile_t peer_profile)198 static bool is_pulseaudio_audio_gateway(pa_bluetooth_profile_t peer_profile) {
199 return !is_peer_audio_gateway(peer_profile);
200 }
201
send_and_add_to_pending(pa_bluetooth_backend * backend,DBusMessage * m,DBusPendingCallNotifyFunction func,void * call_data)202 static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_backend *backend, DBusMessage *m,
203 DBusPendingCallNotifyFunction func, void *call_data) {
204
205 pa_dbus_pending *p;
206 DBusPendingCall *call;
207
208 pa_assert(backend);
209 pa_assert(m);
210
211 pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(backend->connection), m, &call, -1));
212
213 p = pa_dbus_pending_new(pa_dbus_connection_get(backend->connection), m, call, backend, call_data);
214 PA_LLIST_PREPEND(pa_dbus_pending, backend->pending, p);
215 dbus_pending_call_set_notify(call, func, p, NULL);
216
217 return p;
218 }
219
rfcomm_fmt_write(int fd,const char * fmt_line,const char * fmt_command,va_list ap)220 static void rfcomm_fmt_write(int fd, const char* fmt_line, const char *fmt_command, va_list ap)
221 {
222 size_t len;
223 char buf[512];
224 char command[512];
225
226 pa_vsnprintf(command, sizeof(command), fmt_command, ap);
227
228 pa_log_debug("RFCOMM >> %s", command);
229
230 len = pa_snprintf(buf, sizeof(buf), fmt_line, command);
231
232 /* we ignore any errors, it's not critical and real errors should
233 * be caught with the HANGUP and ERROR events handled above */
234
235 if ((size_t)write(fd, buf, len) != len)
236 pa_log_error("RFCOMM write error: %s", pa_cstrerror(errno));
237 }
238
239 /* The format of COMMAND line sent from HS to AG is COMMAND<cr> */
rfcomm_write_command(int fd,const char * fmt,...)240 static void rfcomm_write_command(int fd, const char *fmt, ...)
241 {
242 va_list ap;
243
244 va_start(ap, fmt);
245 rfcomm_fmt_write(fd, "%s\r", fmt, ap);
246 va_end(ap);
247 }
248
249 /* The format of RESPONSE line sent from AG to HS is <cr><lf>RESPONSE<cr><lf> */
rfcomm_write_response(int fd,const char * fmt,...)250 static void rfcomm_write_response(int fd, const char *fmt, ...)
251 {
252 va_list ap;
253
254 va_start(ap, fmt);
255 rfcomm_fmt_write(fd, "\r\n%s\r\n", fmt, ap);
256 va_end(ap);
257 }
258
sco_setsockopt_enable_bt_voice(pa_bluetooth_transport * t,int fd)259 static int sco_setsockopt_enable_bt_voice(pa_bluetooth_transport *t, int fd) {
260 /* the mSBC codec requires a special transparent eSCO connection */
261 struct bt_voice voice;
262
263 memset(&voice, 0, sizeof(voice));
264 voice.setting = BT_VOICE_TRANSPARENT;
265 if (setsockopt(fd, SOL_BLUETOOTH, BT_VOICE, &voice, sizeof(voice)) < 0) {
266 pa_log_error("sockopt(): %s", pa_cstrerror(errno));
267 return -1;
268 }
269 pa_log_info("Enabled BT_VOICE_TRANSPARENT connection for mSBC");
270 return 0;
271 }
272
sco_do_connect(pa_bluetooth_transport * t)273 static int sco_do_connect(pa_bluetooth_transport *t) {
274 pa_bluetooth_device *d = t->device;
275 struct sockaddr_sco addr;
276 socklen_t len;
277 int err, i;
278 int sock;
279 bdaddr_t src;
280 bdaddr_t dst;
281 const char *src_addr, *dst_addr;
282
283 src_addr = d->adapter->address;
284 dst_addr = d->address;
285
286 /* don't use ba2str to avoid -lbluetooth */
287 for (i = 5; i >= 0; i--, src_addr += 3)
288 src.b[i] = strtol(src_addr, NULL, 16);
289 for (i = 5; i >= 0; i--, dst_addr += 3)
290 dst.b[i] = strtol(dst_addr, NULL, 16);
291
292 sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
293 if (sock < 0) {
294 pa_log_error("socket(SEQPACKET, SCO) %s", pa_cstrerror(errno));
295 return -1;
296 }
297
298 len = sizeof(addr);
299 memset(&addr, 0, len);
300 addr.sco_family = AF_BLUETOOTH;
301 bacpy(&addr.sco_bdaddr, &src);
302
303 if (bind(sock, (struct sockaddr *) &addr, len) < 0) {
304 pa_log_error("bind(): %s", pa_cstrerror(errno));
305 goto fail_close;
306 }
307
308 if (t->setsockopt && t->setsockopt(t, sock) < 0)
309 goto fail_close;
310
311 memset(&addr, 0, len);
312 addr.sco_family = AF_BLUETOOTH;
313 bacpy(&addr.sco_bdaddr, &dst);
314
315 pa_log_info("doing connect");
316 err = connect(sock, (struct sockaddr *) &addr, len);
317 if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
318 pa_log_error("connect(): %s", pa_cstrerror(errno));
319 goto fail_close;
320 }
321 return sock;
322
323 fail_close:
324 close(sock);
325 return -1;
326 }
327
sco_do_accept(pa_bluetooth_transport * t)328 static int sco_do_accept(pa_bluetooth_transport *t) {
329 struct transport_data *trd = t->userdata;
330 struct sockaddr_sco addr;
331 socklen_t optlen;
332 int sock;
333
334 memset(&addr, 0, sizeof(addr));
335 optlen = sizeof(addr);
336
337 pa_log_info ("doing accept");
338 sock = accept(trd->sco_fd, (struct sockaddr *) &addr, &optlen);
339 if (sock < 0) {
340 if (errno != EAGAIN)
341 pa_log_error("accept(): %s", pa_cstrerror(errno));
342 goto fail;
343 }
344 return sock;
345
346 fail:
347 return -1;
348 }
349
sco_acquire_cb(pa_bluetooth_transport * t,bool optional,size_t * imtu,size_t * omtu)350 static int sco_acquire_cb(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) {
351 int sock;
352 socklen_t len;
353 int i;
354
355 if (optional)
356 sock = sco_do_accept(t);
357 else {
358 for (i = 0; i < SCO_RECONNECTION_COUNT; i++) {
359 sock = sco_do_connect(t);
360
361 if (sock < 0) {
362 pa_log_debug("err is %s and reconnection count is %d", pa_cstrerror(errno), i);
363 pa_msleep(300);
364 continue;
365 } else
366 break;
367 }
368 }
369
370 if (sock < 0)
371 goto fail;
372
373 /* The correct block size should take into account the SCO MTU from
374 * the Bluetooth adapter and (for adapters in the USB bus) the MxPS
375 * value from the Isoc USB endpoint in use by btusb and should be
376 * made available to userspace by the Bluetooth kernel subsystem.
377 *
378 * Set initial MTU to max known payload length of HCI packet
379 * in USB Alternate Setting 5 (144 bytes)
380 * See also pa_bluetooth_transport::last_read_size handling
381 * and comment about MTU size in bt_prepare_encoder_buffer()
382 */
383 if (imtu) *imtu = 144;
384 if (omtu) *omtu = 144;
385
386 if (t->device->autodetect_mtu) {
387 struct sco_options sco_opt;
388
389 len = sizeof(sco_opt);
390 memset(&sco_opt, 0, len);
391
392 if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0)
393 pa_log_warn("getsockopt(SCO_OPTIONS) failed, loading defaults");
394 else {
395 pa_log_debug("autodetected imtu = omtu = %u", sco_opt.mtu);
396 if (imtu) *imtu = sco_opt.mtu;
397 if (omtu) *omtu = sco_opt.mtu;
398 }
399 }
400
401 return sock;
402
403 fail:
404 return -1;
405 }
406
sco_release_cb(pa_bluetooth_transport * t)407 static void sco_release_cb(pa_bluetooth_transport *t) {
408 pa_log_info("Transport %s released", t->path);
409 /* device will close the SCO socket for us */
410 }
411
sco_transport_write(pa_bluetooth_transport * t,int fd,const void * buffer,size_t size,size_t write_mtu)412 static ssize_t sco_transport_write(pa_bluetooth_transport *t, int fd, const void* buffer, size_t size, size_t write_mtu) {
413 ssize_t l = 0;
414 size_t written = 0;
415 size_t write_size;
416
417 pa_assert(t);
418
419 /* since SCO setup is symmetric, fix write MTU to be size of last read packet */
420 if (t->last_read_size)
421 write_mtu = PA_MIN(t->last_read_size, write_mtu);
422
423 /* if encoder buffer has less data than required to make complete packet */
424 if (size < write_mtu)
425 return 0;
426
427 /* write out MTU sized chunks only */
428 while (written < size) {
429 write_size = PA_MIN(size - written, write_mtu);
430 if (write_size < write_mtu)
431 break;
432 l = pa_write(fd, buffer + written, write_size, &t->stream_write_type);
433 if (l < 0)
434 break;
435 written += l;
436 }
437
438 if (l < 0) {
439 if (errno == EAGAIN) {
440 /* Hmm, apparently the socket was not writable, give up for now */
441 pa_log_debug("Got EAGAIN on write() after POLLOUT, probably there is a temporary connection loss.");
442 /* Drain write buffer */
443 written = size;
444 } else if (errno == EINVAL && t->last_read_size == 0) {
445 /* Likely write_link_mtu is still wrong, retry after next successful read */
446 pa_log_debug("got write EINVAL, next successful read should fix MTU");
447 /* Drain write buffer */
448 written = size;
449 } else {
450 pa_log_error("Failed to write data to socket: %s", pa_cstrerror(errno));
451 /* Report error from write call */
452 return -1;
453 }
454 }
455
456 /* if too much data left discard it all */
457 if (size - written >= write_mtu) {
458 pa_log_warn("Wrote memory block to socket only partially! %lu written, discarding pending write size %lu larger than write_mtu %lu",
459 written, size, write_mtu);
460 /* Drain write buffer */
461 written = size;
462 }
463
464 return written;
465 }
466
sco_io_callback(pa_mainloop_api * io,pa_io_event * e,int fd,pa_io_event_flags_t events,void * userdata)467 static void sco_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
468 pa_bluetooth_transport *t = userdata;
469
470 pa_assert(io);
471 pa_assert(t);
472
473 if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) {
474 pa_log_error("error listening SCO connection: %s", pa_cstrerror(errno));
475 goto fail;
476 }
477
478 if (t->state != PA_BLUETOOTH_TRANSPORT_STATE_PLAYING) {
479 pa_log_info("SCO incoming connection: changing state to PLAYING");
480 pa_bluetooth_transport_set_state (t, PA_BLUETOOTH_TRANSPORT_STATE_PLAYING);
481 }
482
483 fail:
484 return;
485 }
486
sco_listen(pa_bluetooth_transport * t)487 static int sco_listen(pa_bluetooth_transport *t) {
488 struct transport_data *trd = t->userdata;
489 struct sockaddr_sco addr;
490 int sock, i;
491 bdaddr_t src;
492 const char *src_addr;
493
494 sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, BTPROTO_SCO);
495 if (sock < 0) {
496 pa_log_error("socket(SEQPACKET, SCO) %s", pa_cstrerror(errno));
497 return -1;
498 }
499
500 src_addr = t->device->adapter->address;
501
502 /* don't use ba2str to avoid -lbluetooth */
503 for (i = 5; i >= 0; i--, src_addr += 3)
504 src.b[i] = strtol(src_addr, NULL, 16);
505
506 /* Bind to local address */
507 memset(&addr, 0, sizeof(addr));
508 addr.sco_family = AF_BLUETOOTH;
509 bacpy(&addr.sco_bdaddr, &src);
510
511 if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
512 pa_log_error("bind(): %s", pa_cstrerror(errno));
513 goto fail_close;
514 }
515
516 pa_log_info ("doing listen");
517 if (listen(sock, 1) < 0) {
518 pa_log_error("listen(): %s", pa_cstrerror(errno));
519 goto fail_close;
520 }
521
522 trd->sco_fd = sock;
523 trd->sco_io = trd->mainloop->io_new(trd->mainloop, sock, PA_IO_EVENT_INPUT,
524 sco_io_callback, t);
525
526 return sock;
527
528 fail_close:
529 close(sock);
530 return -1;
531 }
532
register_profile_reply(DBusPendingCall * pending,void * userdata)533 static void register_profile_reply(DBusPendingCall *pending, void *userdata) {
534 DBusMessage *r;
535 pa_dbus_pending *p;
536 pa_bluetooth_backend *b;
537 pa_bluetooth_profile_t profile;
538
539 pa_assert(pending);
540 pa_assert_se(p = userdata);
541 pa_assert_se(b = p->context_data);
542 pa_assert_se(profile = (pa_bluetooth_profile_t)p->call_data);
543 pa_assert_se(r = dbus_pending_call_steal_reply(pending));
544
545 if (dbus_message_is_error(r, BLUEZ_ERROR_NOT_SUPPORTED)) {
546 pa_log_info("Couldn't register profile %s because it is disabled in BlueZ", pa_bluetooth_profile_to_string(profile));
547 profile_status_set(b->discovery, profile, PA_BLUETOOTH_PROFILE_STATUS_ACTIVE);
548 goto finish;
549 }
550
551 if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
552 pa_log_error(BLUEZ_PROFILE_MANAGER_INTERFACE ".RegisterProfile() failed: %s: %s", dbus_message_get_error_name(r),
553 pa_dbus_get_error_message(r));
554 profile_status_set(b->discovery, profile, PA_BLUETOOTH_PROFILE_STATUS_ACTIVE);
555 goto finish;
556 }
557
558 profile_status_set(b->discovery, profile, PA_BLUETOOTH_PROFILE_STATUS_REGISTERED);
559
560 finish:
561 dbus_message_unref(r);
562
563 PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p);
564 pa_dbus_pending_free(p);
565 }
566
register_profile(pa_bluetooth_backend * b,const char * object,const char * uuid,pa_bluetooth_profile_t profile)567 static void register_profile(pa_bluetooth_backend *b, const char *object, const char *uuid, pa_bluetooth_profile_t profile) {
568 DBusMessage *m;
569 DBusMessageIter i, d;
570 dbus_bool_t autoconnect;
571 dbus_uint16_t version, chan;
572
573 pa_assert(profile_status_get(b->discovery, profile) == PA_BLUETOOTH_PROFILE_STATUS_ACTIVE);
574
575 pa_log_debug("Registering Profile %s %s", pa_bluetooth_profile_to_string(profile), uuid);
576
577 pa_assert_se(m = dbus_message_new_method_call(BLUEZ_SERVICE, "/org/bluez", BLUEZ_PROFILE_MANAGER_INTERFACE, "RegisterProfile"));
578
579 dbus_message_iter_init_append(m, &i);
580 pa_assert_se(dbus_message_iter_append_basic(&i, DBUS_TYPE_OBJECT_PATH, &object));
581 pa_assert_se(dbus_message_iter_append_basic(&i, DBUS_TYPE_STRING, &uuid));
582 dbus_message_iter_open_container(&i, DBUS_TYPE_ARRAY,
583 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
584 DBUS_TYPE_STRING_AS_STRING
585 DBUS_TYPE_VARIANT_AS_STRING
586 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
587 &d);
588 if (pa_bluetooth_uuid_is_hsp_hs(uuid)) {
589 /* In the headset role, the connection will only be initiated from the remote side */
590 autoconnect = 0;
591 pa_dbus_append_basic_variant_dict_entry(&d, "AutoConnect", DBUS_TYPE_BOOLEAN, &autoconnect);
592 chan = HSP_HS_DEFAULT_CHANNEL;
593 pa_dbus_append_basic_variant_dict_entry(&d, "Channel", DBUS_TYPE_UINT16, &chan);
594 /* HSP version 1.2 */
595 version = 0x0102;
596 pa_dbus_append_basic_variant_dict_entry(&d, "Version", DBUS_TYPE_UINT16, &version);
597 }
598 dbus_message_iter_close_container(&i, &d);
599
600 profile_status_set(b->discovery, profile, PA_BLUETOOTH_PROFILE_STATUS_REGISTERING);
601 send_and_add_to_pending(b, m, register_profile_reply, (void *)profile);
602 }
603
transport_put(pa_bluetooth_transport * t)604 static void transport_put(pa_bluetooth_transport *t)
605 {
606 pa_bluetooth_transport_put(t);
607
608 pa_log_debug("Transport %s available for profile %s", t->path, pa_bluetooth_profile_to_string(t->profile));
609 }
610
611 static pa_volume_t set_sink_volume(pa_bluetooth_transport *t, pa_volume_t volume);
612 static pa_volume_t set_source_volume(pa_bluetooth_transport *t, pa_volume_t volume);
613
hfp_rfcomm_handle(int fd,pa_bluetooth_transport * t,const char * buf)614 static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf)
615 {
616 struct hfp_config *c = t->config;
617 struct transport_data *trd = t->userdata;
618 pa_bluetooth_backend *b = trd->backend;
619 int indicator, mode, val;
620 char *str;
621 const char *r;
622 size_t len;
623 const char *state = NULL;
624
625 /* first-time initialize selected codec to CVSD */
626 if (c->selected_codec == 0)
627 c->selected_codec = 1;
628
629 /* stateful negotiation */
630 if (c->state == 0 && sscanf(buf, "AT+BRSF=%d", &val) == 1) {
631 c->capabilities = val;
632 pa_log_info("HFP capabilities returns 0x%x", val);
633 rfcomm_write_response(fd, "+BRSF: %d", hfp_features);
634 c->supports_indicators = !!(1 << HFP_HF_INDICATORS);
635 c->state = 1;
636
637 return true;
638 } else if (pa_startswith(buf, "AT+BIA=")) {
639 /* Indicators start with index 1 and follow the order of the AT+CIND=? response */
640
641 str = pa_xstrdup(buf + 7);
642 for (indicator = 1; (r = pa_split_in_place(str, ",\r\n", &len, &state)); indicator++) {
643 /* Ignore updates to mandatory indicators which are always ON */
644 if (indicator == CIND_CALL_INDICATOR
645 || indicator == CIND_CALL_SETUP_INDICATOR
646 || indicator == CIND_CALL_HELD_INDICATOR)
647 continue;
648
649 /* Indicators may have no value and should be skipped */
650 if (len == 0)
651 continue;
652
653 if (len == 1 && r[0] == '1')
654 b->cind_enabled_indicators |= (1 << indicator);
655 else if (len == 1 && r[0] == '0')
656 b->cind_enabled_indicators &= ~(1 << indicator);
657 else {
658 pa_log_error("Unable to parse indicator of AT+BIA command: %s", buf);
659 rfcomm_write_response(fd, "ERROR");
660 pa_xfree(str);
661 return false;
662 }
663 }
664 pa_xfree(str);
665
666 return true;
667 } else if (pa_startswith(buf, "AT+BAC=")) {
668 c->support_msbc = false;
669
670 /* check if codec id 2 (mSBC) is in the list of supported codecs */
671 str = pa_xstrdup(buf + 7);
672 while ((r = pa_split_in_place(str, ",\r\n", &len, &state))) {
673 if (len == 1 && r[0] == '2') {
674 c->support_msbc = true;
675 break;
676 }
677 }
678 pa_xfree(str);
679
680 c->support_codec_negotiation = true;
681
682 if (c->state == 1) {
683 /* initial list of codecs supported by HF */
684 } else {
685 /* HF sent updated list of codecs */
686 }
687
688 /* no state change */
689
690 return true;
691 } else if (c->state == 1 && pa_startswith(buf, "AT+CIND=?")) {
692 /* UPower backend available, declare support for more indicators */
693 if (b->upower) {
694 rfcomm_write_response(fd, "+CIND: "
695 MANDATORY_CALL_INDICATORS ","
696 "(\"service\",(0-1)),"
697 "(\"battchg\",(0-5))");
698
699 /* Minimal indicators supported without any additional backend */
700 } else {
701 rfcomm_write_response(fd, "+CIND: "
702 MANDATORY_CALL_INDICATORS ","
703 "(\"service\",(0-1))");
704 }
705 c->state = 2;
706
707 return true;
708 } else if (c->state == 2 && pa_startswith(buf, "AT+CIND?")) {
709 if (b->upower)
710 rfcomm_write_response(fd, "+CIND: 0,0,0,0,%u", pa_upower_get_battery_level(b->upower));
711 else
712 rfcomm_write_response(fd, "+CIND: 0,0,0,0");
713 c->state = 3;
714
715 return true;
716 } else if ((c->state == 2 || c->state == 3) && pa_startswith(buf, "AT+CMER=")) {
717 if (sscanf(buf, "AT+CMER=%d,%*d,%*d,%d", &mode, &val) == 2) {
718 /* Bluetooth HFP spec only defines mode == 3 */
719 if (mode != 3)
720 pa_log_warn("Unexpected mode for AT+CMER: %d", mode);
721
722 /* Configure CMER event reporting */
723 b->cmer_indicator_reporting_enabled = !!val;
724
725 pa_log_debug("Event indications enabled? %s", pa_yes_no(val));
726
727 rfcomm_write_response(fd, "OK");
728 }
729 else {
730 pa_log_error("Unable to parse AT+CMER command: %s", buf);
731 rfcomm_write_response(fd, "ERROR");
732 return false;
733 }
734
735 if (c->support_codec_negotiation) {
736 if (c->support_msbc && pa_bluetooth_discovery_get_enable_msbc(t->device->discovery)) {
737 rfcomm_write_response(fd, "+BCS:2");
738 c->state = 4;
739 } else {
740 rfcomm_write_response(fd, "+BCS:1");
741 c->state = 4;
742 }
743 } else {
744 c->state = 5;
745 pa_bluetooth_transport_reconfigure(t, pa_bluetooth_get_hf_codec("CVSD"), sco_transport_write, NULL);
746 transport_put(t);
747 }
748
749 return false;
750 } else if (sscanf(buf, "AT+BCS=%d", &val)) {
751 if (val == 1) {
752 pa_bluetooth_transport_reconfigure(t, pa_bluetooth_get_hf_codec("CVSD"), sco_transport_write, NULL);
753 } else if (val == 2 && pa_bluetooth_discovery_get_enable_msbc(t->device->discovery)) {
754 pa_bluetooth_transport_reconfigure(t, pa_bluetooth_get_hf_codec("mSBC"), sco_transport_write, sco_setsockopt_enable_bt_voice);
755 } else {
756 pa_assert_fp(val != 1 && val != 2);
757 rfcomm_write_response(fd, "ERROR");
758 return false;
759 }
760
761 c->selected_codec = val;
762
763 if (c->state == 4) {
764 c->state = 5;
765 pa_log_info("HFP negotiated codec %s", t->bt_codec->name);
766 transport_put(t);
767 }
768
769 return true;
770 } else if (c->supports_indicators && pa_startswith(buf, "AT+BIND=?")) {
771 // Support battery indication
772 rfcomm_write_response(fd, "+BIND: (2)");
773 return true;
774 } else if (c->supports_indicators && pa_startswith(buf, "AT+BIND?")) {
775 // Battery indication is enabled
776 rfcomm_write_response(fd, "+BIND: 2,1");
777 return true;
778 } else if (c->supports_indicators && pa_startswith(buf, "AT+BIND=")) {
779 // If this comma-separated list contains `2`, the HF is
780 // able to report values for the battery indicator.
781 return true;
782 } else if (c->supports_indicators && sscanf(buf, "AT+BIEV=%u,%u", &indicator, &val)) {
783 switch (indicator) {
784 case 2:
785 pa_log_notice("Battery Level: %d%%", val);
786 if (val < 0 || val > 100) {
787 pa_log_error("Battery HF indicator %d out of [0, 100] range", val);
788 rfcomm_write_response(fd, "ERROR");
789 return false;
790 }
791 pa_bluetooth_device_report_battery_level(t->device, val, "HFP 1.7 HF indicator");
792 break;
793 default:
794 pa_log_error("Unknown HF indicator %u", indicator);
795 rfcomm_write_response(fd, "ERROR");
796 return false;
797 }
798 return true;
799 } if (c->state == 4) {
800 /* the ack for the codec setting may take a while. we need
801 * to reply OK to everything else until then */
802 return true;
803 }
804
805 /* if we get here, negotiation should be complete */
806 if (c->state != 5) {
807 pa_log_error("HFP negotiation failed in state %d with inbound %s\n",
808 c->state, buf);
809 rfcomm_write_response(fd, "ERROR");
810 return false;
811 }
812
813 /*
814 * once we're fully connected, just reply OK to everything
815 * it will just be the headset sending the occasional status
816 * update, but we process only the ones we care about
817 */
818 return true;
819 }
820
get_rfcomm_fd(pa_bluetooth_discovery * discovery)821 static int get_rfcomm_fd(pa_bluetooth_discovery *discovery) {
822 struct pa_bluetooth_transport *t;
823 struct transport_data *trd = NULL;
824 void *state = NULL;
825
826 /* Find RFCOMM transport by checking if a HSP or HFP profile transport is available */
827 while ((t = pa_hashmap_iterate(pa_bluetooth_discovery_get_transports(discovery), &state, NULL))) {
828 /* Skip non-connected transports */
829 if (!t || t->state == PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED) {
830 continue;
831 }
832
833 /* Break when an RFCOMM capable transport profile is available */
834 if (t->profile == PA_BLUETOOTH_PROFILE_HFP_HF) {
835 trd = t->userdata;
836 break;
837 }
838 }
839
840 /* Skip if RFCOMM channel is not available yet */
841 if (!trd) {
842 pa_log_info("RFCOMM not available yet, skipping notification");
843 return -1;
844 }
845
846 return trd->rfcomm_fd;
847 }
848
host_battery_level_changed_cb(pa_bluetooth_discovery * y,const pa_upower_backend * u,pa_bluetooth_backend * b)849 static pa_hook_result_t host_battery_level_changed_cb(pa_bluetooth_discovery *y, const pa_upower_backend *u, pa_bluetooth_backend *b) {
850 int rfcomm_fd;
851
852 pa_assert(y);
853 pa_assert(u);
854 pa_assert(b);
855
856 /* Get RFCOMM channel if available */
857 rfcomm_fd = get_rfcomm_fd(y);
858 if (rfcomm_fd < 0)
859 return PA_HOOK_OK;
860
861 /* Notify HF about AG battery level change over RFCOMM */
862 if (b->cmer_indicator_reporting_enabled && (b->cind_enabled_indicators & (1 << CIND_BATT_CHG_INDICATOR))) {
863 rfcomm_write_response(rfcomm_fd, "+CIEV: %d,%d", CIND_BATT_CHG_INDICATOR, u->battery_level);
864 pa_log_debug("HG notified of AG's battery level change");
865 /* Skip notification if indicator is disabled or event reporting is completely disabled */
866 } else
867 pa_log_debug("Battery level change indicator disabled, skipping notification");
868
869 return PA_HOOK_OK;
870 }
871
rfcomm_io_callback(pa_mainloop_api * io,pa_io_event * e,int fd,pa_io_event_flags_t events,void * userdata)872 static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
873 pa_bluetooth_transport *t = userdata;
874 struct transport_data *trd = t->userdata;
875 pa_bluetooth_backend *b = trd->backend;
876 int i;
877
878 pa_assert(io);
879 pa_assert(t);
880
881 if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) {
882 pa_log_info("Lost RFCOMM connection.");
883 // TODO: Keep track of which profile is the current battery provider,
884 // only deregister if it is us currently providing these levels.
885 // (Also helpful to fill the 'Source' property)
886 // We might also move this to Profile1::RequestDisconnection
887 pa_bluetooth_device_deregister_battery(t->device);
888 goto fail;
889 }
890
891 if (events & PA_IO_EVENT_INPUT) {
892 char rbuf[512];
893 ssize_t len;
894 int gain, dummy;
895 bool do_reply = false;
896 int vendor, product, version, features;
897 char *buf = rbuf;
898 int num;
899
900 len = pa_read(fd, rbuf, 511, NULL);
901 if (len < 0) {
902 pa_log_error("RFCOMM read error: %s", pa_cstrerror(errno));
903 goto fail;
904 }
905 rbuf[len] = 0;
906 pa_log_debug("RFCOMM << %s", rbuf);
907
908 while (buf[0]) {
909 /* There are only four HSP AT commands:
910 * AT+VGS=value: value between 0 and 15, sent by the HS to AG to set the speaker gain.
911 * +VGS=value is sent by AG to HS as a response to an AT+VGS command or when the gain
912 * is changed on the AG side.
913 * AT+VGM=value: value between 0 and 15, sent by the HS to AG to set the microphone gain.
914 * +VGM=value is sent by AG to HS as a response to an AT+VGM command or when the gain
915 * is changed on the AG side.
916 * AT+CKPD=200: Sent by HS when headset button is pressed.
917 * RING: Sent by AG to HS to notify of an incoming call. It can safely be ignored because
918 * it does not expect a reply. */
919 if (sscanf(buf, "AT+VGS=%d", &gain) == 1 || sscanf(buf, "\r\n+VGM%*[=:]%d\r\n", &gain) == 1) {
920 if (!t->set_sink_volume) {
921 pa_log_debug("HS/HF peer supports speaker gain control");
922 t->set_sink_volume = set_sink_volume;
923 }
924
925 t->sink_volume = hsp_gain_to_volume(gain);
926 pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SINK_VOLUME_CHANGED), t);
927 do_reply = true;
928
929 } else if (sscanf(buf, "AT+VGM=%d", &gain) == 1 || sscanf(buf, "\r\n+VGS%*[=:]%d\r\n", &gain) == 1) {
930 if (!t->set_source_volume) {
931 pa_log_debug("HS/HF peer supports microphone gain control");
932 t->set_source_volume = set_source_volume;
933 }
934
935 t->source_volume = hsp_gain_to_volume(gain);
936 pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SOURCE_VOLUME_CHANGED), t);
937 do_reply = true;
938 } else if (sscanf(buf, "AT+CKPD=%d", &dummy) == 1) {
939 do_reply = true;
940 } else if (sscanf(buf, "AT+XAPL=%04x-%04x-%04x,%d", &vendor, &product, &version, &features) == 4) {
941 if (features & 0x2)
942 /* claim, that we support battery status reports */
943 rfcomm_write_response(fd, "+XAPL=iPhone,6");
944 do_reply = true;
945 } else if (sscanf(buf, "AT+IPHONEACCEV=%d", &num) == 1) {
946 char *substr = buf, *keystr;
947 int key, val, i;
948
949 do_reply = true;
950
951 for (i = 0; i < num; ++i) {
952 keystr = strchr(substr, ',');
953 if (!keystr) {
954 pa_log_warn("%s misses key for argument #%d", buf, i);
955 do_reply = false;
956 break;
957 }
958 keystr++;
959 substr = strchr(keystr, ',');
960 if (!substr) {
961 pa_log_warn("%s misses value for argument #%d", buf, i);
962 do_reply = false;
963 break;
964 }
965 substr++;
966
967 key = atoi(keystr);
968 val = atoi(substr);
969
970 switch (key) {
971 case 1:
972 pa_log_notice("Battery Level: %d0%%", val + 1);
973 pa_bluetooth_device_report_battery_level(t->device, (val + 1) * 10, "Apple accessory indication");
974 break;
975 case 2:
976 pa_log_notice("Dock Status: %s", val ? "docked" : "undocked");
977 break;
978 default:
979 pa_log_debug("Unexpected IPHONEACCEV key %#x", key);
980 break;
981 }
982 }
983 if (!do_reply)
984 rfcomm_write_response(fd, "ERROR");
985 } else if (t->config) { /* t->config is only non-null for hfp profile */
986 do_reply = hfp_rfcomm_handle(fd, t, buf);
987 } else {
988 rfcomm_write_response(fd, "ERROR");
989 do_reply = false;
990 }
991
992 if (do_reply)
993 rfcomm_write_response(fd, "OK");
994
995 if (buf[0] == '\r') /* in case it is the command with format \r\nCOMMAND\r\n, skip the starting \r */
996 buf = buf + 1;
997
998 buf = strstr(buf, "\r"); /* try to find the next AT command in the buf */
999 if (!buf)
1000 break;
1001 else if (buf[1] == '\n')
1002 buf = buf + 2; /* skip \r\n */
1003 else
1004 buf = buf + 1; /* skip \r */
1005 }
1006 }
1007
1008 return;
1009
1010 fail:
1011 /* Service Connection lost, reset indicators and event reporting to default values */
1012 b->cmer_indicator_reporting_enabled = false;
1013 for (i = 1; i < CIND_INDICATOR_MAX; i++)
1014 b->cind_enabled_indicators |= (1 << i);
1015
1016 pa_bluetooth_transport_unlink(t);
1017 pa_bluetooth_transport_free(t);
1018 }
1019
transport_destroy(pa_bluetooth_transport * t)1020 static void transport_destroy(pa_bluetooth_transport *t) {
1021 struct transport_data *trd = t->userdata;
1022
1023 if (trd->sco_io) {
1024 trd->mainloop->io_free(trd->sco_io);
1025 shutdown(trd->sco_fd, SHUT_RDWR);
1026 close (trd->sco_fd);
1027 }
1028
1029 trd->mainloop->io_free(trd->rfcomm_io);
1030 shutdown(trd->rfcomm_fd, SHUT_RDWR);
1031 close (trd->rfcomm_fd);
1032
1033 pa_xfree(trd);
1034 }
1035
set_sink_volume(pa_bluetooth_transport * t,pa_volume_t volume)1036 static pa_volume_t set_sink_volume(pa_bluetooth_transport *t, pa_volume_t volume) {
1037 struct transport_data *trd = t->userdata;
1038 uint16_t gain = volume_to_hsp_gain(volume);
1039
1040 /* Propagate rounding and bound checks */
1041 volume = hsp_gain_to_volume(gain);
1042
1043 if (t->sink_volume == volume)
1044 return volume;
1045
1046 t->sink_volume = volume;
1047
1048 /* If we are in the AG role, we send an unsolicited result-code to the headset
1049 * to change the speaker gain. In the HS role, source and sink are swapped,
1050 * so in this case we notify the AG that the microphone gain has changed
1051 * by sending a command. */
1052 if (is_pulseaudio_audio_gateway(t->profile)) {
1053 rfcomm_write_response(trd->rfcomm_fd, "+VGS=%d", gain);
1054 } else {
1055 rfcomm_write_command(trd->rfcomm_fd, "AT+VGM=%d", gain);
1056 }
1057
1058 return volume;
1059 }
1060
set_source_volume(pa_bluetooth_transport * t,pa_volume_t volume)1061 static pa_volume_t set_source_volume(pa_bluetooth_transport *t, pa_volume_t volume) {
1062 struct transport_data *trd = t->userdata;
1063 uint16_t gain = volume_to_hsp_gain(volume);
1064
1065 /* Propagate rounding and bound checks */
1066 volume = hsp_gain_to_volume(gain);
1067
1068 if (t->source_volume == volume)
1069 return volume;
1070
1071 t->source_volume = volume;
1072
1073 /* If we are in the AG role, we send an unsolicited result-code to the headset
1074 * to change the microphone gain. In the HS role, source and sink are swapped,
1075 * so in this case we notify the AG that the speaker gain has changed
1076 * by sending a command. */
1077 if (is_pulseaudio_audio_gateway(t->profile)) {
1078 rfcomm_write_response(trd->rfcomm_fd, "+VGM=%d", gain);
1079 } else {
1080 rfcomm_write_command(trd->rfcomm_fd, "AT+VGS=%d", gain);
1081 }
1082
1083 return volume;
1084 }
1085
profile_new_connection(DBusConnection * conn,DBusMessage * m,void * userdata)1086 static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m, void *userdata) {
1087 pa_bluetooth_backend *b = userdata;
1088 pa_bluetooth_device *d;
1089 pa_bluetooth_transport *t;
1090 pa_bluetooth_profile_t p;
1091 DBusMessage *r;
1092 int fd;
1093 const char *sender, *path, PA_UNUSED *handler;
1094 DBusMessageIter arg_i;
1095 char *pathfd;
1096 struct transport_data *trd;
1097
1098 if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oha{sv}")) {
1099 pa_log_error("Invalid signature found in NewConnection");
1100 goto fail;
1101 }
1102
1103 handler = dbus_message_get_path(m);
1104 if (pa_streq(handler, HSP_AG_PROFILE)) {
1105 p = PA_BLUETOOTH_PROFILE_HSP_HS;
1106 } else if (pa_streq(handler, HSP_HS_PROFILE)) {
1107 p = PA_BLUETOOTH_PROFILE_HSP_AG;
1108 } else if (pa_streq(handler, HFP_AG_PROFILE)) {
1109 p = PA_BLUETOOTH_PROFILE_HFP_HF;
1110 } else {
1111 pa_log_error("Invalid handler");
1112 goto fail;
1113 }
1114
1115 pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_OBJECT_PATH);
1116 dbus_message_iter_get_basic(&arg_i, &path);
1117
1118 d = pa_bluetooth_discovery_get_device_by_path(b->discovery, path);
1119 if (d == NULL) {
1120 pa_log_error("Device doesn't exist for %s", path);
1121 goto fail;
1122 }
1123
1124 if (d->enable_hfp_hf) {
1125 if (p == PA_BLUETOOTH_PROFILE_HSP_HS && pa_hashmap_get(d->uuids, PA_BLUETOOTH_UUID_HFP_HF)) {
1126 /* If peer connecting to HSP Audio Gateway supports HFP HF profile
1127 * reject this connection to force it to connect to HSP Audio Gateway instead.
1128 */
1129 pa_log_info("HFP HF enabled in native backend and is supported by peer, rejecting HSP HS peer connection");
1130 goto fail;
1131 }
1132 }
1133
1134 pa_assert_se(dbus_message_iter_next(&arg_i));
1135
1136 pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_UNIX_FD);
1137 dbus_message_iter_get_basic(&arg_i, &fd);
1138
1139 pa_log_debug("dbus: NewConnection path=%s, fd=%d, profile %s", path, fd,
1140 pa_bluetooth_profile_to_string(p));
1141
1142 sender = dbus_message_get_sender(m);
1143
1144 pathfd = pa_sprintf_malloc ("%s/fd%d", path, fd);
1145 t = pa_bluetooth_transport_new(d, sender, pathfd, p, NULL,
1146 p == PA_BLUETOOTH_PROFILE_HFP_HF ?
1147 sizeof(struct hfp_config) : 0);
1148 pa_xfree(pathfd);
1149
1150 t->acquire = sco_acquire_cb;
1151 t->release = sco_release_cb;
1152 t->destroy = transport_destroy;
1153
1154 /* If PA is the HF/HS we are in control of volume attenuation and
1155 * can always send volume commands (notifications) to keep the peer
1156 * updated on actual volume value.
1157 *
1158 * If the peer is the HF/HS it is responsible for attenuation of both
1159 * speaker and microphone gain.
1160 * On HFP speaker/microphone gain support is reported by bit 4 in the
1161 * `AT+BRSF=` command. Since it isn't explicitly documented whether this
1162 * applies to speaker or microphone gain but the peer is required to send
1163 * an initial value with `AT+VG[MS]=` either callback is hooked
1164 * independently as soon as this command is received.
1165 * On HSP this is not specified and is assumed to be dynamic for both
1166 * speaker and microphone.
1167 */
1168 if (is_peer_audio_gateway(p)) {
1169 t->set_sink_volume = set_sink_volume;
1170 t->set_source_volume = set_source_volume;
1171 }
1172
1173 pa_bluetooth_transport_reconfigure(t, pa_bluetooth_get_hf_codec("CVSD"), sco_transport_write, NULL);
1174
1175 trd = pa_xnew0(struct transport_data, 1);
1176 trd->rfcomm_fd = fd;
1177 trd->mainloop = b->core->mainloop;
1178 trd->backend = b;
1179 trd->rfcomm_io = trd->mainloop->io_new(b->core->mainloop, fd, PA_IO_EVENT_INPUT,
1180 rfcomm_io_callback, t);
1181 t->userdata = trd;
1182
1183 sco_listen(t);
1184
1185 if (p != PA_BLUETOOTH_PROFILE_HFP_HF)
1186 transport_put(t);
1187
1188 pa_assert_se(r = dbus_message_new_method_return(m));
1189
1190 return r;
1191
1192 fail:
1193 pa_assert_se(r = dbus_message_new_error(m, BLUEZ_ERROR_INVALID_ARGUMENTS, "Unable to handle new connection"));
1194 return r;
1195 }
1196
profile_request_disconnection(DBusConnection * conn,DBusMessage * m,void * userdata)1197 static DBusMessage *profile_request_disconnection(DBusConnection *conn, DBusMessage *m, void *userdata) {
1198 DBusMessage *r;
1199
1200 pa_assert_se(r = dbus_message_new_method_return(m));
1201
1202 return r;
1203 }
1204
profile_handler(DBusConnection * c,DBusMessage * m,void * userdata)1205 static DBusHandlerResult profile_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
1206 pa_bluetooth_backend *b = userdata;
1207 DBusMessage *r = NULL;
1208 const char *path, *interface, *member;
1209
1210 pa_assert(b);
1211
1212 path = dbus_message_get_path(m);
1213 interface = dbus_message_get_interface(m);
1214 member = dbus_message_get_member(m);
1215
1216 pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
1217
1218 if (!pa_streq(path, HSP_AG_PROFILE) && !pa_streq(path, HSP_HS_PROFILE)
1219 && !pa_streq(path, HFP_AG_PROFILE))
1220 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1221
1222 if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) {
1223 const char *xml = PROFILE_INTROSPECT_XML;
1224
1225 pa_assert_se(r = dbus_message_new_method_return(m));
1226 pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
1227
1228 } else if (dbus_message_is_method_call(m, BLUEZ_PROFILE_INTERFACE, "Release")) {
1229 pa_log_debug("Release not handled");
1230 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1231 } else if (dbus_message_is_method_call(m, BLUEZ_PROFILE_INTERFACE, "RequestDisconnection")) {
1232 r = profile_request_disconnection(c, m, userdata);
1233 } else if (dbus_message_is_method_call(m, BLUEZ_PROFILE_INTERFACE, "NewConnection"))
1234 r = profile_new_connection(c, m, userdata);
1235 else
1236 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1237
1238 if (r) {
1239 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(b->connection), r, NULL));
1240 dbus_message_unref(r);
1241 }
1242
1243 return DBUS_HANDLER_RESULT_HANDLED;
1244 }
1245
adapter_uuids_changed_cb(pa_bluetooth_discovery * y,const pa_bluetooth_adapter * a,pa_bluetooth_backend * b)1246 static pa_hook_result_t adapter_uuids_changed_cb(pa_bluetooth_discovery *y, const pa_bluetooth_adapter *a, pa_bluetooth_backend *b) {
1247 pa_assert(y);
1248 pa_assert(a);
1249 pa_assert(b);
1250
1251 if (profile_status_get(y, PA_BLUETOOTH_PROFILE_HSP_HS) == PA_BLUETOOTH_PROFILE_STATUS_ACTIVE &&
1252 !pa_hashmap_get(a->uuids, PA_BLUETOOTH_UUID_HSP_AG))
1253 register_profile(b, HSP_AG_PROFILE, PA_BLUETOOTH_UUID_HSP_AG, PA_BLUETOOTH_PROFILE_HSP_HS);
1254
1255 if (profile_status_get(y, PA_BLUETOOTH_PROFILE_HSP_AG) == PA_BLUETOOTH_PROFILE_STATUS_ACTIVE &&
1256 !pa_hashmap_get(a->uuids, PA_BLUETOOTH_UUID_HSP_HS))
1257 register_profile(b, HSP_HS_PROFILE, PA_BLUETOOTH_UUID_HSP_HS, PA_BLUETOOTH_PROFILE_HSP_AG);
1258
1259 if (profile_status_get(y, PA_BLUETOOTH_PROFILE_HFP_HF) == PA_BLUETOOTH_PROFILE_STATUS_ACTIVE &&
1260 !pa_hashmap_get(a->uuids, PA_BLUETOOTH_UUID_HFP_AG))
1261 register_profile(b, HFP_AG_PROFILE, PA_BLUETOOTH_UUID_HFP_AG, PA_BLUETOOTH_PROFILE_HFP_HF);
1262
1263 return PA_HOOK_OK;
1264 }
1265
profile_init(pa_bluetooth_backend * b,pa_bluetooth_profile_t profile)1266 static void profile_init(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile) {
1267 static const DBusObjectPathVTable vtable_profile = {
1268 .message_function = profile_handler,
1269 };
1270 const char *object_name;
1271 const char *uuid;
1272
1273 pa_assert(b);
1274
1275 switch (profile) {
1276 case PA_BLUETOOTH_PROFILE_HSP_HS:
1277 object_name = HSP_AG_PROFILE;
1278 uuid = PA_BLUETOOTH_UUID_HSP_AG;
1279 break;
1280 case PA_BLUETOOTH_PROFILE_HSP_AG:
1281 object_name = HSP_HS_PROFILE;
1282 uuid = PA_BLUETOOTH_UUID_HSP_HS;
1283 break;
1284 case PA_BLUETOOTH_PROFILE_HFP_HF:
1285 object_name = HFP_AG_PROFILE;
1286 uuid = PA_BLUETOOTH_UUID_HFP_AG;
1287 break;
1288 default:
1289 pa_assert_not_reached();
1290 break;
1291 }
1292
1293 pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(b->connection), object_name, &vtable_profile, b));
1294
1295 profile_status_set(b->discovery, profile, PA_BLUETOOTH_PROFILE_STATUS_ACTIVE);
1296 register_profile(b, object_name, uuid, profile);
1297 }
1298
profile_done(pa_bluetooth_backend * b,pa_bluetooth_profile_t profile)1299 static void profile_done(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile) {
1300 pa_assert(b);
1301
1302 profile_status_set(b->discovery, profile, PA_BLUETOOTH_PROFILE_STATUS_INACTIVE);
1303
1304 switch (profile) {
1305 case PA_BLUETOOTH_PROFILE_HSP_HS:
1306 dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HSP_AG_PROFILE);
1307 break;
1308 case PA_BLUETOOTH_PROFILE_HSP_AG:
1309 dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HSP_HS_PROFILE);
1310 break;
1311 case PA_BLUETOOTH_PROFILE_HFP_HF:
1312 dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HFP_AG_PROFILE);
1313 break;
1314 default:
1315 pa_assert_not_reached();
1316 break;
1317 }
1318 }
1319
native_backend_apply_profile_registration_change(pa_bluetooth_backend * native_backend,bool enable_shared_profiles)1320 static void native_backend_apply_profile_registration_change(pa_bluetooth_backend *native_backend, bool enable_shared_profiles) {
1321 if (enable_shared_profiles) {
1322 profile_init(native_backend, PA_BLUETOOTH_PROFILE_HSP_AG);
1323 if (native_backend->enable_hfp_hf)
1324 profile_init(native_backend, PA_BLUETOOTH_PROFILE_HFP_HF);
1325 } else {
1326 profile_done(native_backend, PA_BLUETOOTH_PROFILE_HSP_AG);
1327 if (native_backend->enable_hfp_hf)
1328 profile_done(native_backend, PA_BLUETOOTH_PROFILE_HFP_HF);
1329 }
1330 }
1331
pa_bluetooth_native_backend_enable_shared_profiles(pa_bluetooth_backend * native_backend,bool enable)1332 void pa_bluetooth_native_backend_enable_shared_profiles(pa_bluetooth_backend *native_backend, bool enable) {
1333
1334 if (enable == native_backend->enable_shared_profiles)
1335 return;
1336
1337 native_backend_apply_profile_registration_change(native_backend, enable);
1338
1339 native_backend->enable_shared_profiles = enable;
1340 }
1341
pa_bluetooth_native_backend_new(pa_core * c,pa_bluetooth_discovery * y,bool enable_shared_profiles)1342 pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_discovery *y, bool enable_shared_profiles) {
1343 pa_bluetooth_backend *backend;
1344 DBusError err;
1345 int i;
1346
1347 pa_log_debug("Bluetooth Headset Backend API support using the native backend");
1348
1349 backend = pa_xnew0(pa_bluetooth_backend, 1);
1350 backend->core = c;
1351
1352 dbus_error_init(&err);
1353 if (!(backend->connection = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &err))) {
1354 pa_log("Failed to get D-Bus connection: %s", err.message);
1355 dbus_error_free(&err);
1356 pa_xfree(backend);
1357 return NULL;
1358 }
1359
1360 backend->discovery = y;
1361 backend->enable_shared_profiles = enable_shared_profiles;
1362 backend->enable_hfp_hf = pa_bluetooth_discovery_get_enable_native_hfp_hf(y);
1363 backend->enable_hsp_hs = pa_bluetooth_discovery_get_enable_native_hsp_hs(y);
1364
1365 backend->adapter_uuids_changed_slot =
1366 pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_ADAPTER_UUIDS_CHANGED), PA_HOOK_NORMAL,
1367 (pa_hook_cb_t) adapter_uuids_changed_cb, backend);
1368
1369 backend->host_battery_level_changed_slot =
1370 pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_HOST_BATTERY_LEVEL_CHANGED), PA_HOOK_NORMAL,
1371 (pa_hook_cb_t) host_battery_level_changed_cb, backend);
1372
1373 if (!backend->enable_hsp_hs && !backend->enable_hfp_hf)
1374 pa_log_warn("Both HSP HS and HFP HF bluetooth profiles disabled in native backend. Native backend will not register for headset connections.");
1375
1376 if (backend->enable_hsp_hs)
1377 profile_init(backend, PA_BLUETOOTH_PROFILE_HSP_HS);
1378
1379 if (backend->enable_shared_profiles)
1380 native_backend_apply_profile_registration_change(backend, true);
1381
1382 backend->upower = pa_upower_backend_new(c, y);
1383
1384 /* All CIND indicators are enabled by default until overriden by AT+BIA */
1385 for (i = 1; i < CIND_INDICATOR_MAX; i++)
1386 backend->cind_enabled_indicators |= (1 << i);
1387
1388 /* While all CIND indicators are enabled, event reporting is not enabled by default */
1389 backend->cmer_indicator_reporting_enabled = false;
1390
1391
1392 return backend;
1393 }
1394
pa_bluetooth_native_backend_free(pa_bluetooth_backend * backend)1395 void pa_bluetooth_native_backend_free(pa_bluetooth_backend *backend) {
1396 pa_assert(backend);
1397
1398 pa_dbus_free_pending_list(&backend->pending);
1399
1400 if (backend->adapter_uuids_changed_slot)
1401 pa_hook_slot_free(backend->adapter_uuids_changed_slot);
1402
1403 if (backend->host_battery_level_changed_slot)
1404 pa_hook_slot_free(backend->host_battery_level_changed_slot);
1405
1406 if (backend->enable_shared_profiles)
1407 native_backend_apply_profile_registration_change(backend, false);
1408
1409 if (backend->enable_hsp_hs)
1410 profile_done(backend, PA_BLUETOOTH_PROFILE_HSP_HS);
1411
1412 if (backend->upower)
1413 pa_upower_backend_free(backend->upower);
1414
1415 pa_dbus_connection_unref(backend->connection);
1416
1417 pa_xfree(backend);
1418 }
1419