]> code.delx.au - pulseaudio/blob - src/modules/bluetooth/module-bluez5-device.c
bluetooth: Create BlueZ 5 card ports
[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 void create_card_ports(struct userdata *u, pa_hashmap *ports) {
224 pa_device_port *port;
225 pa_device_port_new_data port_data;
226 const char *name_prefix, *input_description, *output_description;
227
228 pa_assert(u);
229 pa_assert(ports);
230 pa_assert(u->device);
231
232 name_prefix = "unknown";
233 input_description = _("Bluetooth Input");
234 output_description = _("Bluetooth Output");
235
236 switch (form_factor_from_class(u->device->class_of_device)) {
237 case PA_BLUETOOTH_FORM_FACTOR_HEADSET:
238 name_prefix = "headset";
239 input_description = output_description = _("Headset");
240 break;
241
242 case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE:
243 name_prefix = "handsfree";
244 input_description = output_description = _("Handsfree");
245 break;
246
247 case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE:
248 name_prefix = "microphone";
249 input_description = _("Microphone");
250 output_description = _("Bluetooth Output");
251 break;
252
253 case PA_BLUETOOTH_FORM_FACTOR_SPEAKER:
254 name_prefix = "speaker";
255 input_description = _("Bluetooth Input");
256 output_description = _("Speaker");
257 break;
258
259 case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE:
260 name_prefix = "headphone";
261 input_description = _("Bluetooth Input");
262 output_description = _("Headphone");
263 break;
264
265 case PA_BLUETOOTH_FORM_FACTOR_PORTABLE:
266 name_prefix = "portable";
267 input_description = output_description = _("Portable");
268 break;
269
270 case PA_BLUETOOTH_FORM_FACTOR_CAR:
271 name_prefix = "car";
272 input_description = output_description = _("Car");
273 break;
274
275 case PA_BLUETOOTH_FORM_FACTOR_HIFI:
276 name_prefix = "hifi";
277 input_description = output_description = _("HiFi");
278 break;
279
280 case PA_BLUETOOTH_FORM_FACTOR_PHONE:
281 name_prefix = "phone";
282 input_description = output_description = _("Phone");
283 break;
284
285 case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN:
286 name_prefix = "unknown";
287 input_description = _("Bluetooth Input");
288 output_description = _("Bluetooth Output");
289 break;
290 }
291
292 u->output_port_name = pa_sprintf_malloc("%s-output", name_prefix);
293 pa_device_port_new_data_init(&port_data);
294 pa_device_port_new_data_set_name(&port_data, u->output_port_name);
295 pa_device_port_new_data_set_description(&port_data, output_description);
296 pa_device_port_new_data_set_direction(&port_data, PA_DIRECTION_OUTPUT);
297 pa_device_port_new_data_set_available(&port_data, get_port_availability(u, PA_DIRECTION_OUTPUT));
298 pa_assert_se(port = pa_device_port_new(u->core, &port_data, 0));
299 pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
300 pa_device_port_new_data_done(&port_data);
301
302 u->input_port_name = pa_sprintf_malloc("%s-input", name_prefix);
303 pa_device_port_new_data_init(&port_data);
304 pa_device_port_new_data_set_name(&port_data, u->input_port_name);
305 pa_device_port_new_data_set_description(&port_data, input_description);
306 pa_device_port_new_data_set_direction(&port_data, PA_DIRECTION_INPUT);
307 pa_device_port_new_data_set_available(&port_data, get_port_availability(u, PA_DIRECTION_INPUT));
308 pa_assert_se(port = pa_device_port_new(u->core, &port_data, 0));
309 pa_assert_se(pa_hashmap_put(ports, port->name, port) >= 0);
310 pa_device_port_new_data_done(&port_data);
311 }
312
313 /* Run from main thread */
314 static int add_card(struct userdata *u) {
315 const pa_bluetooth_device *d;
316 pa_card_new_data data;
317 char *alias;
318 pa_bluetooth_form_factor_t ff;
319 pa_card_profile *cp;
320 pa_bluetooth_profile_t *p;
321
322 pa_assert(u);
323 pa_assert(u->device);
324
325 d = u->device;
326
327 pa_card_new_data_init(&data);
328 data.driver = __FILE__;
329 data.module = u->module;
330
331 alias = cleanup_name(d->alias);
332 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, alias);
333 pa_xfree(alias);
334
335 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, d->address);
336 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "bluez");
337 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "sound");
338 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_BUS, "bluetooth");
339
340 if ((ff = form_factor_from_class(d->class_of_device)) != PA_BLUETOOTH_FORM_FACTOR_UNKNOWN)
341 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_FORM_FACTOR, form_factor_to_string(ff));
342
343 pa_proplist_sets(data.proplist, "bluez.path", d->path);
344 pa_proplist_setf(data.proplist, "bluez.class", "0x%06x", d->class_of_device);
345 pa_proplist_sets(data.proplist, "bluez.alias", d->alias);
346 data.name = pa_sprintf_malloc("bluez_card.%s", d->address);
347 data.namereg_fail = false;
348
349 create_card_ports(u, data.ports);
350
351 cp = pa_card_profile_new("off", _("Off"), sizeof(pa_bluetooth_profile_t));
352 cp->available = PA_AVAILABLE_YES;
353 p = PA_CARD_PROFILE_DATA(cp);
354 *p = PA_BLUETOOTH_PROFILE_OFF;
355 pa_hashmap_put(data.profiles, cp->name, cp);
356
357 u->card = pa_card_new(u->core, &data);
358 pa_card_new_data_done(&data);
359 if (!u->card) {
360 pa_log("Failed to allocate card.");
361 return -1;
362 }
363
364 u->card->userdata = u;
365
366 p = PA_CARD_PROFILE_DATA(u->card->active_profile);
367 u->profile = *p;
368
369 return 0;
370 }
371
372 /* Run from main thread */
373 static pa_hook_result_t device_connection_changed_cb(pa_bluetooth_discovery *y, const pa_bluetooth_device *d, struct userdata *u) {
374 pa_assert(d);
375 pa_assert(u);
376
377 if (d != u->device || pa_bluetooth_device_any_transport_connected(d))
378 return PA_HOOK_OK;
379
380 pa_log_debug("Unloading module for device %s", d->path);
381 pa_module_unload(u->core, u->module, true);
382
383 return PA_HOOK_OK;
384 }
385
386 int pa__init(pa_module* m) {
387 struct userdata *u;
388 const char *path;
389 pa_modargs *ma;
390
391 pa_assert(m);
392
393 m->userdata = u = pa_xnew0(struct userdata, 1);
394 u->module = m;
395 u->core = m->core;
396
397 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
398 pa_log_error("Failed to parse module arguments");
399 goto fail;
400 }
401
402 if (!(path = pa_modargs_get_value(ma, "path", NULL))) {
403 pa_log_error("Failed to get device path from module arguments");
404 goto fail;
405 }
406
407 if (!(u->discovery = pa_bluetooth_discovery_get(m->core)))
408 goto fail;
409
410 if (!(u->device = pa_bluetooth_discovery_get_device_by_path(u->discovery, path))) {
411 pa_log_error("%s is unknown", path);
412 goto fail;
413 }
414
415 pa_modargs_free(ma);
416
417 u->device_connection_changed_slot =
418 pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED),
419 PA_HOOK_NORMAL, (pa_hook_cb_t) device_connection_changed_cb, u);
420
421 if (add_card(u) < 0)
422 goto fail;
423
424 return 0;
425
426 fail:
427
428 if (ma)
429 pa_modargs_free(ma);
430
431 pa__done(m);
432
433 return -1;
434 }
435
436 void pa__done(pa_module *m) {
437 struct userdata *u;
438
439 pa_assert(m);
440
441 if (!(u = m->userdata))
442 return;
443
444 if (u->device_connection_changed_slot)
445 pa_hook_slot_free(u->device_connection_changed_slot);
446
447 if (u->card)
448 pa_card_free(u->card);
449
450 if (u->discovery)
451 pa_bluetooth_discovery_unref(u->discovery);
452
453 pa_xfree(u->output_port_name);
454 pa_xfree(u->input_port_name);
455
456 pa_xfree(u);
457 }