experimental fixes bluetooth profile switching (f28+ only, fdo#93898)
This commit is contained in:
parent
9eb2445385
commit
51d25e23db
@ -25,7 +25,7 @@
|
||||
Name: pulseaudio
|
||||
Summary: Improved Linux Sound Server
|
||||
Version: %{pa_major}%{?pa_minor:.%{pa_minor}}
|
||||
Release: 3%{?snap:.%{snap}git%{shortcommit}}%{?dist}
|
||||
Release: 4%{?snap:.%{snap}git%{shortcommit}}%{?dist}
|
||||
License: LGPLv2+
|
||||
URL: http://www.freedesktop.org/wiki/Software/PulseAudio
|
||||
%if 0%{?gitrel}
|
||||
@ -65,6 +65,11 @@ Patch35: 0035-alsa-mixer-Prioritize-hdmi-mappings-over-iec958-mapp.patch
|
||||
## upstreamable patches
|
||||
# patchset from https://bugs.freedesktop.org/show_bug.cgi?id=100488
|
||||
Patch100: Fix-Intel-HDMI-LPE-problems.patch
|
||||
# patchset from https://bugs.freedesktop.org/show_bug.cgi?id=93898
|
||||
Patch101: v5-1-4-bluetooth-use-consistent-profile-names.patch
|
||||
Patch102: v5-2-4-bluetooth-separate-HSP-and-HFP.patch
|
||||
Patch103: v5-3-4-bluetooth-add-correct-HFP-rfcomm-negotiation.patch
|
||||
Patch104: v5-4-4-bluetooth-make-native-the-default-backend.patch
|
||||
|
||||
BuildRequires: automake libtool
|
||||
BuildRequires: pkgconfig(bash-completion)
|
||||
@ -254,6 +259,13 @@ This package contains GDM integration hooks for the PulseAudio sound server.
|
||||
|
||||
## upstreamable patches
|
||||
%patch100 -p1
|
||||
# rawhide-only, for now, on hadess' advice --rex
|
||||
%if 0%{?fedora} > 27
|
||||
%patch101 -p1
|
||||
%patch102 -p1
|
||||
%patch103 -p1
|
||||
%patch104 -p1
|
||||
%endif
|
||||
|
||||
%patch1 -p1 -b .autostart
|
||||
%patch2 -p1 -b .disable_flat_volumes
|
||||
@ -597,6 +609,9 @@ exit 0
|
||||
|
||||
|
||||
%changelog
|
||||
* Thu Oct 12 2017 Rex Dieter <rdieter@fedoraproject.org> - 11.1-4
|
||||
- experimental fixes bluetooth profile switching (f28+ only, fdo#93898)
|
||||
|
||||
* Thu Oct 12 2017 Rex Dieter <rdieter@fedoraproject.org> - 11.1-3
|
||||
- include experiemental Intel HDMI LPE fixes (fdo#100488)
|
||||
|
||||
|
||||
379
v5-1-4-bluetooth-use-consistent-profile-names.patch
Normal file
379
v5-1-4-bluetooth-use-consistent-profile-names.patch
Normal file
@ -0,0 +1,379 @@
|
||||
diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c
|
||||
index 0f0104d8..f2009bfd 100644
|
||||
--- a/src/modules/bluetooth/backend-native.c
|
||||
+++ b/src/modules/bluetooth/backend-native.c
|
||||
@@ -449,7 +449,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
|
||||
* 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_HEADSET_HEAD_UNIT) {
|
||||
+ if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS) {
|
||||
len = sprintf(buf, "\r\n+VGS=%d\r\n", gain);
|
||||
pa_log_debug("RFCOMM >> +VGS=%d", gain);
|
||||
} else {
|
||||
@@ -476,7 +476,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
|
||||
* 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_HEADSET_HEAD_UNIT) {
|
||||
+ if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS) {
|
||||
len = sprintf(buf, "\r\n+VGM=%d\r\n", gain);
|
||||
pa_log_debug("RFCOMM >> +VGM=%d", gain);
|
||||
} else {
|
||||
@@ -509,9 +509,9 @@ static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m,
|
||||
|
||||
handler = dbus_message_get_path(m);
|
||||
if (pa_streq(handler, HSP_AG_PROFILE)) {
|
||||
- p = PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT;
|
||||
+ p = PA_BLUETOOTH_PROFILE_HSP_HS;
|
||||
} else if (pa_streq(handler, HSP_HS_PROFILE)) {
|
||||
- p = PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY;
|
||||
+ p = PA_BLUETOOTH_PROFILE_HFP_AG;
|
||||
} else {
|
||||
pa_log_error("Invalid handler");
|
||||
goto fail;
|
||||
@@ -626,11 +626,11 @@ static void profile_init(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile
|
||||
pa_assert(b);
|
||||
|
||||
switch (profile) {
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
|
||||
+ case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||
object_name = HSP_AG_PROFILE;
|
||||
uuid = PA_BLUETOOTH_UUID_HSP_AG;
|
||||
break;
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||
object_name = HSP_HS_PROFILE;
|
||||
uuid = PA_BLUETOOTH_UUID_HSP_HS;
|
||||
break;
|
||||
@@ -647,10 +647,10 @@ static void profile_done(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile
|
||||
pa_assert(b);
|
||||
|
||||
switch (profile) {
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
|
||||
+ 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_HEADSET_AUDIO_GATEWAY:
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||
dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HSP_HS_PROFILE);
|
||||
break;
|
||||
default:
|
||||
@@ -665,9 +665,9 @@ void pa_bluetooth_native_backend_enable_hs_role(pa_bluetooth_backend *native_bac
|
||||
return;
|
||||
|
||||
if (enable_hs_role)
|
||||
- profile_init(native_backend, PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY);
|
||||
+ profile_init(native_backend, PA_BLUETOOTH_PROFILE_HFP_AG);
|
||||
else
|
||||
- profile_done(native_backend, PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY);
|
||||
+ profile_done(native_backend, PA_BLUETOOTH_PROFILE_HFP_AG);
|
||||
|
||||
native_backend->enable_hs_role = enable_hs_role;
|
||||
}
|
||||
@@ -693,8 +693,8 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d
|
||||
backend->enable_hs_role = enable_hs_role;
|
||||
|
||||
if (enable_hs_role)
|
||||
- profile_init(backend, PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY);
|
||||
- profile_init(backend, PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT);
|
||||
+ profile_init(backend, PA_BLUETOOTH_PROFILE_HFP_AG);
|
||||
+ profile_init(backend, PA_BLUETOOTH_PROFILE_HSP_HS);
|
||||
|
||||
return backend;
|
||||
}
|
||||
@@ -705,8 +705,8 @@ void pa_bluetooth_native_backend_free(pa_bluetooth_backend *backend) {
|
||||
pa_dbus_free_pending_list(&backend->pending);
|
||||
|
||||
if (backend->enable_hs_role)
|
||||
- profile_done(backend, PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY);
|
||||
- profile_done(backend, PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT);
|
||||
+ profile_done(backend, PA_BLUETOOTH_PROFILE_HFP_AG);
|
||||
+ profile_done(backend, PA_BLUETOOTH_PROFILE_HSP_HS);
|
||||
|
||||
pa_dbus_connection_unref(backend->connection);
|
||||
|
||||
diff --git a/src/modules/bluetooth/backend-ofono.c b/src/modules/bluetooth/backend-ofono.c
|
||||
index 2c51497f..85b9c477 100644
|
||||
--- a/src/modules/bluetooth/backend-ofono.c
|
||||
+++ b/src/modules/bluetooth/backend-ofono.c
|
||||
@@ -223,7 +223,7 @@ static void hf_audio_agent_card_found(pa_bluetooth_backend *backend, const char
|
||||
const char *key, *value;
|
||||
struct hf_audio_card *card;
|
||||
pa_bluetooth_device *d;
|
||||
- pa_bluetooth_profile_t p = PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY;
|
||||
+ pa_bluetooth_profile_t p = PA_BLUETOOTH_PROFILE_HFP_AG;
|
||||
|
||||
pa_assert(backend);
|
||||
pa_assert(path);
|
||||
@@ -257,7 +257,7 @@ static void hf_audio_agent_card_found(pa_bluetooth_backend *backend, const char
|
||||
card->local_address = pa_xstrdup(value);
|
||||
} else if (pa_streq(key, "Type")) {
|
||||
if (pa_streq(value, "gateway"))
|
||||
- p = PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT;
|
||||
+ p = PA_BLUETOOTH_PROFILE_HSP_HS;
|
||||
}
|
||||
|
||||
pa_log_debug("%s: %s", key, value);
|
||||
diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c
|
||||
index c9283232..4470f2ef 100644
|
||||
--- a/src/modules/bluetooth/bluez5-util.c
|
||||
+++ b/src/modules/bluetooth/bluez5-util.c
|
||||
@@ -174,10 +174,10 @@ static bool device_supports_profile(pa_bluetooth_device *device, pa_bluetooth_pr
|
||||
return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_A2DP_SINK);
|
||||
case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
|
||||
return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_A2DP_SOURCE);
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
|
||||
+ case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||
return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_HS)
|
||||
|| !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_HF);
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||
return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_AG)
|
||||
|| !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_AG);
|
||||
case PA_BLUETOOTH_PROFILE_OFF:
|
||||
@@ -1018,7 +1018,7 @@ void pa_bluetooth_discovery_set_ofono_running(pa_bluetooth_discovery *y, bool is
|
||||
pa_bluetooth_device *d;
|
||||
|
||||
PA_HASHMAP_FOREACH(d, y->devices, state) {
|
||||
- if (device_supports_profile(d, PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)) {
|
||||
+ if (device_supports_profile(d, PA_BLUETOOTH_PROFILE_HFP_AG)) {
|
||||
DBusMessage *m;
|
||||
|
||||
pa_assert_se(m = dbus_message_new_method_call(BLUEZ_SERVICE, d->path, "org.bluez.Device1", "Disconnect"));
|
||||
@@ -1304,9 +1304,9 @@ const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile) {
|
||||
return "a2dp_sink";
|
||||
case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
|
||||
return "a2dp_source";
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
|
||||
+ case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||
return "headset_head_unit";
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||
return "headset_audio_gateway";
|
||||
case PA_BLUETOOTH_PROFILE_OFF:
|
||||
return "off";
|
||||
diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h
|
||||
index a3e7bf3d..84c0c3f1 100644
|
||||
--- a/src/modules/bluetooth/bluez5-util.h
|
||||
+++ b/src/modules/bluetooth/bluez5-util.h
|
||||
@@ -46,8 +46,8 @@ typedef enum pa_bluetooth_hook {
|
||||
typedef enum profile {
|
||||
PA_BLUETOOTH_PROFILE_A2DP_SINK,
|
||||
PA_BLUETOOTH_PROFILE_A2DP_SOURCE,
|
||||
- PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT,
|
||||
- PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY,
|
||||
+ PA_BLUETOOTH_PROFILE_HSP_HS,
|
||||
+ PA_BLUETOOTH_PROFILE_HFP_AG,
|
||||
PA_BLUETOOTH_PROFILE_OFF
|
||||
} pa_bluetooth_profile_t;
|
||||
#define PA_BLUETOOTH_PROFILE_COUNT PA_BLUETOOTH_PROFILE_OFF
|
||||
diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
|
||||
index 530207a2..d076fbad 100644
|
||||
--- a/src/modules/bluetooth/module-bluez5-device.c
|
||||
+++ b/src/modules/bluetooth/module-bluez5-device.c
|
||||
@@ -257,8 +257,8 @@ static int sco_process_render(struct userdata *u) {
|
||||
pa_memchunk memchunk;
|
||||
|
||||
pa_assert(u);
|
||||
- pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
|
||||
- u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY);
|
||||
+ pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HSP_HS ||
|
||||
+ u->profile == PA_BLUETOOTH_PROFILE_HFP_AG);
|
||||
pa_assert(u->sink);
|
||||
|
||||
pa_sink_render_full(u->sink, u->write_block_size, &memchunk);
|
||||
@@ -317,8 +317,8 @@ static int sco_process_push(struct userdata *u) {
|
||||
pa_usec_t tstamp = 0;
|
||||
|
||||
pa_assert(u);
|
||||
- pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
|
||||
- u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY);
|
||||
+ pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HSP_HS ||
|
||||
+ u->profile == PA_BLUETOOTH_PROFILE_HFP_AG);
|
||||
pa_assert(u->source);
|
||||
pa_assert(u->read_smoother);
|
||||
|
||||
@@ -784,7 +784,7 @@ static void transport_release(struct userdata *u) {
|
||||
|
||||
/* Run from I/O thread */
|
||||
static void transport_config_mtu(struct userdata *u) {
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
||||
u->read_block_size = u->read_link_mtu;
|
||||
u->write_block_size = u->write_link_mtu;
|
||||
|
||||
@@ -981,7 +981,7 @@ static void source_set_volume_cb(pa_source *s) {
|
||||
pa_cvolume_set(&s->real_volume, u->sample_spec.channels, volume);
|
||||
|
||||
/* Set soft volume when in headset role */
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG)
|
||||
pa_cvolume_set(&s->soft_volume, u->sample_spec.channels, volume);
|
||||
|
||||
/* If we are in the AG role, we send a command to the head set to change
|
||||
@@ -1004,7 +1004,7 @@ static int add_source(struct userdata *u) {
|
||||
data.namereg_fail = false;
|
||||
pa_proplist_sets(data.proplist, "bluetooth.protocol", pa_bluetooth_profile_to_string(u->profile));
|
||||
pa_source_new_data_set_sample_spec(&data, &u->sample_spec);
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT)
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS)
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
|
||||
|
||||
connect_ports(u, &data, PA_DIRECTION_INPUT);
|
||||
@@ -1012,10 +1012,10 @@ static int add_source(struct userdata *u) {
|
||||
if (!u->transport_acquired)
|
||||
switch (u->profile) {
|
||||
case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||
data.suspend_cause = PA_SUSPEND_USER;
|
||||
break;
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
|
||||
+ case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||
/* u->stream_fd contains the error returned by the last transport_acquire()
|
||||
* EAGAIN means we are waiting for a NewConnection signal */
|
||||
if (u->stream_fd == -EAGAIN)
|
||||
@@ -1039,7 +1039,7 @@ static int add_source(struct userdata *u) {
|
||||
u->source->userdata = u;
|
||||
u->source->parent.process_msg = source_process_msg;
|
||||
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
||||
pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
|
||||
u->source->n_volume_steps = 16;
|
||||
}
|
||||
@@ -1151,7 +1151,7 @@ static void sink_set_volume_cb(pa_sink *s) {
|
||||
pa_cvolume_set(&s->real_volume, u->sample_spec.channels, volume);
|
||||
|
||||
/* Set soft volume when in headset role */
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG)
|
||||
pa_cvolume_set(&s->soft_volume, u->sample_spec.channels, volume);
|
||||
|
||||
/* If we are in the AG role, we send a command to the head set to change
|
||||
@@ -1174,17 +1174,17 @@ static int add_sink(struct userdata *u) {
|
||||
data.namereg_fail = false;
|
||||
pa_proplist_sets(data.proplist, "bluetooth.protocol", pa_bluetooth_profile_to_string(u->profile));
|
||||
pa_sink_new_data_set_sample_spec(&data, &u->sample_spec);
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT)
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS)
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
|
||||
|
||||
connect_ports(u, &data, PA_DIRECTION_OUTPUT);
|
||||
|
||||
if (!u->transport_acquired)
|
||||
switch (u->profile) {
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||
data.suspend_cause = PA_SUSPEND_USER;
|
||||
break;
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
|
||||
+ case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||
/* u->stream_fd contains the error returned by the last transport_acquire()
|
||||
* EAGAIN means we are waiting for a NewConnection signal */
|
||||
if (u->stream_fd == -EAGAIN)
|
||||
@@ -1210,7 +1210,7 @@ static int add_sink(struct userdata *u) {
|
||||
u->sink->userdata = u;
|
||||
u->sink->parent.process_msg = sink_process_msg;
|
||||
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
||||
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
|
||||
u->sink->n_volume_steps = 16;
|
||||
}
|
||||
@@ -1219,7 +1219,7 @@ static int add_sink(struct userdata *u) {
|
||||
|
||||
/* Run from main thread */
|
||||
static void transport_config(struct userdata *u) {
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
||||
u->sample_spec.format = PA_SAMPLE_S16LE;
|
||||
u->sample_spec.channels = 1;
|
||||
u->sample_spec.rate = 8000;
|
||||
@@ -1349,7 +1349,7 @@ static int setup_transport(struct userdata *u) {
|
||||
|
||||
u->transport = t;
|
||||
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG)
|
||||
transport_acquire(u, true); /* In case of error, the sink/sources will be created suspended */
|
||||
else {
|
||||
int transport_error;
|
||||
@@ -1369,8 +1369,8 @@ static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
|
||||
static const pa_direction_t profile_direction[] = {
|
||||
[PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
|
||||
[PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
|
||||
- [PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
|
||||
- [PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
|
||||
+ [PA_BLUETOOTH_PROFILE_HSP_HS] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
|
||||
+ [PA_BLUETOOTH_PROFILE_HFP_AG] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
|
||||
[PA_BLUETOOTH_PROFILE_OFF] = 0
|
||||
};
|
||||
|
||||
@@ -1620,7 +1620,7 @@ static int start_thread(struct userdata *u) {
|
||||
|
||||
/* 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_HEADSET_AUDIO_GATEWAY)
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG)
|
||||
u->sink->priority = 1500;
|
||||
|
||||
pa_sink_put(u->sink);
|
||||
@@ -1636,7 +1636,7 @@ static int start_thread(struct userdata *u) {
|
||||
/* 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_HEADSET_AUDIO_GATEWAY || u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE)
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG || u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE)
|
||||
u->source->priority = 1500;
|
||||
|
||||
pa_source_put(u->source);
|
||||
@@ -1873,7 +1873,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro
|
||||
p = PA_CARD_PROFILE_DATA(cp);
|
||||
break;
|
||||
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
|
||||
+ case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||
cp = pa_card_profile_new(name, _("Headset Head Unit (HSP/HFP)"), sizeof(pa_bluetooth_profile_t));
|
||||
cp->priority = 20;
|
||||
cp->n_sinks = 1;
|
||||
@@ -1886,7 +1886,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro
|
||||
p = PA_CARD_PROFILE_DATA(cp);
|
||||
break;
|
||||
|
||||
- case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||
cp = pa_card_profile_new(name, _("Headset Audio Gateway (HSP/HFP)"), sizeof(pa_bluetooth_profile_t));
|
||||
cp->priority = 20;
|
||||
cp->n_sinks = 1;
|
||||
@@ -1961,9 +1961,9 @@ static int uuid_to_profile(const char *uuid, pa_bluetooth_profile_t *_r) {
|
||||
else if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE))
|
||||
*_r = PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
|
||||
else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF))
|
||||
- *_r = PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT;
|
||||
+ *_r = PA_BLUETOOTH_PROFILE_HSP_HS;
|
||||
else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_AG) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_AG))
|
||||
- *_r = PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY;
|
||||
+ *_r = PA_BLUETOOTH_PROFILE_HFP_AG;
|
||||
else
|
||||
return -PA_ERR_INVALID;
|
||||
|
||||
@@ -2174,7 +2174,7 @@ static pa_hook_result_t transport_speaker_gain_changed_cb(pa_bluetooth_discovery
|
||||
volume++;
|
||||
|
||||
pa_cvolume_set(&v, u->sample_spec.channels, volume);
|
||||
- if (t->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT)
|
||||
+ if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS)
|
||||
pa_sink_volume_changed(u->sink, &v);
|
||||
else
|
||||
pa_sink_set_volume(u->sink, &v, true, true);
|
||||
@@ -2202,7 +2202,7 @@ static pa_hook_result_t transport_microphone_gain_changed_cb(pa_bluetooth_discov
|
||||
|
||||
pa_cvolume_set(&v, u->sample_spec.channels, volume);
|
||||
|
||||
- if (t->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT)
|
||||
+ if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS)
|
||||
pa_source_volume_changed(u->source, &v);
|
||||
else
|
||||
pa_source_set_volume(u->source, &v, true, true);
|
||||
394
v5-2-4-bluetooth-separate-HSP-and-HFP.patch
Normal file
394
v5-2-4-bluetooth-separate-HSP-and-HFP.patch
Normal file
@ -0,0 +1,394 @@
|
||||
diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c
|
||||
index f2009bfd..9ec9244b 100644
|
||||
--- a/src/modules/bluetooth/backend-native.c
|
||||
+++ b/src/modules/bluetooth/backend-native.c
|
||||
@@ -62,6 +62,7 @@ struct transport_data {
|
||||
#define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1"
|
||||
|
||||
#define HSP_AG_PROFILE "/Profile/HSPAGProfile"
|
||||
+#define HFP_AG_PROFILE "/Profile/HFPAGProfile"
|
||||
#define HSP_HS_PROFILE "/Profile/HSPHSProfile"
|
||||
|
||||
/* RFCOMM channel for HSP headset role
|
||||
@@ -512,6 +513,8 @@ static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m,
|
||||
p = PA_BLUETOOTH_PROFILE_HSP_HS;
|
||||
} else if (pa_streq(handler, HSP_HS_PROFILE)) {
|
||||
p = PA_BLUETOOTH_PROFILE_HFP_AG;
|
||||
+ } else if (pa_streq(handler, HFP_AG_PROFILE)) {
|
||||
+ p = PA_BLUETOOTH_PROFILE_HFP_HF;
|
||||
} else {
|
||||
pa_log_error("Invalid handler");
|
||||
goto fail;
|
||||
@@ -589,7 +592,8 @@ static DBusHandlerResult profile_handler(DBusConnection *c, DBusMessage *m, void
|
||||
|
||||
pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
|
||||
|
||||
- if (!pa_streq(path, HSP_AG_PROFILE) && !pa_streq(path, HSP_HS_PROFILE))
|
||||
+ if (!pa_streq(path, HSP_AG_PROFILE) && !pa_streq(path, HSP_HS_PROFILE)
|
||||
+ && !pa_streq(path, HFP_AG_PROFILE))
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
|
||||
if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
|
||||
@@ -634,6 +638,10 @@ static void profile_init(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile
|
||||
object_name = HSP_HS_PROFILE;
|
||||
uuid = PA_BLUETOOTH_UUID_HSP_HS;
|
||||
break;
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_HF:
|
||||
+ object_name = HFP_AG_PROFILE;
|
||||
+ uuid = PA_BLUETOOTH_UUID_HFP_AG;
|
||||
+ break;
|
||||
default:
|
||||
pa_assert_not_reached();
|
||||
break;
|
||||
@@ -653,6 +661,9 @@ static void profile_done(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile
|
||||
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||
dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HSP_HS_PROFILE);
|
||||
break;
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_HF:
|
||||
+ dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HFP_AG_PROFILE);
|
||||
+ break;
|
||||
default:
|
||||
pa_assert_not_reached();
|
||||
break;
|
||||
@@ -695,6 +706,8 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d
|
||||
if (enable_hs_role)
|
||||
profile_init(backend, PA_BLUETOOTH_PROFILE_HFP_AG);
|
||||
profile_init(backend, PA_BLUETOOTH_PROFILE_HSP_HS);
|
||||
+ if (pa_bluetooth_discovery_get_enable_native_hfp_hf(y))
|
||||
+ profile_init(backend, PA_BLUETOOTH_PROFILE_HFP_HF);
|
||||
|
||||
return backend;
|
||||
}
|
||||
@@ -707,6 +720,8 @@ void pa_bluetooth_native_backend_free(pa_bluetooth_backend *backend) {
|
||||
if (backend->enable_hs_role)
|
||||
profile_done(backend, PA_BLUETOOTH_PROFILE_HFP_AG);
|
||||
profile_done(backend, PA_BLUETOOTH_PROFILE_HSP_HS);
|
||||
+ if (pa_bluetooth_discovery_get_enable_native_hfp_hf(backend->discovery))
|
||||
+ profile_done(backend, PA_BLUETOOTH_PROFILE_HFP_HF);
|
||||
|
||||
pa_dbus_connection_unref(backend->connection);
|
||||
|
||||
diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c
|
||||
index 4470f2ef..80a025d5 100644
|
||||
--- a/src/modules/bluetooth/bluez5-util.c
|
||||
+++ b/src/modules/bluetooth/bluez5-util.c
|
||||
@@ -92,6 +92,7 @@ struct pa_bluetooth_discovery {
|
||||
int headset_backend;
|
||||
pa_bluetooth_backend *ofono_backend, *native_backend;
|
||||
PA_LLIST_HEAD(pa_dbus_pending, pending);
|
||||
+ bool enable_native_hfp_hf;
|
||||
};
|
||||
|
||||
static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, DBusMessage *m,
|
||||
@@ -169,14 +170,27 @@ static const char *transport_state_to_string(pa_bluetooth_transport_state_t stat
|
||||
}
|
||||
|
||||
static bool device_supports_profile(pa_bluetooth_device *device, pa_bluetooth_profile_t profile) {
|
||||
+ bool show_hfp, show_hsp, enable_native_hfp_hf;
|
||||
+
|
||||
+ enable_native_hfp_hf = pa_bluetooth_discovery_get_enable_native_hfp_hf(device->discovery);
|
||||
+
|
||||
+ if (enable_native_hfp_hf) {
|
||||
+ show_hfp = pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_HF);
|
||||
+ show_hsp = !show_hfp;
|
||||
+ } else {
|
||||
+ show_hfp = false;
|
||||
+ show_hsp = true;
|
||||
+ }
|
||||
+
|
||||
switch (profile) {
|
||||
case PA_BLUETOOTH_PROFILE_A2DP_SINK:
|
||||
return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_A2DP_SINK);
|
||||
case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
|
||||
return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_A2DP_SOURCE);
|
||||
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||
- return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_HS)
|
||||
- || !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_HF);
|
||||
+ return show_hsp && !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_HS);
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_HF:
|
||||
+ return show_hfp && !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_HF);
|
||||
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||
return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_AG)
|
||||
|| !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_AG);
|
||||
@@ -536,6 +550,14 @@ pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_path(pa_bluetooth_disc
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+bool pa_bluetooth_discovery_get_enable_native_hfp_hf(pa_bluetooth_discovery *y)
|
||||
+{
|
||||
+ pa_assert(y);
|
||||
+ pa_assert(PA_REFCNT_VALUE(y) > 0);
|
||||
+
|
||||
+ return y->enable_native_hfp_hf;
|
||||
+}
|
||||
+
|
||||
pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_address(pa_bluetooth_discovery *y, const char *remote, const char *local) {
|
||||
pa_bluetooth_device *d;
|
||||
void *state = NULL;
|
||||
@@ -1306,6 +1328,8 @@ const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile) {
|
||||
return "a2dp_source";
|
||||
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||
return "headset_head_unit";
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_HF:
|
||||
+ return "headset_handsfree";
|
||||
case PA_BLUETOOTH_PROFILE_HFP_AG:
|
||||
return "headset_audio_gateway";
|
||||
case PA_BLUETOOTH_PROFILE_OFF:
|
||||
@@ -1727,7 +1751,7 @@ static void endpoint_done(pa_bluetooth_discovery *y, pa_bluetooth_profile_t prof
|
||||
}
|
||||
}
|
||||
|
||||
-pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c, int headset_backend) {
|
||||
+pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c, int headset_backend, bool enable_native_hfp_hf) {
|
||||
pa_bluetooth_discovery *y;
|
||||
DBusError err;
|
||||
DBusConnection *conn;
|
||||
@@ -1737,6 +1761,7 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c, int headset_backe
|
||||
PA_REFCNT_INIT(y);
|
||||
y->core = c;
|
||||
y->headset_backend = headset_backend;
|
||||
+ y->enable_native_hfp_hf = enable_native_hfp_hf;
|
||||
y->adapters = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
|
||||
(pa_free_cb_t) adapter_free);
|
||||
y->devices = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
|
||||
diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h
|
||||
index 84c0c3f1..b077ca2c 100644
|
||||
--- a/src/modules/bluetooth/bluez5-util.h
|
||||
+++ b/src/modules/bluetooth/bluez5-util.h
|
||||
@@ -47,6 +47,7 @@ typedef enum profile {
|
||||
PA_BLUETOOTH_PROFILE_A2DP_SINK,
|
||||
PA_BLUETOOTH_PROFILE_A2DP_SOURCE,
|
||||
PA_BLUETOOTH_PROFILE_HSP_HS,
|
||||
+ PA_BLUETOOTH_PROFILE_HFP_HF,
|
||||
PA_BLUETOOTH_PROFILE_HFP_AG,
|
||||
PA_BLUETOOTH_PROFILE_OFF
|
||||
} pa_bluetooth_profile_t;
|
||||
@@ -161,8 +162,9 @@ const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile);
|
||||
#define HEADSET_BACKEND_NATIVE 1
|
||||
#define HEADSET_BACKEND_AUTO 2
|
||||
|
||||
-pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core, int headset_backend);
|
||||
+pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core, int headset_backend, bool default_profile_hfp);
|
||||
pa_bluetooth_discovery* pa_bluetooth_discovery_ref(pa_bluetooth_discovery *y);
|
||||
void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y);
|
||||
void pa_bluetooth_discovery_set_ofono_running(pa_bluetooth_discovery *y, bool is_running);
|
||||
+bool pa_bluetooth_discovery_get_enable_native_hfp_hf(pa_bluetooth_discovery *y);
|
||||
#endif
|
||||
diff --git a/src/modules/bluetooth/module-bluetooth-policy.c b/src/modules/bluetooth/module-bluetooth-policy.c
|
||||
index 316b9a82..b17c5d39 100644
|
||||
--- a/src/modules/bluetooth/module-bluetooth-policy.c
|
||||
+++ b/src/modules/bluetooth/module-bluetooth-policy.c
|
||||
@@ -365,7 +365,8 @@ 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 */
|
||||
/* TODO: remove a2dp and hsp when we remove BlueZ 4 support */
|
||||
if (pa_streq(profile->name, "hsp") || pa_streq(profile->name, "a2dp") || 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"))
|
||||
return PA_HOOK_OK;
|
||||
|
||||
is_active_profile = card->active_profile == profile;
|
||||
diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
|
||||
index d076fbad..d37ce9ce 100644
|
||||
--- a/src/modules/bluetooth/module-bluez5-device.c
|
||||
+++ b/src/modules/bluetooth/module-bluez5-device.c
|
||||
@@ -258,6 +258,7 @@ static int sco_process_render(struct userdata *u) {
|
||||
|
||||
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);
|
||||
pa_assert(u->sink);
|
||||
|
||||
@@ -318,6 +319,7 @@ static int sco_process_push(struct userdata *u) {
|
||||
|
||||
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);
|
||||
pa_assert(u->source);
|
||||
pa_assert(u->read_smoother);
|
||||
@@ -784,7 +786,9 @@ static void transport_release(struct userdata *u) {
|
||||
|
||||
/* 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_HFP_AG) {
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
||||
+ || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF
|
||||
+ || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
||||
u->read_block_size = u->read_link_mtu;
|
||||
u->write_block_size = u->write_link_mtu;
|
||||
|
||||
@@ -1004,7 +1008,8 @@ static int add_source(struct userdata *u) {
|
||||
data.namereg_fail = false;
|
||||
pa_proplist_sets(data.proplist, "bluetooth.protocol", pa_bluetooth_profile_to_string(u->profile));
|
||||
pa_source_new_data_set_sample_spec(&data, &u->sample_spec);
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS)
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
||||
+ || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF)
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
|
||||
|
||||
connect_ports(u, &data, PA_DIRECTION_INPUT);
|
||||
@@ -1016,6 +1021,7 @@ static int add_source(struct userdata *u) {
|
||||
data.suspend_cause = PA_SUSPEND_USER;
|
||||
break;
|
||||
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_HF:
|
||||
/* u->stream_fd contains the error returned by the last transport_acquire()
|
||||
* EAGAIN means we are waiting for a NewConnection signal */
|
||||
if (u->stream_fd == -EAGAIN)
|
||||
@@ -1039,7 +1045,9 @@ static int add_source(struct userdata *u) {
|
||||
u->source->userdata = u;
|
||||
u->source->parent.process_msg = source_process_msg;
|
||||
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
||||
+ || 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);
|
||||
u->source->n_volume_steps = 16;
|
||||
}
|
||||
@@ -1174,7 +1182,8 @@ static int add_sink(struct userdata *u) {
|
||||
data.namereg_fail = false;
|
||||
pa_proplist_sets(data.proplist, "bluetooth.protocol", pa_bluetooth_profile_to_string(u->profile));
|
||||
pa_sink_new_data_set_sample_spec(&data, &u->sample_spec);
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS)
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
||||
+ || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF)
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
|
||||
|
||||
connect_ports(u, &data, PA_DIRECTION_OUTPUT);
|
||||
@@ -1185,6 +1194,7 @@ static int add_sink(struct userdata *u) {
|
||||
data.suspend_cause = PA_SUSPEND_USER;
|
||||
break;
|
||||
case PA_BLUETOOTH_PROFILE_HSP_HS:
|
||||
+ case PA_BLUETOOTH_PROFILE_HFP_HF:
|
||||
/* u->stream_fd contains the error returned by the last transport_acquire()
|
||||
* EAGAIN means we are waiting for a NewConnection signal */
|
||||
if (u->stream_fd == -EAGAIN)
|
||||
@@ -1210,7 +1220,9 @@ static int add_sink(struct userdata *u) {
|
||||
u->sink->userdata = u;
|
||||
u->sink->parent.process_msg = sink_process_msg;
|
||||
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
||||
+ || 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);
|
||||
u->sink->n_volume_steps = 16;
|
||||
}
|
||||
@@ -1219,7 +1231,9 @@ static int add_sink(struct userdata *u) {
|
||||
|
||||
/* Run from main thread */
|
||||
static void transport_config(struct userdata *u) {
|
||||
- if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
||||
+ if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
|
||||
+ || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF
|
||||
+ || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) {
|
||||
u->sample_spec.format = PA_SAMPLE_S16LE;
|
||||
u->sample_spec.channels = 1;
|
||||
u->sample_spec.rate = 8000;
|
||||
@@ -1370,6 +1384,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_SOURCE] = PA_DIRECTION_INPUT,
|
||||
[PA_BLUETOOTH_PROFILE_HSP_HS] = 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
|
||||
};
|
||||
@@ -1874,7 +1889,20 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro
|
||||
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 = 20;
|
||||
+ 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->priority = 20;
|
||||
cp->n_sinks = 1;
|
||||
cp->n_sources = 1;
|
||||
@@ -1960,8 +1988,10 @@ static int uuid_to_profile(const char *uuid, pa_bluetooth_profile_t *_r) {
|
||||
*_r = PA_BLUETOOTH_PROFILE_A2DP_SINK;
|
||||
else if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE))
|
||||
*_r = PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
|
||||
- else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF))
|
||||
+ else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS))
|
||||
*_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))
|
||||
*_r = PA_BLUETOOTH_PROFILE_HFP_AG;
|
||||
else
|
||||
@@ -1980,6 +2010,7 @@ static int add_card(struct userdata *u) {
|
||||
pa_bluetooth_profile_t *p;
|
||||
const char *uuid;
|
||||
void *state;
|
||||
+ bool enable_native_hfp_hf, has_both;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(u->device);
|
||||
@@ -2010,9 +2041,22 @@ static int add_card(struct userdata *u) {
|
||||
|
||||
create_card_ports(u, data.ports);
|
||||
|
||||
+ enable_native_hfp_hf = pa_bluetooth_discovery_get_enable_native_hfp_hf(u->discovery);
|
||||
+
|
||||
+ has_both = enable_native_hfp_hf && pa_hashmap_get(d->uuids, PA_BLUETOOTH_UUID_HFP_HF) && pa_hashmap_get(d->uuids, PA_BLUETOOTH_UUID_HSP_HS);
|
||||
PA_HASHMAP_FOREACH(uuid, d->uuids, state) {
|
||||
pa_bluetooth_profile_t profile;
|
||||
|
||||
+ if (!enable_native_hfp_hf && pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF)) {
|
||||
+ pa_log_info("device supports HFP but disabling profile as requested");
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (has_both && pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS)) {
|
||||
+ pa_log_info("device support HSP and HFP, selecting HFP only");
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
if (uuid_to_profile(uuid, &profile) < 0)
|
||||
continue;
|
||||
|
||||
diff --git a/src/modules/bluetooth/module-bluez5-discover.c b/src/modules/bluetooth/module-bluez5-discover.c
|
||||
index c535ead4..bfb361ae 100644
|
||||
--- a/src/modules/bluetooth/module-bluez5-discover.c
|
||||
+++ b/src/modules/bluetooth/module-bluez5-discover.c
|
||||
@@ -104,6 +104,7 @@ int pa__init(pa_module *m) {
|
||||
const char *headset_str;
|
||||
int headset_backend;
|
||||
bool autodetect_mtu;
|
||||
+ bool enable_native_hfp_hf = true;
|
||||
|
||||
pa_assert(m);
|
||||
|
||||
@@ -127,6 +128,9 @@ int pa__init(pa_module *m) {
|
||||
autodetect_mtu = false;
|
||||
if (pa_modargs_get_value_boolean(ma, "autodetect_mtu", &autodetect_mtu) < 0) {
|
||||
pa_log("Invalid boolean value for autodetect_mtu parameter");
|
||||
+ }
|
||||
+ if (pa_modargs_get_value_boolean(ma, "enable_native_hfp_hf", &enable_native_hfp_hf) < 0) {
|
||||
+ pa_log("enable_native_hfp_hf must be true or false");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -136,7 +140,7 @@ int pa__init(pa_module *m) {
|
||||
u->autodetect_mtu = autodetect_mtu;
|
||||
u->loaded_device_paths = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
|
||||
|
||||
- if (!(u->discovery = pa_bluetooth_discovery_get(u->core, headset_backend)))
|
||||
+ if (!(u->discovery = pa_bluetooth_discovery_get(u->core, headset_backend, enable_native_hfp_hf)))
|
||||
goto fail;
|
||||
|
||||
u->device_connection_changed_slot =
|
||||
199
v5-3-4-bluetooth-add-correct-HFP-rfcomm-negotiation.patch
Normal file
199
v5-3-4-bluetooth-add-correct-HFP-rfcomm-negotiation.patch
Normal file
@ -0,0 +1,199 @@
|
||||
diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c
|
||||
index 9ec9244b..99efa066 100644
|
||||
--- a/src/modules/bluetooth/backend-native.c
|
||||
+++ b/src/modules/bluetooth/backend-native.c
|
||||
@@ -53,6 +53,43 @@ struct transport_data {
|
||||
pa_mainloop_api *mainloop;
|
||||
};
|
||||
|
||||
+struct hfp_config {
|
||||
+ uint32_t capabilities;
|
||||
+ int state;
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * the separate hansfree headset (HF) and Audio Gateway (AG) features
|
||||
+ */
|
||||
+enum hfp_hf_features {
|
||||
+ HFP_HF_EC_NR = 0,
|
||||
+ HFP_HF_CALL_WAITING = 1,
|
||||
+ HFP_HF_CLI = 2,
|
||||
+ HFP_HF_VR = 3,
|
||||
+ HFP_HF_RVOL = 4,
|
||||
+ HFP_HF_ESTATUS = 5,
|
||||
+ HFP_HF_ECALL = 6,
|
||||
+ HFP_HF_CODECS = 7,
|
||||
+};
|
||||
+
|
||||
+enum hfp_ag_features {
|
||||
+ HFP_AG_THREE_WAY = 0,
|
||||
+ HFP_AG_EC_NR = 1,
|
||||
+ HFP_AG_VR = 2,
|
||||
+ HFP_AG_RING = 3,
|
||||
+ HFP_AG_NUM_TAG = 4,
|
||||
+ HFP_AG_REJECT = 5,
|
||||
+ HFP_AG_ESTATUS = 6,
|
||||
+ HFP_AG_ECALL = 7,
|
||||
+ HFP_AG_EERR = 8,
|
||||
+ HFP_AG_CODECS = 9,
|
||||
+};
|
||||
+
|
||||
+/* gateway features we support, which is as little as we can get away with */
|
||||
+static uint32_t hfp_features =
|
||||
+ /* HFP 1.6 requires this */
|
||||
+ (1 << HFP_AG_ESTATUS );
|
||||
+
|
||||
#define BLUEZ_SERVICE "org.bluez"
|
||||
#define BLUEZ_MEDIA_TRANSPORT_INTERFACE BLUEZ_SERVICE ".MediaTransport1"
|
||||
|
||||
@@ -109,6 +146,27 @@ static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_backend *backend, D
|
||||
return p;
|
||||
}
|
||||
|
||||
+static void rfcomm_write(int fd, const char *str)
|
||||
+{
|
||||
+ size_t len;
|
||||
+ char buf[512];
|
||||
+
|
||||
+ pa_log_debug("RFCOMM >> %s", str);
|
||||
+ sprintf(buf, "\r\n%s\r\n", str);
|
||||
+ len = write(fd, buf, strlen(buf));
|
||||
+
|
||||
+ if (len != strlen(buf))
|
||||
+ pa_log_error("RFCOMM write error: %s", pa_cstrerror(errno));
|
||||
+}
|
||||
+
|
||||
+static void hfp_send_features(int fd)
|
||||
+{
|
||||
+ char buf[512];
|
||||
+
|
||||
+ sprintf(buf, "+BRSF: %d", hfp_features);
|
||||
+ rfcomm_write(fd, buf);
|
||||
+}
|
||||
+
|
||||
static int sco_do_connect(pa_bluetooth_transport *t) {
|
||||
pa_bluetooth_device *d = t->device;
|
||||
struct sockaddr_sco addr;
|
||||
@@ -352,6 +410,61 @@ static void register_profile(pa_bluetooth_backend *b, const char *profile, const
|
||||
send_and_add_to_pending(b, m, register_profile_reply, pa_xstrdup(profile));
|
||||
}
|
||||
|
||||
+static void transport_put(pa_bluetooth_transport *t)
|
||||
+{
|
||||
+ pa_bluetooth_transport_put(t);
|
||||
+
|
||||
+ pa_log_debug("Transport %s available for profile %s", t->path, pa_bluetooth_profile_to_string(t->profile));
|
||||
+}
|
||||
+
|
||||
+static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf)
|
||||
+{
|
||||
+ struct hfp_config *c = t->config;
|
||||
+ int val;
|
||||
+
|
||||
+ /* stateful negotiation */
|
||||
+ if (c->state == 0 && sscanf(buf, "AT+BRSF=%d", &val) == 1) {
|
||||
+ c->capabilities = val;
|
||||
+ pa_log_info("HFP capabilities returns 0x%x", val);
|
||||
+ hfp_send_features(fd);
|
||||
+ c->state = 1;
|
||||
+ return true;
|
||||
+ } else if (c->state == 1 && pa_startswith(buf, "AT+CIND=?")) {
|
||||
+ /* we declare minimal no indicators */
|
||||
+ rfcomm_write(fd, "+CIND: "
|
||||
+ /* many indicators can be supported, only call and
|
||||
+ * callheld are mandatory, so that's all we repy */
|
||||
+ "(\"call\",(0-1)),"
|
||||
+ "(\"callheld\",(0-2))");
|
||||
+ c->state = 2;
|
||||
+ return true;
|
||||
+ } else if (c->state == 2 && pa_startswith(buf, "AT+CIND?")) {
|
||||
+ rfcomm_write(fd, "+CIND: 0,0");
|
||||
+ c->state = 3;
|
||||
+ return true;
|
||||
+ } else if ((c->state == 2 || c->state == 3) && pa_startswith(buf, "AT+CMER=")) {
|
||||
+ rfcomm_write(fd, "\r\nOK\r\n");
|
||||
+ c->state = 4;
|
||||
+ transport_put(t);
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /* if we get here, negotiation should be complete */
|
||||
+ if (c->state != 4) {
|
||||
+ pa_log_error("HFP negotiation failed in state %d with inbound %s\n",
|
||||
+ c->state, buf);
|
||||
+ rfcomm_write(fd, "ERROR");
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * once we're fully connected, just reply OK to everything
|
||||
+ * it will just be the headset sending the occasional status
|
||||
+ * update, but we process only the ones we care about
|
||||
+ */
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
|
||||
pa_bluetooth_transport *t = userdata;
|
||||
|
||||
@@ -398,6 +511,8 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i
|
||||
do_reply = true;
|
||||
} else if (sscanf(buf, "AT+CKPD=%d", &dummy) == 1) {
|
||||
do_reply = true;
|
||||
+ } else if (t->config) { /* t->config is only non-null for hfp profile */
|
||||
+ do_reply = hfp_rfcomm_handle(fd, t, buf);
|
||||
} else {
|
||||
do_reply = false;
|
||||
}
|
||||
@@ -540,7 +655,9 @@ static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m,
|
||||
sender = dbus_message_get_sender(m);
|
||||
|
||||
pathfd = pa_sprintf_malloc ("%s/fd%d", path, fd);
|
||||
- t = pa_bluetooth_transport_new(d, sender, pathfd, p, NULL, 0);
|
||||
+ t = pa_bluetooth_transport_new(d, sender, pathfd, p, NULL,
|
||||
+ p == PA_BLUETOOTH_PROFILE_HFP_HF ?
|
||||
+ sizeof(struct hfp_config) : 0);
|
||||
pa_xfree(pathfd);
|
||||
|
||||
t->acquire = sco_acquire_cb;
|
||||
@@ -558,9 +675,8 @@ static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m,
|
||||
|
||||
sco_listen(t);
|
||||
|
||||
- pa_bluetooth_transport_put(t);
|
||||
-
|
||||
- pa_log_debug("Transport %s available for profile %s", t->path, pa_bluetooth_profile_to_string(t->profile));
|
||||
+ if (p != PA_BLUETOOTH_PROFILE_HFP_HF)
|
||||
+ transport_put(t);
|
||||
|
||||
pa_assert_se(r = dbus_message_new_method_return(m));
|
||||
|
||||
diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c
|
||||
index 80a025d5..8be8a11d 100644
|
||||
--- a/src/modules/bluetooth/bluez5-util.c
|
||||
+++ b/src/modules/bluetooth/bluez5-util.c
|
||||
@@ -150,7 +150,10 @@ pa_bluetooth_transport *pa_bluetooth_transport_new(pa_bluetooth_device *d, const
|
||||
|
||||
if (size > 0) {
|
||||
t->config = pa_xnew(uint8_t, size);
|
||||
- memcpy(t->config, config, size);
|
||||
+ if (config)
|
||||
+ memcpy(t->config, config, size);
|
||||
+ else
|
||||
+ memset(t->config, 0, size);
|
||||
}
|
||||
|
||||
return t;
|
||||
diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h
|
||||
index b077ca2c..23f9a798 100644
|
||||
--- a/src/modules/bluetooth/bluez5-util.h
|
||||
+++ b/src/modules/bluetooth/bluez5-util.h
|
||||
@@ -73,7 +73,7 @@ struct pa_bluetooth_transport {
|
||||
pa_bluetooth_profile_t profile;
|
||||
|
||||
uint8_t codec;
|
||||
- uint8_t *config;
|
||||
+ void *config;
|
||||
size_t config_size;
|
||||
|
||||
uint16_t microphone_gain;
|
||||
32
v5-4-4-bluetooth-make-native-the-default-backend.patch
Normal file
32
v5-4-4-bluetooth-make-native-the-default-backend.patch
Normal file
@ -0,0 +1,32 @@
|
||||
diff --git a/src/modules/bluetooth/module-bluez5-discover.c b/src/modules/bluetooth/module-bluez5-discover.c
|
||||
index bfb361ae..d2a0420d 100644
|
||||
--- a/src/modules/bluetooth/module-bluez5-discover.c
|
||||
+++ b/src/modules/bluetooth/module-bluez5-discover.c
|
||||
@@ -93,7 +93,7 @@ static pa_hook_result_t device_connection_changed_cb(pa_bluetooth_discovery *y,
|
||||
}
|
||||
|
||||
#ifdef HAVE_BLUEZ_5_NATIVE_HEADSET
|
||||
-const char *default_headset_backend = "auto";
|
||||
+const char *default_headset_backend = "native";
|
||||
#else
|
||||
const char *default_headset_backend = "ofono";
|
||||
#endif
|
||||
@@ -104,7 +104,7 @@ int pa__init(pa_module *m) {
|
||||
const char *headset_str;
|
||||
int headset_backend;
|
||||
bool autodetect_mtu;
|
||||
- bool enable_native_hfp_hf = true;
|
||||
+ bool enable_native_hfp_hf;
|
||||
|
||||
pa_assert(m);
|
||||
|
||||
@@ -125,6 +125,9 @@ int pa__init(pa_module *m) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
+ /* default value if no module parameter */
|
||||
+ enable_native_hfp_hf = (headset_backend == HEADSET_BACKEND_NATIVE);
|
||||
+
|
||||
autodetect_mtu = false;
|
||||
if (pa_modargs_get_value_boolean(ma, "autodetect_mtu", &autodetect_mtu) < 0) {
|
||||
pa_log("Invalid boolean value for autodetect_mtu parameter");
|
||||
Loading…
Reference in New Issue
Block a user