]> code.delx.au - pulseaudio/blob - src/modules/bluetooth/module-bluez5-device.c
bluetooth: Create BlueZ 5 card profile for each audio UUID
[pulseaudio] / src / modules / bluetooth / module-bluez5-device.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2008-2013 João Paulo Rechi Vita
5 Copyright 2011-2013 BMW Car IT GmbH.
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <pulsecore/core-util.h>
28 #include <pulsecore/i18n.h>
29 #include <pulsecore/module.h>
30 #include <pulsecore/modargs.h>
31
32 #include "bluez5-util.h"
33
34 #include "module-bluez5-device-symdef.h"
35
36 PA_MODULE_AUTHOR("João Paulo Rechi Vita");
37 PA_MODULE_DESCRIPTION("BlueZ 5 Bluetooth audio sink and source");
38 PA_MODULE_VERSION(PACKAGE_VERSION);
39 PA_MODULE_LOAD_ONCE(false);
40 PA_MODULE_USAGE("path=<device object path>");
41
42 static const char* const valid_modargs[] = {
43 "path",
44 NULL
45 };
46
47 struct userdata {
48 pa_module *module;
49 pa_core *core;
50
51 pa_hook_slot *device_connection_changed_slot;
52
53 pa_bluetooth_discovery *discovery;
54 pa_bluetooth_device *device;
55
56 pa_card *card;
57 pa_bluetooth_profile_t profile;
58 char *output_port_name;
59 char *input_port_name;
60 };
61
62 typedef enum pa_bluetooth_form_factor {
63 PA_BLUETOOTH_FORM_FACTOR_UNKNOWN,
64 PA_BLUETOOTH_FORM_FACTOR_HEADSET,
65 PA_BLUETOOTH_FORM_FACTOR_HANDSFREE,
66 PA_BLUETOOTH_FORM_FACTOR_MICROPHONE,
67 PA_BLUETOOTH_FORM_FACTOR_SPEAKER,
68 PA_BLUETOOTH_FORM_FACTOR_HEADPHONE,
69 PA_BLUETOOTH_FORM_FACTOR_PORTABLE,
70 PA_BLUETOOTH_FORM_FACTOR_CAR,
71 PA_BLUETOOTH_FORM_FACTOR_HIFI,
72 PA_BLUETOOTH_FORM_FACTOR_PHONE,
73 } pa_bluetooth_form_factor_t;
74
75 /* Run from main thread */
76 static pa_bluetooth_form_factor_t form_factor_from_class(uint32_t class_of_device) {
77 unsigned major, minor;
78 pa_bluetooth_form_factor_t r;
79
80 static const pa_bluetooth_form_factor_t table[] = {
81 [1] = PA_BLUETOOTH_FORM_FACTOR_HEADSET,
82 [2] = PA_BLUETOOTH_FORM_FACTOR_HANDSFREE,
83 [4] = PA_BLUETOOTH_FORM_FACTOR_MICROPHONE,
84 [5] = PA_BLUETOOTH_FORM_FACTOR_SPEAKER,
85 [6] = PA_BLUETOOTH_FORM_FACTOR_HEADPHONE,
86 [7] = PA_BLUETOOTH_FORM_FACTOR_PORTABLE,
87 [8] = PA_BLUETOOTH_FORM_FACTOR_CAR,
88 [10] = PA_BLUETOOTH_FORM_FACTOR_HIFI
89 };
90
91 /*
92 * See Bluetooth Assigned Numbers:
93 * https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
94 */
95 major = (class_of_device >> 8) & 0x1F;
96 minor = (class_of_device >> 2) & 0x3F;
97
98 switch (major) {
99 case 2:
100 return PA_BLUETOOTH_FORM_FACTOR_PHONE;
101 case 4:
102 break;
103 default:
104 pa_log_debug("Unknown Bluetooth major device class %u", major);
105 return PA_BLUETOOTH_FORM_FACTOR_UNKNOWN;
106 }
107
108 r = minor < PA_ELEMENTSOF(table) ? table[minor] : PA_BLUETOOTH_FORM_FACTOR_UNKNOWN;
109
110 if (!r)
111 pa_log_debug("Unknown Bluetooth minor device class %u", minor);
112
113 return r;
114 }
115
116 /* Run from main thread */
117 static const char *form_factor_to_string(pa_bluetooth_form_factor_t ff) {
118 switch (ff) {
119 case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN:
120 return "unknown";
121 case PA_BLUETOOTH_FORM_FACTOR_HEADSET:
122 return "headset";
123 case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE:
124 return "hands-free";
125 case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE:
126 return "microphone";
127 case PA_BLUETOOTH_FORM_FACTOR_SPEAKER:
128 return "speaker";
129 case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE:
130 return "headphone";
131 case PA_BLUETOOTH_FORM_FACTOR_PORTABLE:
132 return "portable";
133 case PA_BLUETOOTH_FORM_FACTOR_CAR:
134 return "car";
135 case PA_BLUETOOTH_FORM_FACTOR_HIFI:
136 return "hifi";
137 case PA_BLUETOOTH_FORM_FACTOR_PHONE:
138 return "phone";
139 }
140
141 pa_assert_not_reached();
142 }
143
144 /* Run from main thread */
145 static char *cleanup_name(const char *name) {
146 char *t, *s, *d;
147 bool space = false;
148
149 pa_assert(name);
150
151 while ((*name >= 1 && *name <= 32) || *name >= 127)
152 name++;
153
154 t = pa_xstrdup(name);
155
156 for (s = d = t; *s; s++) {
157
158 if (*s <= 32 || *s >= 127 || *s == '_') {
159 space = true;
160 continue;
161 }
162
163 if (space) {
164 *(d++) = ' ';
165 space = false;
166 }
167
168 *(d++) = *s;
169 }
170
171 *d = 0;
172
173 return t;
174 }
175
176 /* Run from main thread */
177 static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
178 static const pa_direction_t profile_direction[] = {
179 [PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
180 [PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
181 [PA_BLUETOOTH_PROFILE_OFF] = 0
182 };
183
184 return profile_direction[p];
185 }
186
187 /* Run from main thread */
188 static pa_available_t get_port_availability(struct userdata *u, pa_direction_t direction) {
189 pa_available_t result = PA_AVAILABLE_NO;
190 unsigned i;
191
192 pa_assert(u);
193 pa_assert(u->device);
194
195 for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++) {
196 pa_bluetooth_transport *transport;
197
198 if (!(get_profile_direction(i) & direction))
199 continue;
200
201 if (!(transport = u->device->transports[i]))
202 continue;
203
204 switch(transport->state) {
205 case PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED:
206 continue;
207
208 case PA_BLUETOOTH_TRANSPORT_STATE_IDLE:
209 if (result == PA_AVAILABLE_NO)
210 result = PA_AVAILABLE_UNKNOWN;
211
212 break;
213
214 case PA_BLUETOOTH_TRANSPORT_STATE_PLAYING:
215 return PA_AVAILABLE_YES;
216 }
217 }
218
219 return result;
220 }
221
222 /* Run from main thread */
223 static pa_available_t transport_state_to_availability(pa_bluetooth_transport_state_t state) {
224 switch (state) {
225 case PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED:
226 return PA_AVAILABLE_NO;
227 case PA_BLUETOOTH_TRANSPORT_STATE_PLAYING:
228 return PA_AVAILABLE_YES;
229 default:
230 return PA_AVAILABLE_UNKNOWN;
231 }
232 }
233
234 /* Run from main thread */
235 static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
236 pa_device_port *port;
237 pa_device_port_new_data port_data;
238 const char *name_prefix, *input_description, *output_description;
239
240 pa_assert(u);
241 pa_assert(ports);
242 pa_assert(u->device);
243
244 name_prefix = "unknown";
245 input_description = _("Bluetooth Input");
246 output_description = _("Bluetooth Output");
247
248 switch (form_factor_from_class(u->device->class_of_device)) {
249 case PA_BLUETOOTH_FORM_FACTOR_HEADSET:
250 name_prefix = "headset";
251 input_description = output_description = _("Headset");
252 break;
253
254 case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE:
255 name_prefix = "handsfree";
256 input_description = output_description = _("Handsfree");
257 break;
258
259 case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE:
260 name_prefix = "microphone";
261 input_description = _("Microphone");
262 output_description = _("Bluetooth Output");
263 break;
264
265 case PA_BLUETOOTH_FORM_FACTOR_SPEAKER:
266 name_prefix = "speaker";
267 input_description = _("Bluetooth Input");
268 output_description = _("Speaker");
269 break;
270
271 case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE:
272 name_prefix = "headphone";
273 input_description = _("Bluetooth Input");
274 output_description = _("Headphone");
275 break;
276
277 case PA_BLUETOOTH_FORM_FACTOR_PORTABLE:
278 name_prefix = "portable";
279 input_description = output_description = _("Portable");
280 break;
281
282 case PA_BLUETOOTH_FORM_FACTOR_CAR:
283 name_prefix = "car";
284 input_description = output_description = _("Car");
285 break;
286
287 case PA_BLUETOOTH_FORM_FACTOR_HIFI:
288 name_prefix = "hifi";
289 input_description = output_description = _("HiFi");
290 break;
291
292 case PA_BLUETOOTH_FORM_FACTOR_PHONE:
293 name_prefix = "phone";
294 input_description = output_description = _("Phone");
295 break;
296
297 case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN:
298 name_prefix = "unknown";
299 input_description = _("Bluetooth Input");
300 output_description = _("Bluetooth Output");
301 break;
302 }
303
304 u->output_port_name = pa_sprintf_malloc("%s-output", name_prefix);
305 pa_device_port_new_data_init(&port_data);
306 pa_device_port_new_data_set_name(&port_data, u->output_port_name);
307 pa_device_port_new_data_set_description(&port_data, output_description);
308 pa_device_port_new_data_set_direction(&port_data, PA_DIRECTION_OUTPUT);
309 pa_device_port_new_data_set_available(&port_data, get_port_availability(u, PA_DIRECTION_OUTPUT));
310 pa_assert_se(port = pa_device_port_new(u->core, &port_data, 0));
311 pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
312 pa_device_port_new_data_done(&port_data);
313
314 u->input_port_name = pa_sprintf_malloc("%s-input", name_prefix);
315 pa_device_port_new_data_init(&port_data);
316 pa_device_port_new_data_set_name(&port_data, u->input_port_name);
317 pa_device_port_new_data_set_description(&port_data, input_description);
318 pa_device_port_new_data_set_direction(&port_data, PA_DIRECTION_INPUT);
319 pa_device_port_new_data_set_available(&port_data, get_port_availability(u, PA_DIRECTION_INPUT));
320 pa_assert_se(port = pa_device_port_new(u->core, &port_data, 0));
321 pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
322 pa_device_port_new_data_done(&port_data);
323 }
324
325 /* Run from main thread */
326 static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid, pa_hashmap *ports) {
327 pa_device_port *input_port, *output_port;
328 pa_card_profile *cp = NULL;
329 pa_bluetooth_profile_t *p;
330
331 pa_assert(u->input_port_name);
332 pa_assert(u->output_port_name);
333 pa_assert_se(input_port = pa_hashmap_get(ports, u->input_port_name));
334 pa_assert_se(output_port = pa_hashmap_get(ports, u->output_port_name));
335
336 if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SINK)) {
337 /* TODO: Change this profile's name to a2dp_sink, to reflect the remote
338 * device's role and be consistent with the a2dp source profile */
339 cp = pa_card_profile_new("a2dp", _("High Fidelity Playback (A2DP Sink)"), sizeof(pa_bluetooth_profile_t));
340 cp->priority = 10;
341 cp->n_sinks = 1;
342 cp->n_sources = 0;
343 cp->max_sink_channels = 2;
344 cp->max_source_channels = 0;
345 pa_hashmap_put(output_port->profiles, cp->name, cp);
346
347 p = PA_CARD_PROFILE_DATA(cp);
348 *p = PA_BLUETOOTH_PROFILE_A2DP_SINK;
349 } else if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE)) {
350 cp = pa_card_profile_new("a2dp_source", _("High Fidelity Capture (A2DP Source)"), sizeof(pa_bluetooth_profile_t));
351 cp->priority = 10;
352 cp->n_sinks = 0;
353 cp->n_sources = 1;
354 cp->max_sink_channels = 0;
355 cp->max_source_channels = 2;
356 pa_hashmap_put(input_port->profiles, cp->name, cp);
357
358 p = PA_CARD_PROFILE_DATA(cp);
359 *p = PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
360 }
361
362 if (cp && u->device->transports[*p])
363 cp->available = transport_state_to_availability(u->device->transports[*p]->state);
364
365 return cp;
366 }
367
368 /* Run from main thread */
369 static int add_card(struct userdata *u) {
370 const pa_bluetooth_device *d;
371 pa_card_new_data data;
372 char *alias;
373 pa_bluetooth_form_factor_t ff;
374 pa_card_profile *cp;
375 pa_bluetooth_profile_t *p;
376 const char *uuid;
377 void *state;
378
379 pa_assert(u);
380 pa_assert(u->device);
381
382 d = u->device;
383
384 pa_card_new_data_init(&data);
385 data.driver = __FILE__;
386 data.module = u->module;
387
388 alias = cleanup_name(d->alias);
389 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, alias);
390 pa_xfree(alias);
391
392 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, d->address);
393 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "bluez");
394 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "sound");
395 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_BUS, "bluetooth");
396
397 if ((ff = form_factor_from_class(d->class_of_device)) != PA_BLUETOOTH_FORM_FACTOR_UNKNOWN)
398 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_FORM_FACTOR, form_factor_to_string(ff));
399
400 pa_proplist_sets(data.proplist, "bluez.path", d->path);
401 pa_proplist_setf(data.proplist, "bluez.class", "0x%06x", d->class_of_device);
402 pa_proplist_sets(data.proplist, "bluez.alias", d->alias);
403 data.name = pa_sprintf_malloc("bluez_card.%s", d->address);
404 data.namereg_fail = false;
405
406 create_card_ports(u, data.ports);
407
408 PA_HASHMAP_FOREACH(uuid, d->uuids, state) {
409 cp = create_card_profile(u, uuid, data.ports);
410
411 if (!cp)
412 continue;
413
414 if (pa_hashmap_get(data.profiles, cp->name)) {
415 pa_card_profile_free(cp);
416 continue;
417 }
418
419 pa_hashmap_put(data.profiles, cp->name, cp);
420 }
421
422 pa_assert(!pa_hashmap_isempty(data.profiles));
423
424 cp = pa_card_profile_new("off", _("Off"), sizeof(pa_bluetooth_profile_t));
425 cp->available = PA_AVAILABLE_YES;
426 p = PA_CARD_PROFILE_DATA(cp);
427 *p = PA_BLUETOOTH_PROFILE_OFF;
428 pa_hashmap_put(data.profiles, cp->name, cp);
429
430 u->card = pa_card_new(u->core, &data);
431 pa_card_new_data_done(&data);
432 if (!u->card) {
433 pa_log("Failed to allocate card.");
434 return -1;
435 }
436
437 u->card->userdata = u;
438
439 p = PA_CARD_PROFILE_DATA(u->card->active_profile);
440 u->profile = *p;
441
442 return 0;
443 }
444
445 /* Run from main thread */
446 static pa_hook_result_t device_connection_changed_cb(pa_bluetooth_discovery *y, const pa_bluetooth_device *d, struct userdata *u) {
447 pa_assert(d);
448 pa_assert(u);
449
450 if (d != u->device || pa_bluetooth_device_any_transport_connected(d))
451 return PA_HOOK_OK;
452
453 pa_log_debug("Unloading module for device %s", d->path);
454 pa_module_unload(u->core, u->module, true);
455
456 return PA_HOOK_OK;
457 }
458
459 int pa__init(pa_module* m) {
460 struct userdata *u;
461 const char *path;
462 pa_modargs *ma;
463
464 pa_assert(m);
465
466 m->userdata = u = pa_xnew0(struct userdata, 1);
467 u->module = m;
468 u->core = m->core;
469
470 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
471 pa_log_error("Failed to parse module arguments");
472 goto fail;
473 }
474
475 if (!(path = pa_modargs_get_value(ma, "path", NULL))) {
476 pa_log_error("Failed to get device path from module arguments");
477 goto fail;
478 }
479
480 if (!(u->discovery = pa_bluetooth_discovery_get(m->core)))
481 goto fail;
482
483 if (!(u->device = pa_bluetooth_discovery_get_device_by_path(u->discovery, path))) {
484 pa_log_error("%s is unknown", path);
485 goto fail;
486 }
487
488 pa_modargs_free(ma);
489
490 u->device_connection_changed_slot =
491 pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED),
492 PA_HOOK_NORMAL, (pa_hook_cb_t) device_connection_changed_cb, u);
493
494 if (add_card(u) < 0)
495 goto fail;
496
497 return 0;
498
499 fail:
500
501 if (ma)
502 pa_modargs_free(ma);
503
504 pa__done(m);
505
506 return -1;
507 }
508
509 void pa__done(pa_module *m) {
510 struct userdata *u;
511
512 pa_assert(m);
513
514 if (!(u = m->userdata))
515 return;
516
517 if (u->device_connection_changed_slot)
518 pa_hook_slot_free(u->device_connection_changed_slot);
519
520 if (u->card)
521 pa_card_free(u->card);
522
523 if (u->discovery)
524 pa_bluetooth_discovery_unref(u->discovery);
525
526 pa_xfree(u->output_port_name);
527 pa_xfree(u->input_port_name);
528
529 pa_xfree(u);
530 }