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
;
75 pa_bluetooth_profile_t profile
;
76 char *output_port_name
;
77 char *input_port_name
;
81 size_t write_link_mtu
;
82 size_t read_block_size
;
83 size_t write_block_size
;
84 pa_sample_spec sample_spec
;
85 struct sbc_info sbc_info
;
88 typedef enum pa_bluetooth_form_factor
{
89 PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
,
90 PA_BLUETOOTH_FORM_FACTOR_HEADSET
,
91 PA_BLUETOOTH_FORM_FACTOR_HANDSFREE
,
92 PA_BLUETOOTH_FORM_FACTOR_MICROPHONE
,
93 PA_BLUETOOTH_FORM_FACTOR_SPEAKER
,
94 PA_BLUETOOTH_FORM_FACTOR_HEADPHONE
,
95 PA_BLUETOOTH_FORM_FACTOR_PORTABLE
,
96 PA_BLUETOOTH_FORM_FACTOR_CAR
,
97 PA_BLUETOOTH_FORM_FACTOR_HIFI
,
98 PA_BLUETOOTH_FORM_FACTOR_PHONE
,
99 } pa_bluetooth_form_factor_t
;
101 /* Run from main thread */
102 static pa_bluetooth_form_factor_t
form_factor_from_class(uint32_t class_of_device
) {
103 unsigned major
, minor
;
104 pa_bluetooth_form_factor_t r
;
106 static const pa_bluetooth_form_factor_t table
[] = {
107 [1] = PA_BLUETOOTH_FORM_FACTOR_HEADSET
,
108 [2] = PA_BLUETOOTH_FORM_FACTOR_HANDSFREE
,
109 [4] = PA_BLUETOOTH_FORM_FACTOR_MICROPHONE
,
110 [5] = PA_BLUETOOTH_FORM_FACTOR_SPEAKER
,
111 [6] = PA_BLUETOOTH_FORM_FACTOR_HEADPHONE
,
112 [7] = PA_BLUETOOTH_FORM_FACTOR_PORTABLE
,
113 [8] = PA_BLUETOOTH_FORM_FACTOR_CAR
,
114 [10] = PA_BLUETOOTH_FORM_FACTOR_HIFI
118 * See Bluetooth Assigned Numbers:
119 * https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
121 major
= (class_of_device
>> 8) & 0x1F;
122 minor
= (class_of_device
>> 2) & 0x3F;
126 return PA_BLUETOOTH_FORM_FACTOR_PHONE
;
130 pa_log_debug("Unknown Bluetooth major device class %u", major
);
131 return PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
;
134 r
= minor
< PA_ELEMENTSOF(table
) ? table
[minor
] : PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
;
137 pa_log_debug("Unknown Bluetooth minor device class %u", minor
);
142 /* Run from main thread */
143 static const char *form_factor_to_string(pa_bluetooth_form_factor_t ff
) {
145 case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
:
147 case PA_BLUETOOTH_FORM_FACTOR_HEADSET
:
149 case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE
:
151 case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE
:
153 case PA_BLUETOOTH_FORM_FACTOR_SPEAKER
:
155 case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE
:
157 case PA_BLUETOOTH_FORM_FACTOR_PORTABLE
:
159 case PA_BLUETOOTH_FORM_FACTOR_CAR
:
161 case PA_BLUETOOTH_FORM_FACTOR_HIFI
:
163 case PA_BLUETOOTH_FORM_FACTOR_PHONE
:
167 pa_assert_not_reached();
170 /* Run from main thread */
171 static void connect_ports(struct userdata
*u
, void *new_data
, pa_direction_t direction
) {
172 pa_device_port
*port
;
174 if (direction
== PA_DIRECTION_OUTPUT
) {
175 pa_sink_new_data
*sink_new_data
= new_data
;
177 pa_assert_se(port
= pa_hashmap_get(u
->card
->ports
, u
->output_port_name
));
178 pa_assert_se(pa_hashmap_put(sink_new_data
->ports
, port
->name
, port
) >= 0);
179 pa_device_port_ref(port
);
181 pa_source_new_data
*source_new_data
= new_data
;
183 pa_assert_se(port
= pa_hashmap_get(u
->card
->ports
, u
->input_port_name
));
184 pa_assert_se(pa_hashmap_put(source_new_data
->ports
, port
->name
, port
) >= 0);
185 pa_device_port_ref(port
);
189 static int transport_acquire(struct userdata
*u
, bool optional
) {
190 pa_assert(u
->transport
);
192 if (u
->transport_acquired
)
195 pa_log_debug("Acquiring transport %s", u
->transport
->path
);
197 u
->stream_fd
= u
->transport
->acquire(u
->transport
, optional
, &u
->read_link_mtu
, &u
->write_link_mtu
);
198 if (u
->stream_fd
< 0)
201 u
->transport_acquired
= true;
202 pa_log_info("Transport %s acquired: fd %d", u
->transport
->path
, u
->stream_fd
);
207 /* Run from main thread */
208 static int add_sink(struct userdata
*u
) {
209 pa_sink_new_data data
;
211 pa_assert(u
->transport
);
213 pa_sink_new_data_init(&data
);
214 data
.module
= u
->module
;
216 data
.driver
= __FILE__
;
217 data
.name
= pa_sprintf_malloc("bluez_sink.%s", u
->device
->address
);
218 data
.namereg_fail
= false;
219 pa_proplist_sets(data
.proplist
, "bluetooth.protocol", pa_bluetooth_profile_to_string(u
->profile
));
220 pa_sink_new_data_set_sample_spec(&data
, &u
->sample_spec
);
222 connect_ports(u
, &data
, PA_DIRECTION_OUTPUT
);
224 if (!u
->transport_acquired
)
225 switch (u
->profile
) {
226 case PA_BLUETOOTH_PROFILE_A2DP_SINK
:
227 /* Profile switch should have failed */
228 case PA_BLUETOOTH_PROFILE_A2DP_SOURCE
:
229 case PA_BLUETOOTH_PROFILE_OFF
:
230 pa_assert_not_reached();
234 u
->sink
= pa_sink_new(u
->core
, &data
, PA_SINK_HARDWARE
|PA_SINK_LATENCY
);
235 pa_sink_new_data_done(&data
);
237 pa_log_error("Failed to create sink");
241 u
->sink
->userdata
= u
;
246 /* Run from main thread */
247 static void transport_config(struct userdata
*u
) {
248 sbc_info_t
*sbc_info
= &u
->sbc_info
;
251 pa_assert(u
->transport
);
253 u
->sample_spec
.format
= PA_SAMPLE_S16LE
;
254 config
= (a2dp_sbc_t
*) u
->transport
->config
;
256 if (sbc_info
->sbc_initialized
)
257 sbc_reinit(&sbc_info
->sbc
, 0);
259 sbc_init(&sbc_info
->sbc
, 0);
260 sbc_info
->sbc_initialized
= true;
262 switch (config
->frequency
) {
263 case SBC_SAMPLING_FREQ_16000
:
264 sbc_info
->sbc
.frequency
= SBC_FREQ_16000
;
265 u
->sample_spec
.rate
= 16000U;
267 case SBC_SAMPLING_FREQ_32000
:
268 sbc_info
->sbc
.frequency
= SBC_FREQ_32000
;
269 u
->sample_spec
.rate
= 32000U;
271 case SBC_SAMPLING_FREQ_44100
:
272 sbc_info
->sbc
.frequency
= SBC_FREQ_44100
;
273 u
->sample_spec
.rate
= 44100U;
275 case SBC_SAMPLING_FREQ_48000
:
276 sbc_info
->sbc
.frequency
= SBC_FREQ_48000
;
277 u
->sample_spec
.rate
= 48000U;
280 pa_assert_not_reached();
283 switch (config
->channel_mode
) {
284 case SBC_CHANNEL_MODE_MONO
:
285 sbc_info
->sbc
.mode
= SBC_MODE_MONO
;
286 u
->sample_spec
.channels
= 1;
288 case SBC_CHANNEL_MODE_DUAL_CHANNEL
:
289 sbc_info
->sbc
.mode
= SBC_MODE_DUAL_CHANNEL
;
290 u
->sample_spec
.channels
= 2;
292 case SBC_CHANNEL_MODE_STEREO
:
293 sbc_info
->sbc
.mode
= SBC_MODE_STEREO
;
294 u
->sample_spec
.channels
= 2;
296 case SBC_CHANNEL_MODE_JOINT_STEREO
:
297 sbc_info
->sbc
.mode
= SBC_MODE_JOINT_STEREO
;
298 u
->sample_spec
.channels
= 2;
301 pa_assert_not_reached();
304 switch (config
->allocation_method
) {
305 case SBC_ALLOCATION_SNR
:
306 sbc_info
->sbc
.allocation
= SBC_AM_SNR
;
308 case SBC_ALLOCATION_LOUDNESS
:
309 sbc_info
->sbc
.allocation
= SBC_AM_LOUDNESS
;
312 pa_assert_not_reached();
315 switch (config
->subbands
) {
317 sbc_info
->sbc
.subbands
= SBC_SB_4
;
320 sbc_info
->sbc
.subbands
= SBC_SB_8
;
323 pa_assert_not_reached();
326 switch (config
->block_length
) {
327 case SBC_BLOCK_LENGTH_4
:
328 sbc_info
->sbc
.blocks
= SBC_BLK_4
;
330 case SBC_BLOCK_LENGTH_8
:
331 sbc_info
->sbc
.blocks
= SBC_BLK_8
;
333 case SBC_BLOCK_LENGTH_12
:
334 sbc_info
->sbc
.blocks
= SBC_BLK_12
;
336 case SBC_BLOCK_LENGTH_16
:
337 sbc_info
->sbc
.blocks
= SBC_BLK_16
;
340 pa_assert_not_reached();
343 sbc_info
->min_bitpool
= config
->min_bitpool
;
344 sbc_info
->max_bitpool
= config
->max_bitpool
;
346 /* Set minimum bitpool for source to get the maximum possible block_size */
347 sbc_info
->sbc
.bitpool
= u
->profile
== PA_BLUETOOTH_PROFILE_A2DP_SINK
? sbc_info
->max_bitpool
: sbc_info
->min_bitpool
;
348 sbc_info
->codesize
= sbc_get_codesize(&sbc_info
->sbc
);
349 sbc_info
->frame_length
= sbc_get_frame_length(&sbc_info
->sbc
);
351 pa_log_info("SBC parameters: allocation=%u, subbands=%u, blocks=%u, bitpool=%u",
352 sbc_info
->sbc
.allocation
, sbc_info
->sbc
.subbands
, sbc_info
->sbc
.blocks
, sbc_info
->sbc
.bitpool
);
355 /* Run from main thread */
356 static int setup_transport(struct userdata
*u
) {
357 pa_bluetooth_transport
*t
;
360 pa_assert(!u
->transport
);
361 pa_assert(u
->profile
!= PA_BLUETOOTH_PROFILE_OFF
);
363 /* check if profile has a transport */
364 t
= u
->device
->transports
[u
->profile
];
365 if (!t
|| t
->state
<= PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED
) {
366 pa_log_warn("Profile has no transport");
372 if (u
->profile
== PA_BLUETOOTH_PROFILE_A2DP_SOURCE
)
373 transport_acquire(u
, true); /* In case of error, the sink/sources will be created suspended */
374 else if (transport_acquire(u
, false) < 0)
375 return -1; /* We need to fail here until the interactions with module-suspend-on-idle and alike get improved */
382 /* Run from main thread */
383 static int init_profile(struct userdata
*u
) {
386 pa_assert(u
->profile
!= PA_BLUETOOTH_PROFILE_OFF
);
388 if (setup_transport(u
) < 0)
391 pa_assert(u
->transport
);
393 if (u
->profile
== PA_BLUETOOTH_PROFILE_A2DP_SINK
)
397 /* TODO: add source */
402 /* Run from main thread */
403 static char *cleanup_name(const char *name
) {
409 while ((*name
>= 1 && *name
<= 32) || *name
>= 127)
412 t
= pa_xstrdup(name
);
414 for (s
= d
= t
; *s
; s
++) {
416 if (*s
<= 32 || *s
>= 127 || *s
== '_') {
434 /* Run from main thread */
435 static pa_direction_t
get_profile_direction(pa_bluetooth_profile_t p
) {
436 static const pa_direction_t profile_direction
[] = {
437 [PA_BLUETOOTH_PROFILE_A2DP_SINK
] = PA_DIRECTION_OUTPUT
,
438 [PA_BLUETOOTH_PROFILE_A2DP_SOURCE
] = PA_DIRECTION_INPUT
,
439 [PA_BLUETOOTH_PROFILE_OFF
] = 0
442 return profile_direction
[p
];
445 /* Run from main thread */
446 static pa_available_t
get_port_availability(struct userdata
*u
, pa_direction_t direction
) {
447 pa_available_t result
= PA_AVAILABLE_NO
;
451 pa_assert(u
->device
);
453 for (i
= 0; i
< PA_BLUETOOTH_PROFILE_COUNT
; i
++) {
454 pa_bluetooth_transport
*transport
;
456 if (!(get_profile_direction(i
) & direction
))
459 if (!(transport
= u
->device
->transports
[i
]))
462 switch(transport
->state
) {
463 case PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED
:
466 case PA_BLUETOOTH_TRANSPORT_STATE_IDLE
:
467 if (result
== PA_AVAILABLE_NO
)
468 result
= PA_AVAILABLE_UNKNOWN
;
472 case PA_BLUETOOTH_TRANSPORT_STATE_PLAYING
:
473 return PA_AVAILABLE_YES
;
480 /* Run from main thread */
481 static pa_available_t
transport_state_to_availability(pa_bluetooth_transport_state_t state
) {
483 case PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED
:
484 return PA_AVAILABLE_NO
;
485 case PA_BLUETOOTH_TRANSPORT_STATE_PLAYING
:
486 return PA_AVAILABLE_YES
;
488 return PA_AVAILABLE_UNKNOWN
;
492 /* Run from main thread */
493 static void create_card_ports(struct userdata
*u
, pa_hashmap
*ports
) {
494 pa_device_port
*port
;
495 pa_device_port_new_data port_data
;
496 const char *name_prefix
, *input_description
, *output_description
;
500 pa_assert(u
->device
);
502 name_prefix
= "unknown";
503 input_description
= _("Bluetooth Input");
504 output_description
= _("Bluetooth Output");
506 switch (form_factor_from_class(u
->device
->class_of_device
)) {
507 case PA_BLUETOOTH_FORM_FACTOR_HEADSET
:
508 name_prefix
= "headset";
509 input_description
= output_description
= _("Headset");
512 case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE
:
513 name_prefix
= "handsfree";
514 input_description
= output_description
= _("Handsfree");
517 case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE
:
518 name_prefix
= "microphone";
519 input_description
= _("Microphone");
520 output_description
= _("Bluetooth Output");
523 case PA_BLUETOOTH_FORM_FACTOR_SPEAKER
:
524 name_prefix
= "speaker";
525 input_description
= _("Bluetooth Input");
526 output_description
= _("Speaker");
529 case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE
:
530 name_prefix
= "headphone";
531 input_description
= _("Bluetooth Input");
532 output_description
= _("Headphone");
535 case PA_BLUETOOTH_FORM_FACTOR_PORTABLE
:
536 name_prefix
= "portable";
537 input_description
= output_description
= _("Portable");
540 case PA_BLUETOOTH_FORM_FACTOR_CAR
:
542 input_description
= output_description
= _("Car");
545 case PA_BLUETOOTH_FORM_FACTOR_HIFI
:
546 name_prefix
= "hifi";
547 input_description
= output_description
= _("HiFi");
550 case PA_BLUETOOTH_FORM_FACTOR_PHONE
:
551 name_prefix
= "phone";
552 input_description
= output_description
= _("Phone");
555 case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
:
556 name_prefix
= "unknown";
557 input_description
= _("Bluetooth Input");
558 output_description
= _("Bluetooth Output");
562 u
->output_port_name
= pa_sprintf_malloc("%s-output", name_prefix
);
563 pa_device_port_new_data_init(&port_data
);
564 pa_device_port_new_data_set_name(&port_data
, u
->output_port_name
);
565 pa_device_port_new_data_set_description(&port_data
, output_description
);
566 pa_device_port_new_data_set_direction(&port_data
, PA_DIRECTION_OUTPUT
);
567 pa_device_port_new_data_set_available(&port_data
, get_port_availability(u
, PA_DIRECTION_OUTPUT
));
568 pa_assert_se(port
= pa_device_port_new(u
->core
, &port_data
, 0));
569 pa_assert_se(pa_hashmap_put(ports
, port
->name
, port
) >= 0);
570 pa_device_port_new_data_done(&port_data
);
572 u
->input_port_name
= pa_sprintf_malloc("%s-input", name_prefix
);
573 pa_device_port_new_data_init(&port_data
);
574 pa_device_port_new_data_set_name(&port_data
, u
->input_port_name
);
575 pa_device_port_new_data_set_description(&port_data
, input_description
);
576 pa_device_port_new_data_set_direction(&port_data
, PA_DIRECTION_INPUT
);
577 pa_device_port_new_data_set_available(&port_data
, get_port_availability(u
, PA_DIRECTION_INPUT
));
578 pa_assert_se(port
= pa_device_port_new(u
->core
, &port_data
, 0));
579 pa_assert_se(pa_hashmap_put(ports
, port
->name
, port
) >= 0);
580 pa_device_port_new_data_done(&port_data
);
583 /* Run from main thread */
584 static pa_card_profile
*create_card_profile(struct userdata
*u
, const char *uuid
, pa_hashmap
*ports
) {
585 pa_device_port
*input_port
, *output_port
;
586 pa_card_profile
*cp
= NULL
;
587 pa_bluetooth_profile_t
*p
;
589 pa_assert(u
->input_port_name
);
590 pa_assert(u
->output_port_name
);
591 pa_assert_se(input_port
= pa_hashmap_get(ports
, u
->input_port_name
));
592 pa_assert_se(output_port
= pa_hashmap_get(ports
, u
->output_port_name
));
594 if (pa_streq(uuid
, PA_BLUETOOTH_UUID_A2DP_SINK
)) {
595 /* TODO: Change this profile's name to a2dp_sink, to reflect the remote
596 * device's role and be consistent with the a2dp source profile */
597 cp
= pa_card_profile_new("a2dp", _("High Fidelity Playback (A2DP Sink)"), sizeof(pa_bluetooth_profile_t
));
601 cp
->max_sink_channels
= 2;
602 cp
->max_source_channels
= 0;
603 pa_hashmap_put(output_port
->profiles
, cp
->name
, cp
);
605 p
= PA_CARD_PROFILE_DATA(cp
);
606 *p
= PA_BLUETOOTH_PROFILE_A2DP_SINK
;
607 } else if (pa_streq(uuid
, PA_BLUETOOTH_UUID_A2DP_SOURCE
)) {
608 cp
= pa_card_profile_new("a2dp_source", _("High Fidelity Capture (A2DP Source)"), sizeof(pa_bluetooth_profile_t
));
612 cp
->max_sink_channels
= 0;
613 cp
->max_source_channels
= 2;
614 pa_hashmap_put(input_port
->profiles
, cp
->name
, cp
);
616 p
= PA_CARD_PROFILE_DATA(cp
);
617 *p
= PA_BLUETOOTH_PROFILE_A2DP_SOURCE
;
620 if (cp
&& u
->device
->transports
[*p
])
621 cp
->available
= transport_state_to_availability(u
->device
->transports
[*p
]->state
);
626 /* Run from main thread */
627 static int add_card(struct userdata
*u
) {
628 const pa_bluetooth_device
*d
;
629 pa_card_new_data data
;
631 pa_bluetooth_form_factor_t ff
;
633 pa_bluetooth_profile_t
*p
;
638 pa_assert(u
->device
);
642 pa_card_new_data_init(&data
);
643 data
.driver
= __FILE__
;
644 data
.module
= u
->module
;
646 alias
= cleanup_name(d
->alias
);
647 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, alias
);
650 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_STRING
, d
->address
);
651 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_API
, "bluez");
652 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_CLASS
, "sound");
653 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_BUS
, "bluetooth");
655 if ((ff
= form_factor_from_class(d
->class_of_device
)) != PA_BLUETOOTH_FORM_FACTOR_UNKNOWN
)
656 pa_proplist_sets(data
.proplist
, PA_PROP_DEVICE_FORM_FACTOR
, form_factor_to_string(ff
));
658 pa_proplist_sets(data
.proplist
, "bluez.path", d
->path
);
659 pa_proplist_setf(data
.proplist
, "bluez.class", "0x%06x", d
->class_of_device
);
660 pa_proplist_sets(data
.proplist
, "bluez.alias", d
->alias
);
661 data
.name
= pa_sprintf_malloc("bluez_card.%s", d
->address
);
662 data
.namereg_fail
= false;
664 create_card_ports(u
, data
.ports
);
666 PA_HASHMAP_FOREACH(uuid
, d
->uuids
, state
) {
667 cp
= create_card_profile(u
, uuid
, data
.ports
);
672 if (pa_hashmap_get(data
.profiles
, cp
->name
)) {
673 pa_card_profile_free(cp
);
677 pa_hashmap_put(data
.profiles
, cp
->name
, cp
);
680 pa_assert(!pa_hashmap_isempty(data
.profiles
));
682 cp
= pa_card_profile_new("off", _("Off"), sizeof(pa_bluetooth_profile_t
));
683 cp
->available
= PA_AVAILABLE_YES
;
684 p
= PA_CARD_PROFILE_DATA(cp
);
685 *p
= PA_BLUETOOTH_PROFILE_OFF
;
686 pa_hashmap_put(data
.profiles
, cp
->name
, cp
);
688 u
->card
= pa_card_new(u
->core
, &data
);
689 pa_card_new_data_done(&data
);
691 pa_log("Failed to allocate card.");
695 u
->card
->userdata
= u
;
697 p
= PA_CARD_PROFILE_DATA(u
->card
->active_profile
);
703 /* Run from main thread */
704 static pa_hook_result_t
device_connection_changed_cb(pa_bluetooth_discovery
*y
, const pa_bluetooth_device
*d
, struct userdata
*u
) {
708 if (d
!= u
->device
|| pa_bluetooth_device_any_transport_connected(d
))
711 pa_log_debug("Unloading module for device %s", d
->path
);
712 pa_module_unload(u
->core
, u
->module
, true);
717 int pa__init(pa_module
* m
) {
724 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
728 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
729 pa_log_error("Failed to parse module arguments");
733 if (!(path
= pa_modargs_get_value(ma
, "path", NULL
))) {
734 pa_log_error("Failed to get device path from module arguments");
738 if (!(u
->discovery
= pa_bluetooth_discovery_get(m
->core
)))
741 if (!(u
->device
= pa_bluetooth_discovery_get_device_by_path(u
->discovery
, path
))) {
742 pa_log_error("%s is unknown", path
);
748 u
->device_connection_changed_slot
=
749 pa_hook_connect(pa_bluetooth_discovery_hook(u
->discovery
, PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED
),
750 PA_HOOK_NORMAL
, (pa_hook_cb_t
) device_connection_changed_cb
, u
);
755 if (u
->profile
!= PA_BLUETOOTH_PROFILE_OFF
)
756 if (init_profile(u
) < 0)
763 pa_assert_se(pa_card_set_profile(u
->card
, "off", false) >= 0);
777 void pa__done(pa_module
*m
) {
782 if (!(u
= m
->userdata
))
785 if (u
->device_connection_changed_slot
)
786 pa_hook_slot_free(u
->device_connection_changed_slot
);
788 if (u
->sbc_info
.sbc_initialized
)
789 sbc_finish(&u
->sbc_info
.sbc
);
792 pa_card_free(u
->card
);
795 pa_bluetooth_discovery_unref(u
->discovery
);
797 pa_xfree(u
->output_port_name
);
798 pa_xfree(u
->input_port_name
);