Skip to content
This repository has been archived by the owner on Jan 25, 2021. It is now read-only.

Commit

Permalink
Express the codec being used with pulseaudio; Close #17
Browse files Browse the repository at this point in the history
  • Loading branch information
EHfive committed Feb 12, 2019
1 parent 435730d commit 03d7a2a
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 19 deletions.
45 changes: 45 additions & 0 deletions src/modules/bluetooth/bluez5-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,51 @@ const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile) {
return NULL;
}

const char *pa_bluetooth_a2dp_profile_to_string(pa_a2dp_codec_index_t codec_index) {
switch(codec_index) {
case PA_A2DP_SINK_SBC:
return "a2dp_source_sbc";
case PA_A2DP_SINK_AAC:
return "a2dp_source_aac";
case PA_A2DP_SINK_APTX:
return "a2dp_source_aptx";
case PA_A2DP_SINK_APTX_HD:
return "a2dp_source_aptx_hd";
case PA_A2DP_SOURCE_SBC:
return "a2dp_sink_sbc";
case PA_A2DP_SOURCE_AAC:
return "a2dp_sink_aac";
case PA_A2DP_SOURCE_APTX:
return "a2dp_sink_aptx";
case PA_A2DP_SOURCE_APTX_HD:
return "a2dp_sink_aptx_hd";
case PA_A2DP_SOURCE_LDAC:
return "a2dp_sink_ldac";
default:
return NULL;
}
}

const char *pa_bluetooth_profile_codec_to_string(pa_bluetooth_profile_t profile, const pa_a2dp_codec_t *a2dp_codec) {
pa_a2dp_codec_index_t codec_index = PA_A2DP_CODEC_INDEX_UNAVAILABLE;
bool others = false;
if(profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) {
pa_assert(a2dp_codec);
pa_a2dp_a2dp_codec_to_codec_index(a2dp_codec, false, &codec_index);
} else if (profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE) {
pa_assert(a2dp_codec);
pa_a2dp_a2dp_codec_to_codec_index(a2dp_codec, true, &codec_index);
} else
others = true;

if (PA_A2DP_CODEC_INDEX_UNAVAILABLE != codec_index)
return pa_bluetooth_a2dp_profile_to_string(codec_index);
else if (others)
return pa_bluetooth_profile_to_string(profile);

return NULL;
}

static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage *m, void *userdata) {
pa_bluetooth_discovery *y = userdata;
pa_bluetooth_device *d;
Expand Down
2 changes: 2 additions & 0 deletions src/modules/bluetooth/bluez5-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_address(pa_bluetooth_d
pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *y, pa_bluetooth_hook_t hook);

const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile);
const char *pa_bluetooth_a2dp_profile_to_string(pa_a2dp_codec_index_t codec_index);
const char *pa_bluetooth_profile_codec_to_string(pa_bluetooth_profile_t profile, const pa_a2dp_codec_t *a2dp_codec);

static inline bool pa_bluetooth_uuid_is_hsp_hs(const char *uuid) {
return pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS) || pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS_ALT);
Expand Down
14 changes: 8 additions & 6 deletions src/modules/bluetooth/module-bluetooth-policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <pulsecore/source.h>
#include <pulsecore/core-util.h>

#define pa_bt_prefix_eq(a,b) (pa_strneq((a),(b),(PA_MIN((strlen((a))),(strlen((b)))))))

PA_MODULE_AUTHOR("Frédéric Dalleau, Pali Rohár");
PA_MODULE_DESCRIPTION("Policy module to make using bluetooth devices out-of-the-box easier");
PA_MODULE_VERSION(PACKAGE_VERSION);
Expand Down Expand Up @@ -85,7 +87,7 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
if (!s)
return PA_HOOK_OK;

