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
29 #include <pulsecore/core-util.h>
30 #include <pulsecore/i18n.h>
31 #include <pulsecore/module.h>
32 #include <pulsecore/modargs.h>
34 #include "a2dp-codecs.h"
35 #include "bluez5-util.h"
37 #include "module-bluez5-device-symdef.h"
39 PA_MODULE_AUTHOR("João Paulo Rechi Vita");
40 PA_MODULE_DESCRIPTION("BlueZ 5 Bluetooth audio sink and source");
41 PA_MODULE_VERSION(PACKAGE_VERSION
);
42 PA_MODULE_LOAD_ONCE(false);
43 PA_MODULE_USAGE("path=<device object path>");
45 static const char* const valid_modargs
[] = {
50 typedef struct sbc_info
{
51 sbc_t sbc
; /* Codec data */
52 bool sbc_initialized
; /* Keep track if the encoder is initialized */
53 size_t codesize
, frame_length
; /* SBC Codesize, frame_length. We simply cache those values here */
54 uint16_t seq_num
; /* Cumulative packet sequence */
58 void* buffer
; /* Codec transfer buffer */
59 size_t buffer_size
; /* Size of the buffer */
66 pa_hook_slot
*device_connection_changed_slot
;
68 pa_bluetooth_discovery
*discovery
;
69 pa_bluetooth_device
*device
;
70 pa_bluetooth_transport
*transport
;
71 bool transport_acquired
;
76 pa_bluetooth_profile_t profile
;
77 char *output_port_name
;
78 char *input_port_name
;
82 size_t write_link_mtu
;
83 size_t read_block_size
;
84 size_t write_block_size
;
85 pa_sample_spec sample_spec
;
86 struct sbc_info sbc_info
;
89 typedef enum pa_bluetooth_form_factor
{
90 PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
,
91 PA_BLUETOOTH_FORM_FACTOR_HEADSET
,
92 PA_BLUETOOTH_FORM_FACTOR_HANDSFREE
,
93 PA_BLUETOOTH_FORM_FACTOR_MICROPHONE
,
94 PA_BLUETOOTH_FORM_FACTOR_SPEAKER
,
95 PA_BLUETOOTH_FORM_FACTOR_HEADPHONE
,
96 PA_BLUETOOTH_FORM_FACTOR_PORTABLE
,
97 PA_BLUETOOTH_FORM_FACTOR_CAR
,
98 PA_BLUETOOTH_FORM_FACTOR_HIFI
,
99 PA_BLUETOOTH_FORM_FACTOR_PHONE
,
100 } pa_bluetooth_form_factor_t
;
102 /* Run from main thread */
103 static pa_bluetooth_form_factor_t
form_factor_from_class(uint32_t class_of_device
) {
104 unsigned major
, minor
;
105 pa_bluetooth_form_factor_t r
;
107 static const pa_bluetooth_form_factor_t table
[] = {
108 [1] = PA_BLUETOOTH_FORM_FACTOR_HEADSET
,
109 [2] = PA_BLUETOOTH_FORM_FACTOR_HANDSFREE
,
110 [4] = PA_BLUETOOTH_FORM_FACTOR_MICROPHONE
,
111 [5] = PA_BLUETOOTH_FORM_FACTOR_SPEAKER
,
112 [6] = PA_BLUETOOTH_FORM_FACTOR_HEADPHONE
,
113 [7] = PA_BLUETOOTH_FORM_FACTOR_PORTABLE
,
114 [8] = PA_BLUETOOTH_FORM_FACTOR_CAR
,
115 [10] = PA_BLUETOOTH_FORM_FACTOR_HIFI
119 * See Bluetooth Assigned Numbers:
120 * https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
122 major
= (class_of_device
>> 8) & 0x1F;
123 minor
= (class_of_device
>> 2) & 0x3F;
127 return PA_BLUETOOTH_FORM_FACTOR_PHONE
;
131 pa_log_debug("Unknown Bluetooth major device class %u", major
);
132 return PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
;
135 r
= minor
< PA_ELEMENTSOF(table
) ? table
[minor
] : PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
;
138 pa_log_debug("Unknown Bluetooth minor device class %u", minor
);
143 /* Run from main thread */
144 static const char *form_factor_to_string(pa_bluetooth_form_factor_t ff
) {
146 case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
:
148 case PA_BLUETOOTH_FORM_FACTOR_HEADSET
:
150 case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE
:
152 case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE
:
154 case PA_BLUETOOTH_FORM_FACTOR_SPEAKER
:
156 case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE
:
158 case PA_BLUETOOTH_FORM_FACTOR_PORTABLE
:
160 case PA_BLUETOOTH_FORM_FACTOR_CAR
:
162 case PA_BLUETOOTH_FORM_FACTOR_HIFI
:
164 case PA_BLUETOOTH_FORM_FACTOR_PHONE
:
168 pa_assert_not_reached();
171 /* Run from main thread */
172 static void connect_ports(struct userdata
*u
, void *new_data
, pa_direction_t direction
) {
173 pa_device_port
*port
;
175 if (direction
== PA_DIRECTION_OUTPUT
) {
176 pa_sink_new_data
*sink_new_data
= new_data
;
178 pa_assert_se(port
= pa_hashmap_get(u
->card
->ports
, u
->output_port_name
));
179 pa_assert_se(pa_hashmap_put(sink_new_data
->ports
, port
->name
, port
) >= 0);
180 pa_device_port_ref(port
);
182 pa_source_new_data
*source_new_data
= new_data
;
184 pa_assert_se(port
= pa_hashmap_get(u
->card
->ports
, u
->input_port_name
));
185 pa_assert_se(pa_hashmap_put(source_new_data
->ports
, port
->name
, port
) >= 0);
186 pa_device_port_ref(port
);
190 static int transport_acquire(struct userdata
*u
, bool optional
) {
191 pa_assert(u
->transport
);
193 if (u
->transport_acquired
)
196 pa_log_debug("Acquiring transport %s", u
->transport
->path
);
198 u
->stream_fd
= u
->transport
->acquire(u
->transport
, optional
, &u
->read_link_mtu
, &u
->write_link_mtu
);
199 if (u
->stream_fd
< 0)
202 u
->transport_acquired
= true;
203 pa_log_info("Transport %s acquired: fd %d", u
->transport
->path
, u
->stream_fd
);
208 /* Run from main thread */
209 static int add_source(struct userdata
*u
) {
210 pa_source_new_data data
;
212 pa_assert(u
->transport
);
214 pa_source_new_data_init(&data
);
215 data
.module
= u
->module
;
217 data
.driver
= __FILE__
;
218 data
.name
= pa_sprintf_malloc("bluez_source.%s", u
->device
->address
);
219 data
.namereg_fail
= false;
220 pa_proplist_sets(data
.proplist
, "bluetooth.protocol", pa_bluetooth_profile_to_string(u
->profile
));
221 pa_source_new_data_set_sample_spec(&data
, &u
->sample_spec
);
223 connect_ports(u
, &data
, PA_DIRECTION_INPUT
);
225 if (!u
->transport_acquired
)
226 switch (u
->profile
) {
227 case PA_BLUETOOTH_PROFILE_A2DP_SOURCE
:
228 data
.suspend_cause
= PA_SUSPEND_USER
;
230 case PA_BLUETOOTH_PROFILE_A2DP_SINK
:
231 case PA_BLUETOOTH_PROFILE_OFF
:
232 pa_assert_not_reached();
236 u
->source
= pa_source_new(u
->core
, &data
, PA_SOURCE_HARDWARE
|PA_SOURCE_LATENCY
);
237 pa_source_new_data_done(&data
);
239 pa_log_error("Failed to create source");
243 u
->source
->userdata
= u
;
248 /* Run from main thread */
249 static int add_sink(struct userdata
*u
) {
250 pa_sink_new_data data
;
252 pa_assert(u
->transport
);
254 pa_sink_new_data_init(&data
);
255 data
.module
= u
->module
;
257 data
.driver
= __FILE__
;
258 data
.name
= pa_sprintf_malloc("bluez_sink.%s", u
->device
->address
);
259 data
.namereg_fail
= false;
260 pa_proplist_sets(data
.proplist
, "bluetooth.protocol", pa_bluetooth_profile_to_string(u
->profile
));
261 pa_sink_new_data_set_sample_spec(&data
, &u
->sample_spec
);
263 connect_ports(u
, &data
, PA_DIRECTION_OUTPUT
);
265 if (!u
->transport_acquired
)
266 switch (u
->profile
) {
267 case PA_BLUETOOTH_PROFILE_A2DP_SINK
:
268 /* Profile switch should have failed */
269 case PA_BLUETOOTH_PROFILE_A2DP_SOURCE
:
270 case PA_BLUETOOTH_PROFILE_OFF
:
271 pa_assert_not_reached();
275 u
->sink
= pa_sink_new(u
->core
, &data
, PA_SINK_HARDWARE
|PA_SINK_LATENCY
);
276 pa_sink_new_data_done(&data
);
278 pa_log_error("Failed to create sink");
282 u
->sink
->userdata
= u
;
287 /* Run from main thread */
288 static void transport_config(struct userdata
*u
) {
289 sbc_info_t
*sbc_info
= &u
->sbc_info
;
292 pa_assert(u
->transport
);
294 u
->sample_spec
.format
= PA_SAMPLE_S16LE
;
295 config
= (a2dp_sbc_t
*) u
->transport
->config
;
297 if (sbc_info
->sbc_initialized
)
298 sbc_reinit(&sbc_info
->sbc
, 0);
300 sbc_init(&sbc_info
->sbc
, 0);
301 sbc_info
->sbc_initialized
= true;
303 switch (config
->frequency
) {
304 case SBC_SAMPLING_FREQ_16000
:
305 sbc_info
->sbc
.frequency
= SBC_FREQ_16000
;
306 u
->sample_spec
.rate
= 16000U;
308 case SBC_SAMPLING_FREQ_32000
:
309 sbc_info
->sbc
.frequency
= SBC_FREQ_32000
;
310 u
->sample_spec
.rate
= 32000U;
312 case SBC_SAMPLING_FREQ_44100
:
313 sbc_info
->sbc
.frequency
= SBC_FREQ_44100
;
314 u
->sample_spec
.rate
= 44100U;
316 case SBC_SAMPLING_FREQ_48000
:
317 sbc_info
->sbc
.frequency
= SBC_FREQ_48000
;
318 u
->sample_spec
.rate
= 48000U;
321 pa_assert_not_reached();
324 switch (config
->channel_mode
) {
325 case SBC_CHANNEL_MODE_MONO
:
326 sbc_info
->sbc
.mode
= SBC_MODE_MONO
;
327 u
->sample_spec
.channels
= 1;
329 case SBC_CHANNEL_MODE_DUAL_CHANNEL
:
330 sbc_info
->sbc
.mode
= SBC_MODE_DUAL_CHANNEL
;
331 u
->sample_spec
.channels
= 2;
333 case SBC_CHANNEL_MODE_STEREO
:
334 sbc_info
->sbc
.mode
= SBC_MODE_STEREO
;
335 u
->sample_spec
.channels
= 2;
337 case SBC_CHANNEL_MODE_JOINT_STEREO
:
338 sbc_info
->sbc
.mode
= SBC_MODE_JOINT_STEREO
;
339 u
->sample_spec
.channels
= 2;
342 pa_assert_not_reached();
345 switch (config
->allocation_method
) {
346 case SBC_ALLOCATION_SNR
:
347 sbc_info
->sbc
.allocation
= SBC_AM_SNR
;
349 case SBC_ALLOCATION_LOUDNESS
:
350 sbc_info
->sbc
.allocation
= SBC_AM_LOUDNESS
;
353 pa_assert_not_reached();
356 switch (config
->subbands
) {
358 sbc_info
->sbc
.subbands
= SBC_SB_4
;
361 sbc_info
->sbc
.subbands
= SBC_SB_8
;
364 pa_assert_not_reached();
367 switch (config
->block_length
) {
368 case SBC_BLOCK_LENGTH_4
:
369 sbc_info
->sbc
.blocks
= SBC_BLK_4
;
371 case SBC_BLOCK_LENGTH_8
:
372 sbc_info
->sbc
.blocks
= SBC_BLK_8
;
374 case SBC_BLOCK_LENGTH_12
:
375 sbc_info
->sbc
.blocks
= SBC_BLK_12
;
377 case SBC_BLOCK_LENGTH_16
:
378 sbc_info
->sbc
.blocks
= SBC_BLK_16
;
381 pa_assert_not_reached();
384 sbc_info
->min_bitpool
= config
->min_bitpool
;
385 sbc_info
->max_bitpool
= config
->max_bitpool
;
387 /* Set minimum bitpool for source to get the maximum possible block_size */
388 sbc_info
->sbc
.bitpool
= u
->profile
== PA_BLUETOOTH_PROFILE_A2DP_SINK
? sbc_info
->max_bitpool
: sbc_info
->min_bitpool
;
389 sbc_info
->codesize
= sbc_get_codesize(&sbc_info
->sbc
);
390 sbc_info
->frame_length
= sbc_get_frame_length(&sbc_info
->sbc
);
392 pa_log_info("SBC parameters: allocation=%u, subbands=%u, blocks=%u, bitpool=%u",
393 sbc_info
->sbc
.allocation
, sbc_info
->sbc
.subbands
, sbc_info
->sbc
.blocks
, sbc_info
->sbc
.bitpool
);
396 /* Run from main thread */
397 static int setup_transport(struct userdata
*u
) {
398 pa_bluetooth_transport
*t
;
401 pa_assert(!u
->transport
);
402 pa_assert(u
->profile
!= PA_BLUETOOTH_PROFILE_OFF
);
404 /* check if profile has a transport */
405 t
= u
->device
->transports
[u
->profile
];
406 if (!t
|| t
->state
<= PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED
) {
407 pa_log_warn("Profile has no transport");
413 if (u
->profile
== PA_BLUETOOTH_PROFILE_A2DP_SOURCE
)
414 transport_acquire(u
, true); /* In case of error, the sink/sources will be created suspended */
415 else if (transport_acquire(u
, false) < 0)
416 return -1; /* We need to fail here until the interactions with module-suspend-on-idle and alike get improved */
423 /* Run from main thread */
424 static int init_profile(struct userdata
*u
) {
427 pa_assert(u
->profile
!= PA_BLUETOOTH_PROFILE_OFF
);
429 if (setup_transport(u
) < 0)
432 pa_assert(u
->transport
);
434 if (u
->profile
== PA_BLUETOOTH_PROFILE_A2DP_SINK
)
438 if (u
->profile
== PA_BLUETOOTH_PROFILE_A2DP_SOURCE
)
439 if (add_source(u
) < 0)
445 /* Run from main thread */
446 static char *cleanup_name(const char *name
) {
452 while ((*name
>= 1 && *name
<= 32) || *name
>= 127)
455 t
= pa_xstrdup(name
);
457 for (s
= d
= t
; *s
; s
++) {
459 if (*s
<= 32 || *s
>= 127 || *s
== '_') {
477 /* Run from main thread */
478 static pa_direction_t
get_profile_direction(pa_bluetooth_profile_t p
) {
479 static const pa_direction_t profile_direction
[] = {
480 [PA_BLUETOOTH_PROFILE_A2DP_SINK
] = PA_DIRECTION_OUTPUT
,
481 [PA_BLUETOOTH_PROFILE_A2DP_SOURCE
] = PA_DIRECTION_INPUT
,
482 [PA_BLUETOOTH_PROFILE_OFF
] = 0
485 return profile_direction
[p
];
488 /* Run from main thread */
489 static pa_available_t
get_port_availability(struct userdata
*u
, pa_direction_t direction
) {
490 pa_available_t result
= PA_AVAILABLE_NO
;
494 pa_assert(u
->device
);
496 for (i
= 0; i
< PA_BLUETOOTH_PROFILE_COUNT
; i
++) {
497 pa_bluetooth_transport
*transport
;
499 if (!(get_profile_direction(i
) & direction
))
502 if (!(transport
= u
->device
->transports
[i
]))
505 switch(transport
->state
) {
506 case PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED
:
509 case PA_BLUETOOTH_TRANSPORT_STATE_IDLE
:
510 if (result
== PA_AVAILABLE_NO
)
511 result
= PA_AVAILABLE_UNKNOWN
;
515 case PA_BLUETOOTH_TRANSPORT_STATE_PLAYING
:
516 return PA_AVAILABLE_YES
;
523 /* Run from main thread */
524 static pa_available_t
transport_state_to_availability(pa_bluetooth_transport_state_t state
) {
526 case PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED
:
527 return PA_AVAILABLE_NO
;
528 case PA_BLUETOOTH_TRANSPORT_STATE_PLAYING
:
529 return PA_AVAILABLE_YES
;
531 return PA_AVAILABLE_UNKNOWN
;
535 /* Run from main thread */
536 static void create_card_ports(struct userdata
*u
, pa_hashmap
*ports
) {
537 pa_device_port
*port
;
538 pa_device_port_new_data port_data
;
539 const char *name_prefix
, *input_description
, *output_description
;
543 pa_assert(u
->device
);
545 name_prefix
= "unknown";
546 input_description
= _("Bluetooth Input");
547 output_description
= _("Bluetooth Output");
549 switch (form_factor_from_class(u
->device
->class_of_device
)) {
550 case PA_BLUETOOTH_FORM_FACTOR_HEADSET
:
551 name_prefix
= "headset";
552 input_description
= output_description
= _("Headset");
555 case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE
:
556 name_prefix
= "handsfree";
557 input_description
= output_description
= _("Handsfree");
560 case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE
:
561 name_prefix
= "microphone";
562 input_description
= _("Microphone");
563 output_description
= _("Bluetooth Output");
566 case PA_BLUETOOTH_FORM_FACTOR_SPEAKER
:
567 name_prefix
= "speaker";
568 input_description
= _("Bluetooth Input");
569 output_description
= _("Speaker");
572 case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE
:
573 name_prefix
= "headphone";
574 input_description
= _("Bluetooth Input");
575 output_description
= _("Headphone");
578 case PA_BLUETOOTH_FORM_FACTOR_PORTABLE
:
579 name_prefix
= "portable";
580 input_description
= output_description
= _("Portable");
583 case PA_BLUETOOTH_FORM_FACTOR_CAR
:
585 input_description
= output_description
= _("Car");
588 case PA_BLUETOOTH_FORM_FACTOR_HIFI
:
589 name_prefix
= "hifi";
590 input_description
= output_description
= _("HiFi");
593 case PA_BLUETOOTH_FORM_FACTOR_PHONE
:
594 name_prefix
= "phone";
595 input_description
= output_description
= _("Phone");
598 case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
:
599 name_prefix
= "unknown";
600 input_description
= _("Bluetooth Input");
601 output_description
= _("Bluetooth Output");
605 u
->output_port_name
= pa_sprintf_malloc("%s-output", name_prefix
);
606 pa_device_port_new_data_init(&port_data
);
607 pa_device_port_new_data_set_name(&port_data
, u
->output_port_name
);
608 pa_device_port_new_data_set_description(&port_data
, output_description
);
609 pa_device_port_new_data_set_direction(&port_data
, PA_DIRECTION_OUTPUT
);
610 pa_device_port_new_data_set_available(&port_data
, get_port_availability(u
, PA_DIRECTION_OUTPUT
));
611 pa_assert_se(port
= pa_device_port_new(u
->core
, &port_data
, 0));
612 pa_assert_se(pa_hashmap_put(ports
, port
->name
, port
) >= 0);
613 pa_device_port_new_data_done(&port_data
);
615 u
->input_port_name
= pa_sprintf_malloc("%s-input", name_prefix
);
616 pa_device_port_new_data_init(&port_data
);
617 pa_device_port_new_data_set_name(&port_data
, u
->input_port_name
);
618 pa_device_port_new_data_set_description(&port_data
, input_description
);
619 pa_device_port_new_data_set_direction(&port_data
, PA_DIRECTION_INPUT
);
620 pa_device_port_new_data_set_available(&port_data
, get_port_availability(u
, PA_DIRECTION_INPUT
));
621 pa_assert_se(port
= pa_device_port_new(u
->core
, &port_data
, 0));
622 pa_assert_se(pa_hashmap_put(ports
, port
->name
, port
) >= 0);
623 pa_device_port_new_data_done(&port_data
);
626 /* Run from main thread */
627 static pa_card_profile
*create_card_profile(struct userdata
*u
, const char *uuid
, pa_hashmap
*ports
) {
628 pa_device_port
*input_port
, *output_port
;
629 pa_card_profile
*cp
= NULL
;
630 pa_bluetooth_profile_t
*p
;
632 pa_assert(u
->input_port_name
);
633 pa_assert(u
->output_port_name
);
634 pa_assert_se(input_port
= pa_hashmap_get(ports
, u
->input_port_name
));
635 pa_assert_se(output_port
= pa_hashmap_get(ports
, u
->output_port_name
));
637 if (pa_streq(uuid
, PA_BLUETOOTH_UUID_A2DP_SINK
)) {
638 /* TODO: Change this profile's name to a2dp_sink, to reflect the remote
639 * device's role and be consistent with the a2dp source profile */
640 cp
= pa_card_profile_new("a2dp", _("High Fidelity Playback (A2DP Sink)"), sizeof(pa_bluetooth_profile_t
));
644 cp
->max_sink_channels
= 2;
645 cp
->max_source_channels
= 0;
646 pa_hashmap_put(output_port
->profiles
, cp
->name
, cp
);
648 p
= PA_CARD_PROFILE_DATA(cp
);
649 *p
= PA_BLUETOOTH_PROFILE_A2DP_SINK
;
650 } else if (pa_streq(uuid
, PA_BLUETOOTH_UUID_A2DP_SOURCE
)) {
651 cp
= pa_card_profile_new("a2dp_source", _("High Fidelity Capture (A2DP Source)"), sizeof(pa_bluetooth_profile_t
));
655 cp
->max_sink_channels
= 0;
656 cp
->max_source_channels
= 2;
657 pa_hashmap_put(input_port
->profiles
, cp
->name
, cp
);
659 p
= PA_CARD_PROFILE_DATA(cp
);
660 *p
= PA_BLUETOOTH_PROFILE_A2DP_SOURCE
;
663 if (cp
&& u
->device
->transports
[*p
])
664 cp
->available
= transport_state_to_availability(u
->device
->transports
[*p
]->state
);
669 /* Run from main thread */
670 static int add_card(struct userdata
*u
) {
671 const pa_bluetooth_device
*d
;
672 pa_card_new_data data
;
674 pa_bluetooth_form_factor_t ff
;
676 pa_bluetooth_profile_t
*p
;
681 pa_assert(u
->device
);
685 pa_card_new_data_init(&data
);
686 data
.driver
= __FILE__
;
687 data
.module
= u
->module
;
689 alias
= cleanup_name(d
->alias
);
690 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, alias
);
693 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_STRING
, d
->address
);
694 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_API
, "bluez");
695 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_CLASS
, "sound");
696 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_BUS
, "bluetooth");
698 if ((ff
= form_factor_from_class(d
->class_of_device
)) != PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
)
699 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_FORM_FACTOR
, form_factor_to_string(ff
));
701 pa_proplist_sets(data
.proplist
, "bluez.path", d
->path
);
702 pa_proplist_setf(data
.proplist
, "bluez.class", "0x%06x", d
->class_of_device
);
703 pa_proplist_sets(data
.proplist
, "bluez.alias", d
->alias
);
704 data
.name
= pa_sprintf_malloc("bluez_card.%s", d
->address
);
705 data
.namereg_fail
= false;
707 create_card_ports(u
, data
.ports
);
709 PA_HASHMAP_FOREACH(uuid
, d
->uuids
, state
) {
710 cp
= create_card_profile(u
, uuid
, data
.ports
);
715 if (pa_hashmap_get(data
.profiles
, cp
->name
)) {
716 pa_card_profile_free(cp
);
720 pa_hashmap_put(data
.profiles
, cp
->name
, cp
);
723 pa_assert(!pa_hashmap_isempty(data
.profiles
));
725 cp
= pa_card_profile_new("off", _("Off"), sizeof(pa_bluetooth_profile_t
));
726 cp
->available
= PA_AVAILABLE_YES
;
727 p
= PA_CARD_PROFILE_DATA(cp
);
728 *p
= PA_BLUETOOTH_PROFILE_OFF
;
729 pa_hashmap_put(data
.profiles
, cp
->name
, cp
);
731 u
->card
= pa_card_new(u
->core
, &data
);
732 pa_card_new_data_done(&data
);
734 pa_log("Failed to allocate card.");
738 u
->card
->userdata
= u
;
740 p
= PA_CARD_PROFILE_DATA(u
->card
->active_profile
);
746 /* Run from main thread */
747 static pa_hook_result_t
device_connection_changed_cb(pa_bluetooth_discovery
*y
, const pa_bluetooth_device
*d
, struct userdata
*u
) {
751 if (d
!= u
->device
|| pa_bluetooth_device_any_transport_connected(d
))
754 pa_log_debug("Unloading module for device %s", d
->path
);
755 pa_module_unload(u
->core
, u
->module
, true);
760 int pa__init(pa_module
* m
) {
767 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
771 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
772 pa_log_error("Failed to parse module arguments");
776 if (!(path
= pa_modargs_get_value(ma
, "path", NULL
))) {
777 pa_log_error("Failed to get device path from module arguments");
781 if (!(u
->discovery
= pa_bluetooth_discovery_get(m
->core
)))
784 if (!(u
->device
= pa_bluetooth_discovery_get_device_by_path(u
->discovery
, path
))) {
785 pa_log_error("%s is unknown", path
);
791 u
->device_connection_changed_slot
=
792 pa_hook_connect(pa_bluetooth_discovery_hook(u
->discovery
, PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED
),
793 PA_HOOK_NORMAL
, (pa_hook_cb_t
) device_connection_changed_cb
, u
);
798 if (u
->profile
!= PA_BLUETOOTH_PROFILE_OFF
)
799 if (init_profile(u
) < 0)
806 pa_assert_se(pa_card_set_profile(u
->card
, "off", false) >= 0);
820 void pa__done(pa_module
*m
) {
825 if (!(u
= m
->userdata
))
828 if (u
->device_connection_changed_slot
)
829 pa_hook_slot_free(u
->device_connection_changed_slot
);
831 if (u
->sbc_info
.sbc_initialized
)
832 sbc_finish(&u
->sbc_info
.sbc
);
835 pa_card_free(u
->card
);
838 pa_bluetooth_discovery_unref(u
->discovery
);
840 pa_xfree(u
->output_port_name
);
841 pa_xfree(u
->input_port_name
);