2 This file is part of PulseAudio.
4 Copyright 2008-2013 João Paulo Rechi Vita
5 Copyright 2011-2013 BMW Car IT GmbH.
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.
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.
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
27 #include <pulsecore/core-util.h>
28 #include <pulsecore/i18n.h>
29 #include <pulsecore/module.h>
30 #include <pulsecore/modargs.h>
32 #include "bluez5-util.h"
34 #include "module-bluez5-device-symdef.h"
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>");
42 static const char* const valid_modargs
[] = {
51 pa_hook_slot
*device_connection_changed_slot
;
53 pa_bluetooth_discovery
*discovery
;
54 pa_bluetooth_device
*device
;
57 pa_bluetooth_profile_t profile
;
58 char *output_port_name
;
59 char *input_port_name
;
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
;
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
;
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
92 * See Bluetooth Assigned Numbers:
93 * https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
95 major
= (class_of_device
>> 8) & 0x1F;
96 minor
= (class_of_device
>> 2) & 0x3F;
100 return PA_BLUETOOTH_FORM_FACTOR_PHONE
;
104 pa_log_debug("Unknown Bluetooth major device class %u", major
);
105 return PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
;
108 r
= minor
< PA_ELEMENTSOF(table
) ? table
[minor
] : PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
;
111 pa_log_debug("Unknown Bluetooth minor device class %u", minor
);
116 /* Run from main thread */
117 static const char *form_factor_to_string(pa_bluetooth_form_factor_t ff
) {
119 case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
:
121 case PA_BLUETOOTH_FORM_FACTOR_HEADSET
:
123 case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE
:
125 case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE
:
127 case PA_BLUETOOTH_FORM_FACTOR_SPEAKER
:
129 case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE
:
131 case PA_BLUETOOTH_FORM_FACTOR_PORTABLE
:
133 case PA_BLUETOOTH_FORM_FACTOR_CAR
:
135 case PA_BLUETOOTH_FORM_FACTOR_HIFI
:
137 case PA_BLUETOOTH_FORM_FACTOR_PHONE
:
141 pa_assert_not_reached();
144 /* Run from main thread */
145 static char *cleanup_name(const char *name
) {
151 while ((*name
>= 1 && *name
<= 32) || *name
>= 127)
154 t
= pa_xstrdup(name
);
156 for (s
= d
= t
; *s
; s
++) {
158 if (*s
<= 32 || *s
>= 127 || *s
== '_') {
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
184 return profile_direction
[p
];
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
;
193 pa_assert(u
->device
);
195 for (i
= 0; i
< PA_BLUETOOTH_PROFILE_COUNT
; i
++) {
196 pa_bluetooth_transport
*transport
;
198 if (!(get_profile_direction(i
) & direction
))
201 if (!(transport
= u
->device
->transports
[i
]))
204 switch(transport
->state
) {
205 case PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED
:
208 case PA_BLUETOOTH_TRANSPORT_STATE_IDLE
:
209 if (result
== PA_AVAILABLE_NO
)
210 result
= PA_AVAILABLE_UNKNOWN
;
214 case PA_BLUETOOTH_TRANSPORT_STATE_PLAYING
:
215 return PA_AVAILABLE_YES
;
222 /* Run from main thread */
223 static pa_available_t
transport_state_to_availability(pa_bluetooth_transport_state_t 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
;
230 return PA_AVAILABLE_UNKNOWN
;
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
;
242 pa_assert(u
->device
);
244 name_prefix
= "unknown";
245 input_description
= _("Bluetooth Input");
246 output_description
= _("Bluetooth Output");
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");
254 case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE
:
255 name_prefix
= "handsfree";
256 input_description
= output_description
= _("Handsfree");
259 case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE
:
260 name_prefix
= "microphone";
261 input_description
= _("Microphone");
262 output_description
= _("Bluetooth Output");
265 case PA_BLUETOOTH_FORM_FACTOR_SPEAKER
:
266 name_prefix
= "speaker";
267 input_description
= _("Bluetooth Input");
268 output_description
= _("Speaker");
271 case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE
:
272 name_prefix
= "headphone";
273 input_description
= _("Bluetooth Input");
274 output_description
= _("Headphone");
277 case PA_BLUETOOTH_FORM_FACTOR_PORTABLE
:
278 name_prefix
= "portable";
279 input_description
= output_description
= _("Portable");
282 case PA_BLUETOOTH_FORM_FACTOR_CAR
:
284 input_description
= output_description
= _("Car");
287 case PA_BLUETOOTH_FORM_FACTOR_HIFI
:
288 name_prefix
= "hifi";
289 input_description
= output_description
= _("HiFi");
292 case PA_BLUETOOTH_FORM_FACTOR_PHONE
:
293 name_prefix
= "phone";
294 input_description
= output_description
= _("Phone");
297 case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
:
298 name_prefix
= "unknown";
299 input_description
= _("Bluetooth Input");
300 output_description
= _("Bluetooth Output");
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
);
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
);
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
;
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
));
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
));
343 cp
->max_sink_channels
= 2;
344 cp
->max_source_channels
= 0;
345 pa_hashmap_put(output_port
->profiles
, cp
->name
, cp
);
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
));
354 cp
->max_sink_channels
= 0;
355 cp
->max_source_channels
= 2;
356 pa_hashmap_put(input_port
->profiles
, cp
->name
, cp
);
358 p
= PA_CARD_PROFILE_DATA(cp
);
359 *p
= PA_BLUETOOTH_PROFILE_A2DP_SOURCE
;
362 if (cp
&& u
->device
->transports
[*p
])
363 cp
->available
= transport_state_to_availability(u
->device
->transports
[*p
]->state
);
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
;
373 pa_bluetooth_form_factor_t ff
;
375 pa_bluetooth_profile_t
*p
;
380 pa_assert(u
->device
);
384 pa_card_new_data_init(&data
);
385 data
.driver
= __FILE__
;
386 data
.module
= u
->module
;
388 alias
= cleanup_name(d
->alias
);
389 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, alias
);
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");
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
));
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;
406 create_card_ports(u
, data
.ports
);
408 PA_HASHMAP_FOREACH(uuid
, d
->uuids
, state
) {
409 cp
= create_card_profile(u
, uuid
, data
.ports
);
414 if (pa_hashmap_get(data
.profiles
, cp
->name
)) {
415 pa_card_profile_free(cp
);
419 pa_hashmap_put(data
.profiles
, cp
->name
, cp
);
422 pa_assert(!pa_hashmap_isempty(data
.profiles
));
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
);
430 u
->card
= pa_card_new(u
->core
, &data
);
431 pa_card_new_data_done(&data
);
433 pa_log("Failed to allocate card.");
437 u
->card
->userdata
= u
;
439 p
= PA_CARD_PROFILE_DATA(u
->card
->active_profile
);
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
) {
450 if (d
!= u
->device
|| pa_bluetooth_device_any_transport_connected(d
))
453 pa_log_debug("Unloading module for device %s", d
->path
);
454 pa_module_unload(u
->core
, u
->module
, true);
459 int pa__init(pa_module
* m
) {
466 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
470 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
471 pa_log_error("Failed to parse module arguments");
475 if (!(path
= pa_modargs_get_value(ma
, "path", NULL
))) {
476 pa_log_error("Failed to get device path from module arguments");
480 if (!(u
->discovery
= pa_bluetooth_discovery_get(m
->core
)))
483 if (!(u
->device
= pa_bluetooth_discovery_get_device_by_path(u
->discovery
, path
))) {
484 pa_log_error("%s is unknown", path
);
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
);
509 void pa__done(pa_module
*m
) {
514 if (!(u
= m
->userdata
))
517 if (u
->device_connection_changed_slot
)
518 pa_hook_slot_free(u
->device_connection_changed_slot
);
521 pa_card_free(u
->card
);
524 pa_bluetooth_discovery_unref(u
->discovery
);
526 pa_xfree(u
->output_port_name
);
527 pa_xfree(u
->input_port_name
);