mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-05 13:29:57 -05:00
bluetooth: complete bluetooth profile separation
This is a follow-up change to review of these series on pulseaudio-discuss https://lists.freedesktop.org/archives/pulseaudio-discuss/2017-September/028801.html Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/491>
This commit is contained in:
parent
815dd2d627
commit
698fb3bc26
6 changed files with 65 additions and 37 deletions
|
|
@ -562,7 +562,7 @@ static void set_speaker_gain(pa_bluetooth_transport *t, uint16_t gain) {
|
||||||
/* If we are in the AG role, we send a command to the head set to change
|
/* If we are in the AG role, we send a command to the head set to change
|
||||||
* the speaker gain. In the HS role, source and sink are swapped, so
|
* the speaker gain. In the HS role, source and sink are swapped, so
|
||||||
* in this case we notify the AG that the microphone gain has changed */
|
* in this case we notify the AG that the microphone gain has changed */
|
||||||
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS) {
|
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS || t->profile == PA_BLUETOOTH_PROFILE_HFP_HF) {
|
||||||
len = sprintf(buf, "\r\n+VGS=%d\r\n", gain);
|
len = sprintf(buf, "\r\n+VGS=%d\r\n", gain);
|
||||||
pa_log_debug("RFCOMM >> +VGS=%d", gain);
|
pa_log_debug("RFCOMM >> +VGS=%d", gain);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -589,7 +589,7 @@ static void set_microphone_gain(pa_bluetooth_transport *t, uint16_t gain) {
|
||||||
/* If we are in the AG role, we send a command to the head set to change
|
/* If we are in the AG role, we send a command to the head set to change
|
||||||
* the microphone gain. In the HS role, source and sink are swapped, so
|
* the microphone gain. In the HS role, source and sink are swapped, so
|
||||||
* in this case we notify the AG that the speaker gain has changed */
|
* in this case we notify the AG that the speaker gain has changed */
|
||||||
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS) {
|
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS || t->profile == PA_BLUETOOTH_PROFILE_HFP_HF) {
|
||||||
len = sprintf(buf, "\r\n+VGM=%d\r\n", gain);
|
len = sprintf(buf, "\r\n+VGM=%d\r\n", gain);
|
||||||
pa_log_debug("RFCOMM >> +VGM=%d", gain);
|
pa_log_debug("RFCOMM >> +VGM=%d", gain);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -624,7 +624,7 @@ static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m,
|
||||||
if (pa_streq(handler, HSP_AG_PROFILE)) {
|
if (pa_streq(handler, HSP_AG_PROFILE)) {
|
||||||
p = PA_BLUETOOTH_PROFILE_HSP_HS;
|
p = PA_BLUETOOTH_PROFILE_HSP_HS;
|
||||||
} else if (pa_streq(handler, HSP_HS_PROFILE)) {
|
} else if (pa_streq(handler, HSP_HS_PROFILE)) {
|
||||||
p = PA_BLUETOOTH_PROFILE_HFP_AG;
|
p = PA_BLUETOOTH_PROFILE_HSP_AG;
|
||||||
} else if (pa_streq(handler, HFP_AG_PROFILE)) {
|
} else if (pa_streq(handler, HFP_AG_PROFILE)) {
|
||||||
p = PA_BLUETOOTH_PROFILE_HFP_HF;
|
p = PA_BLUETOOTH_PROFILE_HFP_HF;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -757,7 +757,7 @@ static void profile_init(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile
|
||||||
object_name = HSP_AG_PROFILE;
|
object_name = HSP_AG_PROFILE;
|
||||||
uuid = PA_BLUETOOTH_UUID_HSP_AG;
|
uuid = PA_BLUETOOTH_UUID_HSP_AG;
|
||||||
break;
|
break;
|
||||||
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
case PA_BLUETOOTH_PROFILE_HSP_AG:
|
||||||
object_name = HSP_HS_PROFILE;
|
object_name = HSP_HS_PROFILE;
|
||||||
uuid = PA_BLUETOOTH_UUID_HSP_HS;
|
uuid = PA_BLUETOOTH_UUID_HSP_HS;
|
||||||
break;
|
break;
|
||||||
|
|
@ -781,7 +781,7 @@ static void profile_done(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile
|
||||||
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||||
dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HSP_AG_PROFILE);
|
dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HSP_AG_PROFILE);
|
||||||
break;
|
break;
|
||||||
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
case PA_BLUETOOTH_PROFILE_HSP_AG:
|
||||||
dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HSP_HS_PROFILE);
|
dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HSP_HS_PROFILE);
|
||||||
break;
|
break;
|
||||||
case PA_BLUETOOTH_PROFILE_HFP_HF:
|
case PA_BLUETOOTH_PROFILE_HFP_HF:
|
||||||
|
|
@ -795,11 +795,11 @@ static void profile_done(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile
|
||||||
|
|
||||||
static void native_backend_apply_profile_registration_change(pa_bluetooth_backend *native_backend, bool enable_hs_role) {
|
static void native_backend_apply_profile_registration_change(pa_bluetooth_backend *native_backend, bool enable_hs_role) {
|
||||||
if (enable_hs_role) {
|
if (enable_hs_role) {
|
||||||
profile_init(native_backend, PA_BLUETOOTH_PROFILE_HFP_AG);
|
profile_init(native_backend, PA_BLUETOOTH_PROFILE_HSP_AG);
|
||||||
if (native_backend->enable_hfp_hf)
|
if (native_backend->enable_hfp_hf)
|
||||||
profile_init(native_backend, PA_BLUETOOTH_PROFILE_HFP_HF);
|
profile_init(native_backend, PA_BLUETOOTH_PROFILE_HFP_HF);
|
||||||
} else {
|
} else {
|
||||||
profile_done(native_backend, PA_BLUETOOTH_PROFILE_HFP_AG);
|
profile_done(native_backend, PA_BLUETOOTH_PROFILE_HSP_AG);
|
||||||
if (native_backend->enable_hfp_hf)
|
if (native_backend->enable_hfp_hf)
|
||||||
profile_done(native_backend, PA_BLUETOOTH_PROFILE_HFP_HF);
|
profile_done(native_backend, PA_BLUETOOTH_PROFILE_HFP_HF);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,7 @@ static void hf_audio_agent_card_found(pa_bluetooth_backend *backend, const char
|
||||||
card->local_address = pa_xstrdup(value);
|
card->local_address = pa_xstrdup(value);
|
||||||
} else if (pa_streq(key, "Type")) {
|
} else if (pa_streq(key, "Type")) {
|
||||||
if (pa_streq(value, "gateway"))
|
if (pa_streq(value, "gateway"))
|
||||||
p = PA_BLUETOOTH_PROFILE_HSP_HS;
|
p = PA_BLUETOOTH_PROFILE_HFP_HF;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_log_debug("%s: %s", key, value);
|
pa_log_debug("%s: %s", key, value);
|
||||||
|
|
|
||||||
|
|
@ -216,11 +216,12 @@ static bool device_supports_profile(pa_bluetooth_device *device, pa_bluetooth_pr
|
||||||
return show_hsp
|
return show_hsp
|
||||||
&& ( !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_HS)
|
&& ( !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_HS)
|
||||||
|| !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_HS_ALT));
|
|| !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_HS_ALT));
|
||||||
|
case PA_BLUETOOTH_PROFILE_HSP_AG:
|
||||||
|
return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_AG);
|
||||||
case PA_BLUETOOTH_PROFILE_HFP_HF:
|
case PA_BLUETOOTH_PROFILE_HFP_HF:
|
||||||
return show_hfp && !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_HF);
|
return show_hfp && !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_HF);
|
||||||
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||||
return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_AG)
|
return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_AG);
|
||||||
|| !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_AG);
|
|
||||||
case PA_BLUETOOTH_PROFILE_OFF:
|
case PA_BLUETOOTH_PROFILE_OFF:
|
||||||
pa_assert_not_reached();
|
pa_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
@ -1725,10 +1726,12 @@ const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile) {
|
||||||
return "a2dp_source";
|
return "a2dp_source";
|
||||||
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||||
return "headset_head_unit";
|
return "headset_head_unit";
|
||||||
case PA_BLUETOOTH_PROFILE_HFP_HF:
|
case PA_BLUETOOTH_PROFILE_HSP_AG:
|
||||||
return "headset_handsfree";
|
|
||||||
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
|
||||||
return "headset_audio_gateway";
|
return "headset_audio_gateway";
|
||||||
|
case PA_BLUETOOTH_PROFILE_HFP_HF:
|
||||||
|
return "handsfree_head_unit";
|
||||||
|
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||||
|
return "handsfree_audio_gateway";
|
||||||
case PA_BLUETOOTH_PROFILE_OFF:
|
case PA_BLUETOOTH_PROFILE_OFF:
|
||||||
return "off";
|
return "off";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ typedef enum profile {
|
||||||
PA_BLUETOOTH_PROFILE_A2DP_SINK,
|
PA_BLUETOOTH_PROFILE_A2DP_SINK,
|
||||||
PA_BLUETOOTH_PROFILE_A2DP_SOURCE,
|
PA_BLUETOOTH_PROFILE_A2DP_SOURCE,
|
||||||
PA_BLUETOOTH_PROFILE_HSP_HS,
|
PA_BLUETOOTH_PROFILE_HSP_HS,
|
||||||
|
PA_BLUETOOTH_PROFILE_HSP_AG,
|
||||||
PA_BLUETOOTH_PROFILE_HFP_HF,
|
PA_BLUETOOTH_PROFILE_HFP_HF,
|
||||||
PA_BLUETOOTH_PROFILE_HFP_AG,
|
PA_BLUETOOTH_PROFILE_HFP_AG,
|
||||||
PA_BLUETOOTH_PROFILE_OFF
|
PA_BLUETOOTH_PROFILE_OFF
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ PA_MODULE_LOAD_ONCE(true);
|
||||||
PA_MODULE_USAGE(
|
PA_MODULE_USAGE(
|
||||||
"auto_switch=<Switch between hsp and a2dp profile? (0 - never, 1 - media.role=phone, 2 - heuristic> "
|
"auto_switch=<Switch between hsp and a2dp profile? (0 - never, 1 - media.role=phone, 2 - heuristic> "
|
||||||
"a2dp_source=<Handle a2dp_source card profile (sink role)?> "
|
"a2dp_source=<Handle a2dp_source card profile (sink role)?> "
|
||||||
"ag=<Handle headset_audio_gateway card profile (headset role)?> ");
|
"ag=<Handle headset_audio_gateway or handsfree_audio_gateway card profile (headset role)?> ");
|
||||||
|
|
||||||
static const char* const valid_modargs[] = {
|
static const char* const valid_modargs[] = {
|
||||||
"auto_switch",
|
"auto_switch",
|
||||||
|
|
@ -86,7 +86,7 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
|
||||||
|
|
||||||
if (u->enable_a2dp_source && pa_streq(s, "a2dp_source"))
|
if (u->enable_a2dp_source && pa_streq(s, "a2dp_source"))
|
||||||
role = "music";
|
role = "music";
|
||||||
else if (u->enable_ag && pa_streq(s, "headset_audio_gateway"))
|
else if (u->enable_ag && (pa_streq(s, "headset_audio_gateway") || pa_streq(s, "handsfree_audio_gateway")))
|
||||||
role = "phone";
|
role = "phone";
|
||||||
else {
|
else {
|
||||||
pa_log_debug("Profile %s cannot be selected for loopback", s);
|
pa_log_debug("Profile %s cannot be selected for loopback", s);
|
||||||
|
|
@ -125,7 +125,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void *
|
||||||
if (!s)
|
if (!s)
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
|
|
||||||
if (u->enable_ag && pa_streq(s, "headset_audio_gateway"))
|
if (u->enable_ag && (pa_streq(s, "headset_audio_gateway") || pa_streq(s, "handsfree_audio_gateway")))
|
||||||
role = "phone";
|
role = "phone";
|
||||||
else {
|
else {
|
||||||
pa_log_debug("Profile %s cannot be selected for loopback", s);
|
pa_log_debug("Profile %s cannot be selected for loopback", s);
|
||||||
|
|
@ -156,7 +156,7 @@ static void card_set_profile(struct userdata *u, pa_card *card, bool revert_to_a
|
||||||
if (!pa_streq(profile->name, "a2dp_sink"))
|
if (!pa_streq(profile->name, "a2dp_sink"))
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if (!pa_streq(profile->name, "headset_head_unit") && !pa_streq(profile->name, "headset_handsfree"))
|
if (!pa_streq(profile->name, "headset_head_unit") && !pa_streq(profile->name, "handsfree_head_unit"))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,8 +190,8 @@ static void switch_profile(pa_card *card, bool revert_to_a2dp, void *userdata) {
|
||||||
if (!pa_hashmap_remove(u->will_need_revert_card_map, card))
|
if (!pa_hashmap_remove(u->will_need_revert_card_map, card))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Skip card if does not have active hsp profile */
|
/* Skip card if does not have active headset profile */
|
||||||
if (!pa_streq(card->active_profile->name, "headset_head_unit") && !pa_streq(card->active_profile->name, "headset_handsfree"))
|
if (!pa_streq(card->active_profile->name, "headset_head_unit") && !pa_streq(card->active_profile->name, "handsfree_head_unit"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Skip card if already has active a2dp profile */
|
/* Skip card if already has active a2dp profile */
|
||||||
|
|
@ -202,8 +202,8 @@ static void switch_profile(pa_card *card, bool revert_to_a2dp, void *userdata) {
|
||||||
if (!pa_streq(card->active_profile->name, "a2dp_sink"))
|
if (!pa_streq(card->active_profile->name, "a2dp_sink"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Skip card if already has active hsp profile */
|
/* Skip card if already has active headset profile */
|
||||||
if (pa_streq(card->active_profile->name, "headset_head_unit") || pa_streq(card->active_profile->name, "headset_handsfree"))
|
if (pa_streq(card->active_profile->name, "headset_head_unit") || pa_streq(card->active_profile->name, "handsfree_head_unit"))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -360,7 +360,7 @@ static pa_hook_result_t profile_available_hook_callback(pa_core *c, pa_card_prof
|
||||||
/* Do not automatically switch profiles for headsets, just in case */
|
/* Do not automatically switch profiles for headsets, just in case */
|
||||||
if (pa_streq(profile->name, "a2dp_sink") ||
|
if (pa_streq(profile->name, "a2dp_sink") ||
|
||||||
pa_streq(profile->name, "headset_head_unit") ||
|
pa_streq(profile->name, "headset_head_unit") ||
|
||||||
pa_streq(profile->name, "headset_handsfree"))
|
pa_streq(profile->name, "handsfree_head_unit"))
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
|
|
||||||
is_active_profile = card->active_profile == profile;
|
is_active_profile = card->active_profile == profile;
|
||||||
|
|
|
||||||
|
|
@ -262,8 +262,9 @@ static int sco_process_render(struct userdata *u) {
|
||||||
|
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HSP_HS ||
|
pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HSP_HS ||
|
||||||
u->profile == PA_BLUETOOTH_PROFILE_HFP_HF ||
|
u->profile == PA_BLUETOOTH_PROFILE_HSP_AG ||
|
||||||
u->profile == PA_BLUETOOTH_PROFILE_HFP_AG);
|
u->profile == PA_BLUETOOTH_PROFILE_HFP_HF ||
|
||||||
|
u->profile == PA_BLUETOOTH_PROFILE_HFP_AG);
|
||||||
pa_assert(u->sink);
|
pa_assert(u->sink);
|
||||||
|
|
||||||
pa_sink_render_full(u->sink, u->write_block_size, &memchunk);
|
pa_sink_render_full(u->sink, u->write_block_size, &memchunk);
|
||||||
|
|
@ -329,8 +330,9 @@ static int sco_process_push(struct userdata *u) {
|
||||||
|
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HSP_HS ||
|
pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HSP_HS ||
|
||||||
u->profile == PA_BLUETOOTH_PROFILE_HFP_HF||
|
u->profile == PA_BLUETOOTH_PROFILE_HSP_AG ||
|
||||||
u->profile == PA_BLUETOOTH_PROFILE_HFP_AG);
|
u->profile == PA_BLUETOOTH_PROFILE_HFP_HF ||
|
||||||
|
u->profile == PA_BLUETOOTH_PROFILE_HFP_AG);
|
||||||
pa_assert(u->source);
|
pa_assert(u->source);
|
||||||
pa_assert(u->read_smoother);
|
pa_assert(u->read_smoother);
|
||||||
|
|
||||||
|
|
@ -770,6 +772,7 @@ static void handle_sink_block_size_change(struct userdata *u) {
|
||||||
/* Run from I/O thread */
|
/* Run from I/O thread */
|
||||||
static void transport_config_mtu(struct userdata *u) {
|
static void transport_config_mtu(struct userdata *u) {
|
||||||
if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
||||||
|
|| u->profile == PA_BLUETOOTH_PROFILE_HSP_AG
|
||||||
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_HF
|
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_HF
|
||||||
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
||||||
u->read_block_size = u->read_link_mtu;
|
u->read_block_size = u->read_link_mtu;
|
||||||
|
|
@ -988,7 +991,7 @@ static void source_set_volume_cb(pa_source *s) {
|
||||||
pa_cvolume_set(&s->real_volume, u->decoder_sample_spec.channels, volume);
|
pa_cvolume_set(&s->real_volume, u->decoder_sample_spec.channels, volume);
|
||||||
|
|
||||||
/* Set soft volume when in headset role */
|
/* Set soft volume when in headset role */
|
||||||
if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG)
|
if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG || u->profile == PA_BLUETOOTH_PROFILE_HSP_AG)
|
||||||
pa_cvolume_set(&s->soft_volume, u->decoder_sample_spec.channels, volume);
|
pa_cvolume_set(&s->soft_volume, u->decoder_sample_spec.channels, volume);
|
||||||
|
|
||||||
/* If we are in the AG role, we send a command to the head set to change
|
/* If we are in the AG role, we send a command to the head set to change
|
||||||
|
|
@ -1023,6 +1026,7 @@ static int add_source(struct userdata *u) {
|
||||||
switch (u->profile) {
|
switch (u->profile) {
|
||||||
case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
|
case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
|
||||||
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||||
|
case PA_BLUETOOTH_PROFILE_HSP_AG:
|
||||||
data.suspend_cause = PA_SUSPEND_USER;
|
data.suspend_cause = PA_SUSPEND_USER;
|
||||||
break;
|
break;
|
||||||
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||||
|
|
@ -1052,6 +1056,7 @@ static int add_source(struct userdata *u) {
|
||||||
u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb;
|
u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb;
|
||||||
|
|
||||||
if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
||||||
|
|| u->profile == PA_BLUETOOTH_PROFILE_HSP_AG
|
||||||
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_AG
|
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_AG
|
||||||
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_HF) {
|
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_HF) {
|
||||||
pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
|
pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
|
||||||
|
|
@ -1178,7 +1183,7 @@ static void sink_set_volume_cb(pa_sink *s) {
|
||||||
pa_cvolume_set(&s->real_volume, u->encoder_sample_spec.channels, volume);
|
pa_cvolume_set(&s->real_volume, u->encoder_sample_spec.channels, volume);
|
||||||
|
|
||||||
/* Set soft volume when in headset role */
|
/* Set soft volume when in headset role */
|
||||||
if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG)
|
if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG || u->profile == PA_BLUETOOTH_PROFILE_HSP_AG)
|
||||||
pa_cvolume_set(&s->soft_volume, u->encoder_sample_spec.channels, volume);
|
pa_cvolume_set(&s->soft_volume, u->encoder_sample_spec.channels, volume);
|
||||||
|
|
||||||
/* If we are in the AG role, we send a command to the head set to change
|
/* If we are in the AG role, we send a command to the head set to change
|
||||||
|
|
@ -1212,6 +1217,7 @@ static int add_sink(struct userdata *u) {
|
||||||
if (!u->transport_acquired)
|
if (!u->transport_acquired)
|
||||||
switch (u->profile) {
|
switch (u->profile) {
|
||||||
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||||
|
case PA_BLUETOOTH_PROFILE_HSP_AG:
|
||||||
data.suspend_cause = PA_SUSPEND_USER;
|
data.suspend_cause = PA_SUSPEND_USER;
|
||||||
break;
|
break;
|
||||||
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||||
|
|
@ -1243,6 +1249,7 @@ static int add_sink(struct userdata *u) {
|
||||||
u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb;
|
u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb;
|
||||||
|
|
||||||
if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
||||||
|
|| u->profile == PA_BLUETOOTH_PROFILE_HSP_AG
|
||||||
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_AG
|
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_AG
|
||||||
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_HF) {
|
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_HF) {
|
||||||
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
|
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
|
||||||
|
|
@ -1254,6 +1261,7 @@ static int add_sink(struct userdata *u) {
|
||||||
/* Run from main thread */
|
/* Run from main thread */
|
||||||
static int transport_config(struct userdata *u) {
|
static int transport_config(struct userdata *u) {
|
||||||
if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
||||||
|
|| u->profile == PA_BLUETOOTH_PROFILE_HSP_AG
|
||||||
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_HF
|
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_HF
|
||||||
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
|| u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
||||||
u->encoder_sample_spec.format = PA_SAMPLE_S16LE;
|
u->encoder_sample_spec.format = PA_SAMPLE_S16LE;
|
||||||
|
|
@ -1306,7 +1314,7 @@ static int setup_transport(struct userdata *u) {
|
||||||
|
|
||||||
u->transport = t;
|
u->transport = t;
|
||||||
|
|
||||||
if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG)
|
if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG || u->profile == PA_BLUETOOTH_PROFILE_HSP_AG)
|
||||||
transport_acquire(u, true); /* In case of error, the sink/sources will be created suspended */
|
transport_acquire(u, true); /* In case of error, the sink/sources will be created suspended */
|
||||||
else {
|
else {
|
||||||
int transport_error;
|
int transport_error;
|
||||||
|
|
@ -1325,6 +1333,7 @@ static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
|
||||||
[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
|
[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
|
||||||
[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
|
[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
|
||||||
[PA_BLUETOOTH_PROFILE_HSP_HS] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
|
[PA_BLUETOOTH_PROFILE_HSP_HS] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
|
||||||
|
[PA_BLUETOOTH_PROFILE_HSP_AG] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
|
||||||
[PA_BLUETOOTH_PROFILE_HFP_HF] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
|
[PA_BLUETOOTH_PROFILE_HFP_HF] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
|
||||||
[PA_BLUETOOTH_PROFILE_HFP_AG] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
|
[PA_BLUETOOTH_PROFILE_HFP_AG] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
|
||||||
[PA_BLUETOOTH_PROFILE_OFF] = 0
|
[PA_BLUETOOTH_PROFILE_OFF] = 0
|
||||||
|
|
@ -1660,7 +1669,7 @@ static int start_thread(struct userdata *u) {
|
||||||
|
|
||||||
/* If we are in the headset role, the sink should not become default
|
/* If we are in the headset role, the sink should not become default
|
||||||
* unless there is no other sound device available. */
|
* unless there is no other sound device available. */
|
||||||
if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG)
|
if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG || u->profile == PA_BLUETOOTH_PROFILE_HSP_AG)
|
||||||
u->sink->priority = 1500;
|
u->sink->priority = 1500;
|
||||||
|
|
||||||
pa_sink_put(u->sink);
|
pa_sink_put(u->sink);
|
||||||
|
|
@ -1676,7 +1685,7 @@ static int start_thread(struct userdata *u) {
|
||||||
/* If we are in the headset role or the device is an a2dp source,
|
/* If we are in the headset role or the device is an a2dp source,
|
||||||
* the source should not become default unless there is no other
|
* the source should not become default unless there is no other
|
||||||
* sound device available. */
|
* sound device available. */
|
||||||
if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG || u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE)
|
if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG || u->profile == PA_BLUETOOTH_PROFILE_HSP_AG || u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE)
|
||||||
u->source->priority = 1500;
|
u->source->priority = 1500;
|
||||||
|
|
||||||
pa_source_put(u->source);
|
pa_source_put(u->source);
|
||||||
|
|
@ -1945,7 +1954,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||||
cp = pa_card_profile_new(name, _("Headset Head Unit (HSP/HFP)"), sizeof(pa_bluetooth_profile_t));
|
cp = pa_card_profile_new(name, _("Headset Head Unit (HSP)"), sizeof(pa_bluetooth_profile_t));
|
||||||
cp->priority = 30;
|
cp->priority = 30;
|
||||||
cp->n_sinks = 1;
|
cp->n_sinks = 1;
|
||||||
cp->n_sources = 1;
|
cp->n_sources = 1;
|
||||||
|
|
@ -1957,8 +1966,21 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro
|
||||||
p = PA_CARD_PROFILE_DATA(cp);
|
p = PA_CARD_PROFILE_DATA(cp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PA_BLUETOOTH_PROFILE_HSP_AG:
|
||||||
|
cp = pa_card_profile_new(name, _("Headset Audio Gateway (HSP)"), sizeof(pa_bluetooth_profile_t));
|
||||||
|
cp->priority = 10;
|
||||||
|
cp->n_sinks = 1;
|
||||||
|
cp->n_sources = 1;
|
||||||
|
cp->max_sink_channels = 1;
|
||||||
|
cp->max_source_channels = 1;
|
||||||
|
pa_hashmap_put(input_port->profiles, cp->name, cp);
|
||||||
|
pa_hashmap_put(output_port->profiles, cp->name, cp);
|
||||||
|
|
||||||
|
p = PA_CARD_PROFILE_DATA(cp);
|
||||||
|
break;
|
||||||
|
|
||||||
case PA_BLUETOOTH_PROFILE_HFP_HF:
|
case PA_BLUETOOTH_PROFILE_HFP_HF:
|
||||||
cp = pa_card_profile_new(name, _("Headset Handsfree (HFP)"), sizeof(pa_bluetooth_profile_t));
|
cp = pa_card_profile_new(name, _("Handsfree Head Unit (HFP)"), sizeof(pa_bluetooth_profile_t));
|
||||||
cp->priority = 30;
|
cp->priority = 30;
|
||||||
cp->n_sinks = 1;
|
cp->n_sinks = 1;
|
||||||
cp->n_sources = 1;
|
cp->n_sources = 1;
|
||||||
|
|
@ -1971,7 +1993,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||||
cp = pa_card_profile_new(name, _("Headset Audio Gateway (HSP/HFP)"), sizeof(pa_bluetooth_profile_t));
|
cp = pa_card_profile_new(name, _("Handsfree Audio Gateway (HFP)"), sizeof(pa_bluetooth_profile_t));
|
||||||
cp->priority = 10;
|
cp->priority = 10;
|
||||||
cp->n_sinks = 1;
|
cp->n_sinks = 1;
|
||||||
cp->n_sources = 1;
|
cp->n_sources = 1;
|
||||||
|
|
@ -2048,7 +2070,9 @@ static int uuid_to_profile(const char *uuid, pa_bluetooth_profile_t *_r) {
|
||||||
*_r = PA_BLUETOOTH_PROFILE_HSP_HS;
|
*_r = PA_BLUETOOTH_PROFILE_HSP_HS;
|
||||||
else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF))
|
else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF))
|
||||||
*_r = PA_BLUETOOTH_PROFILE_HFP_HF;
|
*_r = PA_BLUETOOTH_PROFILE_HFP_HF;
|
||||||
else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_AG) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_AG))
|
else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_AG))
|
||||||
|
*_r = PA_BLUETOOTH_PROFILE_HSP_AG;
|
||||||
|
else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_AG))
|
||||||
*_r = PA_BLUETOOTH_PROFILE_HFP_AG;
|
*_r = PA_BLUETOOTH_PROFILE_HFP_AG;
|
||||||
else
|
else
|
||||||
return -PA_ERR_INVALID;
|
return -PA_ERR_INVALID;
|
||||||
|
|
@ -2269,7 +2293,7 @@ static pa_hook_result_t transport_speaker_gain_changed_cb(pa_bluetooth_discovery
|
||||||
volume++;
|
volume++;
|
||||||
|
|
||||||
pa_cvolume_set(&v, u->encoder_sample_spec.channels, volume);
|
pa_cvolume_set(&v, u->encoder_sample_spec.channels, volume);
|
||||||
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS)
|
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS || t->profile == PA_BLUETOOTH_PROFILE_HFP_HF)
|
||||||
pa_sink_volume_changed(u->sink, &v);
|
pa_sink_volume_changed(u->sink, &v);
|
||||||
else
|
else
|
||||||
pa_sink_set_volume(u->sink, &v, true, true);
|
pa_sink_set_volume(u->sink, &v, true, true);
|
||||||
|
|
@ -2297,7 +2321,7 @@ static pa_hook_result_t transport_microphone_gain_changed_cb(pa_bluetooth_discov
|
||||||
|
|
||||||
pa_cvolume_set(&v, u->decoder_sample_spec.channels, volume);
|
pa_cvolume_set(&v, u->decoder_sample_spec.channels, volume);
|
||||||
|
|
||||||
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS)
|
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS || t->profile == PA_BLUETOOTH_PROFILE_HFP_HF)
|
||||||
pa_source_volume_changed(u->source, &v);
|
pa_source_volume_changed(u->source, &v);
|
||||||
else
|
else
|
||||||
pa_source_set_volume(u->source, &v, true, true);
|
pa_source_set_volume(u->source, &v, true, true);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue