/* 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
* 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);
pa_log_debug("RFCOMM >> +VGS=%d", gain);
} else {
/* 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
* 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);
pa_log_debug("RFCOMM >> +VGM=%d", gain);
} else {
if (pa_streq(handler, HSP_AG_PROFILE)) {
p = PA_BLUETOOTH_PROFILE_HSP_HS;
} 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)) {
p = PA_BLUETOOTH_PROFILE_HFP_HF;
} else {
object_name = HSP_AG_PROFILE;
uuid = PA_BLUETOOTH_UUID_HSP_AG;
break;
- case PA_BLUETOOTH_PROFILE_HFP_AG:
+ case PA_BLUETOOTH_PROFILE_HSP_AG:
object_name = HSP_HS_PROFILE;
uuid = PA_BLUETOOTH_UUID_HSP_HS;
break;
case PA_BLUETOOTH_PROFILE_HSP_HS:
dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HSP_AG_PROFILE);
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);
break;
case PA_BLUETOOTH_PROFILE_HFP_HF:
static void native_backend_apply_profile_registration_change(pa_bluetooth_backend *native_backend, bool 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)
profile_init(native_backend, PA_BLUETOOTH_PROFILE_HFP_HF);
} 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)
profile_done(native_backend, PA_BLUETOOTH_PROFILE_HFP_HF);
}
PA_MODULE_USAGE(
"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)?> "
- "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[] = {
"auto_switch",
if (u->enable_a2dp_source && pa_streq(s, "a2dp_source"))
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";
else {
pa_log_debug("Profile %s cannot be selected for loopback", s);
if (!s)
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";
else {
pa_log_debug("Profile %s cannot be selected for loopback", s);
if (!pa_streq(profile->name, "a2dp_sink"))
continue;
} 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;
}
if (!pa_hashmap_remove(u->will_need_revert_card_map, card))
return;
- /* Skip card if does not have active hsp profile */
- if (!pa_streq(card->active_profile->name, "headset_head_unit") && !pa_streq(card->active_profile->name, "headset_handsfree"))
+ /* 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, "handsfree_head_unit"))
return;
/* Skip card if already has active a2dp profile */
if (!pa_streq(card->active_profile->name, "a2dp_sink"))
return;
- /* Skip card if already has active hsp profile */
- if (pa_streq(card->active_profile->name, "headset_head_unit") || pa_streq(card->active_profile->name, "headset_handsfree"))
+ /* Skip card if already has active headset profile */
+ if (pa_streq(card->active_profile->name, "headset_head_unit") || pa_streq(card->active_profile->name, "handsfree_head_unit"))
return;
}
/* Do not automatically switch profiles for headsets, just in case */
if (pa_streq(profile->name, "a2dp_sink") ||
pa_streq(profile->name, "headset_head_unit") ||
- pa_streq(profile->name, "headset_handsfree"))
+ pa_streq(profile->name, "handsfree_head_unit"))
return PA_HOOK_OK;
is_active_profile = card->active_profile == profile;
pa_assert(u);
pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HSP_HS ||
- u->profile == PA_BLUETOOTH_PROFILE_HFP_HF ||
- u->profile == PA_BLUETOOTH_PROFILE_HFP_AG);
+ u->profile == PA_BLUETOOTH_PROFILE_HSP_AG ||
+ u->profile == PA_BLUETOOTH_PROFILE_HFP_HF ||
+ u->profile == PA_BLUETOOTH_PROFILE_HFP_AG);
pa_assert(u->sink);
pa_sink_render_full(u->sink, u->write_block_size, &memchunk);
pa_assert(u);
pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HSP_HS ||
- u->profile == PA_BLUETOOTH_PROFILE_HFP_HF||
- u->profile == PA_BLUETOOTH_PROFILE_HFP_AG);
+ u->profile == PA_BLUETOOTH_PROFILE_HSP_AG ||
+ u->profile == PA_BLUETOOTH_PROFILE_HFP_HF ||
+ u->profile == PA_BLUETOOTH_PROFILE_HFP_AG);
pa_assert(u->source);
pa_assert(u->read_smoother);
/* Run from I/O thread */
static void transport_config_mtu(struct userdata *u) {
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_AG) {
u->read_block_size = u->read_link_mtu;
pa_cvolume_set(&s->real_volume, u->decoder_sample_spec.channels, volume);
/* 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);
/* If we are in the AG role, we send a command to the head set to change
switch (u->profile) {
case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
case PA_BLUETOOTH_PROFILE_HFP_AG:
+ case PA_BLUETOOTH_PROFILE_HSP_AG:
data.suspend_cause = PA_SUSPEND_USER;
break;
case PA_BLUETOOTH_PROFILE_HSP_HS:
u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb;
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_HF) {
pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
pa_cvolume_set(&s->real_volume, u->encoder_sample_spec.channels, volume);
/* 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);
/* If we are in the AG role, we send a command to the head set to change
if (!u->transport_acquired)
switch (u->profile) {
case PA_BLUETOOTH_PROFILE_HFP_AG:
+ case PA_BLUETOOTH_PROFILE_HSP_AG:
data.suspend_cause = PA_SUSPEND_USER;
break;
case PA_BLUETOOTH_PROFILE_HSP_HS:
u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb;
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_HF) {
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
/* Run from main thread */
static int transport_config(struct userdata *u) {
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_AG) {
u->encoder_sample_spec.format = PA_SAMPLE_S16LE;
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 */
else {
int transport_error;
[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
[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_AG] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
[PA_BLUETOOTH_PROFILE_OFF] = 0
/* If we are in the headset role, the sink should not become default
* 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;
pa_sink_put(u->sink);
/* 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
* 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;
pa_source_put(u->source);
break;
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->n_sinks = 1;
cp->n_sources = 1;
p = PA_CARD_PROFILE_DATA(cp);
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:
- 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->n_sinks = 1;
cp->n_sources = 1;
break;
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->n_sinks = 1;
cp->n_sources = 1;
*_r = PA_BLUETOOTH_PROFILE_HSP_HS;
else if (pa_streq(uuid, PA_BLUETOOTH_UUID_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;
else
return -PA_ERR_INVALID;
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);
else
pa_sink_set_volume(u->sink, &v, true, true);
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);
else
pa_source_set_volume(u->source, &v, true, true);