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 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
;
230 pa_assert(u
->device
);
232 name_prefix
= "unknown";
233 input_description
= _("Bluetooth Input");
234 output_description
= _("Bluetooth Output");
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");
242 case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE
:
243 name_prefix
= "handsfree";
244 input_description
= output_description
= _("Handsfree");
247 case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE
:
248 name_prefix
= "microphone";
249 input_description
= _("Microphone");
250 output_description
= _("Bluetooth Output");
253 case PA_BLUETOOTH_FORM_FACTOR_SPEAKER
:
254 name_prefix
= "speaker";
255 input_description
= _("Bluetooth Input");
256 output_description
= _("Speaker");
259 case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE
:
260 name_prefix
= "headphone";
261 input_description
= _("Bluetooth Input");
262 output_description
= _("Headphone");
265 case PA_BLUETOOTH_FORM_FACTOR_PORTABLE
:
266 name_prefix
= "portable";
267 input_description
= output_description
= _("Portable");
270 case PA_BLUETOOTH_FORM_FACTOR_CAR
:
272 input_description
= output_description
= _("Car");
275 case PA_BLUETOOTH_FORM_FACTOR_HIFI
:
276 name_prefix
= "hifi";
277 input_description
= output_description
= _("HiFi");
280 case PA_BLUETOOTH_FORM_FACTOR_PHONE
:
281 name_prefix
= "phone";
282 input_description
= output_description
= _("Phone");
285 case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
:
286 name_prefix
= "unknown";
287 input_description
= _("Bluetooth Input");
288 output_description
= _("Bluetooth Output");
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
);
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
);
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
;
318 pa_bluetooth_form_factor_t ff
;
320 pa_bluetooth_profile_t
*p
;
323 pa_assert(u
->device
);
327 pa_card_new_data_init(&data
);
328 data
.driver
= __FILE__
;
329 data
.module
= u
->module
;
331 alias
= cleanup_name(d
->alias
);
332 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, alias
);
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");
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
));
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;
349 create_card_ports(u
, data
.ports
);
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
);
357 u
->card
= pa_card_new(u
->core
, &data
);
358 pa_card_new_data_done(&data
);
360 pa_log("Failed to allocate card.");
364 u
->card
->userdata
= u
;
366 p
= PA_CARD_PROFILE_DATA(u
->card
->active_profile
);
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
) {
377 if (d
!= u
->device
|| pa_bluetooth_device_any_transport_connected(d
))
380 pa_log_debug("Unloading module for device %s", d
->path
);
381 pa_module_unload(u
->core
, u
->module
, true);
386 int pa__init(pa_module
* m
) {
393 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
397 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
398 pa_log_error("Failed to parse module arguments");
402 if (!(path
= pa_modargs_get_value(ma
, "path", NULL
))) {
403 pa_log_error("Failed to get device path from module arguments");
407 if (!(u
->discovery
= pa_bluetooth_discovery_get(m
->core
)))
410 if (!(u
->device
= pa_bluetooth_discovery_get_device_by_path(u
->discovery
, path
))) {
411 pa_log_error("%s is unknown", path
);
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
);
436 void pa__done(pa_module
*m
) {
441 if (!(u
= m
->userdata
))
444 if (u
->device_connection_changed_slot
)
445 pa_hook_slot_free(u
->device_connection_changed_slot
);
448 pa_card_free(u
->card
);
451 pa_bluetooth_discovery_unref(u
->discovery
);
453 pa_xfree(u
->output_port_name
);
454 pa_xfree(u
->input_port_name
);