if (u->enable_a2dp_source && pa_streq(s, "a2dp_source"))
if (u->enable_a2dp_source && pa_bt_prefix_eq(s, "a2dp_source"))
role = "music";
else if (u->enable_ag && pa_streq(s, "headset_audio_gateway"))
role = "phone";
Expand Down Expand Up @@ -154,7 +156,7 @@ static void card_set_profile(struct userdata *u, pa_card *card, bool revert_to_a

/* Check for correct profile based on revert_to_a2dp */
if (revert_to_a2dp) {
if (!pa_streq(profile->name, "a2dp") && !pa_streq(profile->name, "a2dp_sink"))
if (!pa_streq(profile->name, "a2dp") && !pa_bt_prefix_eq(profile->name, "a2dp_sink"))
continue;
} else {
if (!pa_streq(profile->name, "hsp") && !pa_streq(profile->name, "headset_head_unit"))
Expand Down Expand Up @@ -196,11 +198,11 @@ static void switch_profile(pa_card *card, bool revert_to_a2dp, void *userdata) {
return;

/* Skip card if already has active a2dp profile */
if (pa_streq(card->active_profile->name, "a2dp") || pa_streq(card->active_profile->name, "a2dp_sink"))
if (pa_streq(card->active_profile->name, "a2dp") || pa_strneq(card->active_profile->name, "a2dp_sink", strlen("a2dp_sink")))
return;
} else {
/* Skip card if does not have active a2dp profile */
if (!pa_streq(card->active_profile->name, "a2dp") && !pa_streq(card->active_profile->name, "a2dp_sink"))
if (!pa_streq(card->active_profile->name, "a2dp") && !pa_bt_prefix_eq(card->active_profile->name, "a2dp_sink"))
return;

/* Skip card if already has active hsp profile */
Expand Down Expand Up @@ -308,7 +310,7 @@ static pa_hook_result_t card_init_profile_hook_callback(pa_core *c, pa_card *car
/* Ignore card if has already set other initial profile than a2dp */
if (card->active_profile &&
!pa_streq(card->active_profile->name, "a2dp") &&
!pa_streq(card->active_profile->name, "a2dp_sink"))
!pa_bt_prefix_eq(card->active_profile->name, "a2dp_sink"))
return PA_HOOK_OK;

/* Set initial profile to hsp */
Expand Down Expand Up @@ -360,7 +362,7 @@ static pa_hook_result_t profile_available_hook_callback(pa_core *c, pa_card_prof
return PA_HOOK_OK;

/* Do not automatically switch profiles for headsets, just in case */
if (pa_streq(profile->name, "a2dp_sink") || pa_streq(profile->name, "headset_head_unit"))
if (pa_bt_prefix_eq(profile->name, "a2dp_sink") || pa_streq(profile->name, "headset_head_unit"))
return PA_HOOK_OK;

is_active_profile = card->active_profile == profile;
Expand Down
104 changes: 91 additions & 13 deletions src/modules/bluetooth/module-bluez5-device.c
Original file line number Diff line number Diff line change
Expand Up @@ -1796,23 +1796,58 @@ static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
pa_device_port_new_data_done(&port_data);
}

static const char *a2dp_codec_index_to_description(pa_a2dp_codec_index_t codec_index) {
switch(codec_index) {
case PA_A2DP_SINK_SBC:
return "High Fidelity Capture (A2DP Source: SBC)";
case PA_A2DP_SINK_AAC:
return "High Fidelity Capture (A2DP Source: AAC)";
case PA_A2DP_SINK_APTX:
return "High Fidelity Capture (A2DP Source: APTX)";
case PA_A2DP_SINK_APTX_HD:
return "High Fidelity Capture (A2DP Source: aptX HD)";
case PA_A2DP_SOURCE_SBC:
return "High Fidelity Playback (A2DP Sink: SBC)";
case PA_A2DP_SOURCE_AAC:
return "High Fidelity Playback (A2DP Sink: AAC)";
case PA_A2DP_SOURCE_APTX:
return "High Fidelity Playback (A2DP Sink: aptX)";
case PA_A2DP_SOURCE_APTX_HD:
return "High Fidelity Playback (A2DP Sink: aptX HD)";
case PA_A2DP_SOURCE_LDAC:
return "High Fidelity Playback (A2DP Sink: LDAC)";
default:
return "Unknown";
}
}

/* Run from main thread */
static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_profile_t profile, pa_hashmap *ports) {
static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_profile_t profile, pa_a2dp_codec_index_t codec_index, pa_hashmap *ports) {
pa_device_port *input_port, *output_port;
const char *name;
const char *name, *desc;
pa_card_profile *cp = NULL;
pa_bluetooth_profile_t *p;
pa_bluetooth_transport *t;
const pa_a2dp_codec_t *a2dp_codec;

pa_assert(u->input_port_name);
pa_assert(u->output_port_name);
pa_assert_se(input_port = pa_hashmap_get(ports, u->input_port_name));
pa_assert_se(output_port = pa_hashmap_get(ports, u->output_port_name));

name = pa_bluetooth_profile_to_string(profile);
pa_a2dp_codec_index_to_a2dp_codec(codec_index, &a2dp_codec);

if(a2dp_codec)
name = pa_bluetooth_a2dp_profile_to_string(codec_index);
else
name = pa_bluetooth_profile_to_string(profile);

switch (profile) {
case PA_BLUETOOTH_PROFILE_A2DP_SINK:
cp = pa_card_profile_new(name, _("High Fidelity Playback (A2DP Sink)"), sizeof(pa_bluetooth_profile_t));
pa_assert_se(pa_a2dp_codec_index_is_source(codec_index));
pa_assert_se(a2dp_codec != NULL && a2dp_codec->a2dp_source);

cp = pa_card_profile_new(name, _(a2dp_codec_index_to_description(codec_index)), sizeof(pa_bluetooth_profile_t));
cp->priority = 40;
cp->n_sinks = 1;
cp->n_sources = 0;
Expand All @@ -1824,7 +1859,10 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro
break;

case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
cp = pa_card_profile_new(name, _("High Fidelity Capture (A2DP Source)"), sizeof(pa_bluetooth_profile_t));
pa_assert_se(pa_a2dp_codec_index_is_sink(codec_index));
pa_assert_se(a2dp_codec != NULL && a2dp_codec->a2dp_sink);

cp = pa_card_profile_new(name, _(a2dp_codec_index_to_description(codec_index)), sizeof(pa_bluetooth_profile_t));
cp->priority = 20;
cp->n_sinks = 0;
cp->n_sources = 1;
Expand Down Expand Up @@ -1867,9 +1905,12 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro

*p = profile;

if (u->device->transports[*p])
cp->available = transport_state_to_availability(u->device->transports[*p]->state);
else
if ((t = u->device->transports[*p])){
if(t->a2dp_codec == a2dp_codec)
cp->available = transport_state_to_availability(u->device->transports[*p]->state);
else
cp->available = PA_AVAILABLE_NO;
} else
cp->available = PA_AVAILABLE_NO;

return cp;
Expand Down Expand Up @@ -1974,15 +2015,52 @@ static int add_card(struct userdata *u) {

PA_HASHMAP_FOREACH(uuid, d->uuids, state) {
pa_bluetooth_profile_t profile;
struct profile_codec {
const char *profile_string;
pa_a2dp_codec_index_t codec_index;
} *profiles;
size_t profiles_size;

if (uuid_to_profile(uuid, &profile) < 0)
continue;

if (pa_hashmap_get(data.profiles, pa_bluetooth_profile_to_string(profile)))
continue;
if (profile != PA_BLUETOOTH_PROFILE_A2DP_SINK && profile != PA_BLUETOOTH_PROFILE_A2DP_SOURCE) {
profiles_size = 1;
profiles = pa_xnew(struct profile_codec, profiles_size);
profiles[0].profile_string = pa_bluetooth_profile_to_string(profile);
profiles[0].codec_index = PA_A2DP_CODEC_INDEX_UNAVAILABLE;
} else {
pa_a2dp_codec_index_t sink_indices[] = {PA_A2DP_SOURCE_SBC, PA_A2DP_SOURCE_AAC, PA_A2DP_SOURCE_APTX,
PA_A2DP_SOURCE_APTX_HD, PA_A2DP_SOURCE_LDAC};
pa_a2dp_codec_index_t source_indices[] = {PA_A2DP_SINK_SBC, PA_A2DP_SINK_AAC, PA_A2DP_SINK_APTX,
PA_A2DP_SINK_APTX_HD};
pa_a2dp_codec_index_t *indices;
if (profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) {
indices = sink_indices;
profiles_size = PA_ELEMENTSOF(sink_indices);

} else {
indices = source_indices;
profiles_size = PA_ELEMENTSOF(source_indices);
}
profiles = pa_xnew(struct profile_codec, profiles_size);
for(int i = 0; i < profiles_size; ++i) {
profiles[i].profile_string = pa_bluetooth_a2dp_profile_to_string(indices[i]);
profiles[i].codec_index = indices[i];

}

}

for(int i=0; i< profiles_size; ++i){

if (pa_hashmap_get(data.profiles, profiles[i].profile_string))
continue;
cp = create_card_profile(u, profile, profiles[i].codec_index, data.ports);
pa_hashmap_put(data.profiles, cp->name, cp);
}

cp = create_card_profile(u, profile, data.ports);
pa_hashmap_put(data.profiles, cp->name, cp);
pa_xfree(profiles);
}

pa_assert(!pa_hashmap_isempty(data.profiles));
Expand Down Expand Up @@ -2021,7 +2099,7 @@ static void handle_transport_state_change(struct userdata *u, struct pa_bluetoot

pa_assert(u);
pa_assert(t);
pa_assert_se(cp = pa_hashmap_get(u->card->profiles, pa_bluetooth_profile_to_string(t->profile)));
pa_assert_se(cp = pa_hashmap_get(u->card->profiles, pa_bluetooth_profile_codec_to_string(t->profile, t->a2dp_codec)));

oldavail = cp->available;
pa_card_profile_set_available(cp, transport_state_to_availability(t->state));
Expand Down

0 comments on commit 03d7a2a

Please sign in to comment.