mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-04 13:29:59 -05:00
bluetooth: add HFP Gateway support
Create the 'Handsfree Gateway' profile for bluetooth cards and add filters for 'org.bluez.HandsfreeGateway' to the discover module so module-bluetooth-device is loaded with the correct profile when a Handsfree Gateway connects to bluetoothd (in this case bluetoothd is acting as the headset).
This commit is contained in:
parent
edf5f5be6b
commit
342e06498f
4 changed files with 72 additions and 20 deletions
|
|
@ -98,6 +98,7 @@ static pa_bluetooth_device* device_new(const char *path) {
|
||||||
d->audio_sink_state = PA_BT_AUDIO_STATE_INVALID;
|
d->audio_sink_state = PA_BT_AUDIO_STATE_INVALID;
|
||||||
d->audio_source_state = PA_BT_AUDIO_STATE_INVALID;
|
d->audio_source_state = PA_BT_AUDIO_STATE_INVALID;
|
||||||
d->headset_state = PA_BT_AUDIO_STATE_INVALID;
|
d->headset_state = PA_BT_AUDIO_STATE_INVALID;
|
||||||
|
d->hfgw_state = PA_BT_AUDIO_STATE_INVALID;
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
@ -123,11 +124,11 @@ static pa_bool_t device_is_audio(pa_bluetooth_device *d) {
|
||||||
pa_assert(d);
|
pa_assert(d);
|
||||||
|
|
||||||
return
|
return
|
||||||
d->device_info_valid &&
|
d->device_info_valid && (d->hfgw_state != PA_BT_AUDIO_STATE_INVALID ||
|
||||||
(d->audio_state != PA_BT_AUDIO_STATE_INVALID &&
|
(d->audio_state != PA_BT_AUDIO_STATE_INVALID &&
|
||||||
(d->audio_sink_state != PA_BT_AUDIO_STATE_INVALID ||
|
(d->audio_sink_state != PA_BT_AUDIO_STATE_INVALID ||
|
||||||
d->audio_source_state != PA_BT_AUDIO_STATE_INVALID ||
|
d->audio_source_state != PA_BT_AUDIO_STATE_INVALID ||
|
||||||
d->headset_state != PA_BT_AUDIO_STATE_INVALID));
|
d->headset_state != PA_BT_AUDIO_STATE_INVALID)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device *d, DBusMessageIter *i) {
|
static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device *d, DBusMessageIter *i) {
|
||||||
|
|
@ -230,7 +231,10 @@ static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device
|
||||||
PA_LLIST_PREPEND(pa_bluetooth_uuid, d->uuids, node);
|
PA_LLIST_PREPEND(pa_bluetooth_uuid, d->uuids, node);
|
||||||
|
|
||||||
/* Vudentz said the interfaces are here when the UUIDs are announced */
|
/* Vudentz said the interfaces are here when the UUIDs are announced */
|
||||||
if (strcasecmp(HSP_HS_UUID, value) == 0 || strcasecmp(HFP_HS_UUID, value) == 0) {
|
if (strcasecmp(HSP_AG_UUID, value) == 0 || strcasecmp(HFP_AG_UUID, value) == 0) {
|
||||||
|
pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.HandsfreeGateway", "GetProperties"));
|
||||||
|
send_and_add_to_pending(y, d, m, get_properties_reply);
|
||||||
|
} else if (strcasecmp(HSP_HS_UUID, value) == 0 || strcasecmp(HFP_HS_UUID, value) == 0) {
|
||||||
pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Headset", "GetProperties"));
|
pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Headset", "GetProperties"));
|
||||||
send_and_add_to_pending(y, d, m, get_properties_reply);
|
send_and_add_to_pending(y, d, m, get_properties_reply);
|
||||||
} else if (strcasecmp(A2DP_SINK_UUID, value) == 0) {
|
} else if (strcasecmp(A2DP_SINK_UUID, value) == 0) {
|
||||||
|
|
@ -403,9 +407,14 @@ static void get_properties_reply(DBusPendingCall *pending, void *userdata) {
|
||||||
} else if (dbus_message_has_interface(p->message, "org.bluez.AudioSink")) {
|
} else if (dbus_message_has_interface(p->message, "org.bluez.AudioSink")) {
|
||||||
if (parse_audio_property(y, &d->audio_sink_state, &dict_i) < 0)
|
if (parse_audio_property(y, &d->audio_sink_state, &dict_i) < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
} else if (dbus_message_has_interface(p->message, "org.bluez.AudioSource")) {
|
} else if (dbus_message_has_interface(p->message, "org.bluez.AudioSource")) {
|
||||||
if (parse_audio_property(y, &d->audio_source_state, &dict_i) < 0)
|
if (parse_audio_property(y, &d->audio_source_state, &dict_i) < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
} else if (dbus_message_has_interface(p->message, "org.bluez.HandsfreeGateway")) {
|
||||||
|
if (parse_audio_property(y, &d->hfgw_state, &arg_i) < 0)
|
||||||
|
goto finish;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -633,6 +642,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
|
||||||
dbus_message_is_signal(m, "org.bluez.Headset", "PropertyChanged") ||
|
dbus_message_is_signal(m, "org.bluez.Headset", "PropertyChanged") ||
|
||||||
dbus_message_is_signal(m, "org.bluez.AudioSink", "PropertyChanged") ||
|
dbus_message_is_signal(m, "org.bluez.AudioSink", "PropertyChanged") ||
|
||||||
dbus_message_is_signal(m, "org.bluez.AudioSource", "PropertyChanged") ||
|
dbus_message_is_signal(m, "org.bluez.AudioSource", "PropertyChanged") ||
|
||||||
|
dbus_message_is_signal(m, "org.bluez.HandsfreeGateway", "PropertyChanged") ||
|
||||||
dbus_message_is_signal(m, "org.bluez.Device", "PropertyChanged")) {
|
dbus_message_is_signal(m, "org.bluez.Device", "PropertyChanged")) {
|
||||||
|
|
||||||
pa_bluetooth_device *d;
|
pa_bluetooth_device *d;
|
||||||
|
|
@ -660,9 +670,14 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
|
||||||
} else if (dbus_message_has_interface(m, "org.bluez.AudioSink")) {
|
} else if (dbus_message_has_interface(m, "org.bluez.AudioSink")) {
|
||||||
if (parse_audio_property(y, &d->audio_sink_state, &arg_i) < 0)
|
if (parse_audio_property(y, &d->audio_sink_state, &arg_i) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
} else if (dbus_message_has_interface(m, "org.bluez.AudioSource")) {
|
} else if (dbus_message_has_interface(m, "org.bluez.AudioSource")) {
|
||||||
if (parse_audio_property(y, &d->audio_source_state, &arg_i) < 0)
|
if (parse_audio_property(y, &d->audio_source_state, &arg_i) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
} else if (dbus_message_has_interface(m, "org.bluez.HandsfreeGateway")) {
|
||||||
|
if (parse_audio_property(y, &d->hfgw_state, &arg_i) < 0)
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
run_callback(y, d, FALSE);
|
run_callback(y, d, FALSE);
|
||||||
|
|
@ -679,6 +694,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
|
||||||
d->audio_sink_state = PA_BT_AUDIO_STATE_DISCONNECTED;
|
d->audio_sink_state = PA_BT_AUDIO_STATE_DISCONNECTED;
|
||||||
d->audio_source_state = PA_BT_AUDIO_STATE_DISCONNECTED;
|
d->audio_source_state = PA_BT_AUDIO_STATE_DISCONNECTED;
|
||||||
d->headset_state = PA_BT_AUDIO_STATE_DISCONNECTED;
|
d->headset_state = PA_BT_AUDIO_STATE_DISCONNECTED;
|
||||||
|
d->hfgw_state = PA_BT_AUDIO_STATE_DISCONNECTED;
|
||||||
|
|
||||||
run_callback(y, d, FALSE);
|
run_callback(y, d, FALSE);
|
||||||
}
|
}
|
||||||
|
|
@ -809,7 +825,9 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
|
||||||
"type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'",
|
"type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'",
|
||||||
"type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",
|
"type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",
|
||||||
"type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
|
"type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
|
||||||
"type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'", NULL) < 0) {
|
"type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
|
||||||
|
"type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'",
|
||||||
|
NULL) < 0) {
|
||||||
pa_log("Failed to add D-Bus matches: %s", err.message);
|
pa_log("Failed to add D-Bus matches: %s", err.message);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
@ -863,7 +881,9 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
|
||||||
"type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'",
|
"type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'",
|
||||||
"type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",
|
"type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",
|
||||||
"type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
|
"type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
|
||||||
"type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'", NULL);
|
"type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
|
||||||
|
"type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'",
|
||||||
|
NULL);
|
||||||
|
|
||||||
if (y->filter_added)
|
if (y->filter_added)
|
||||||
dbus_connection_remove_filter(pa_dbus_connection_get(y->connection), filter_cb, y);
|
dbus_connection_remove_filter(pa_dbus_connection_get(y->connection), filter_cb, y);
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,9 @@ struct pa_bluetooth_device {
|
||||||
|
|
||||||
/* Headset state */
|
/* Headset state */
|
||||||
pa_bt_audio_state_t headset_state;
|
pa_bt_audio_state_t headset_state;
|
||||||
|
|
||||||
|
/* HandsfreeGateway state */
|
||||||
|
pa_bt_audio_state_t hfgw_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core);
|
pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core);
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ PA_MODULE_USAGE(
|
||||||
"source_name=<name for the source> "
|
"source_name=<name for the source> "
|
||||||
"source_properties=<properties for the source> "
|
"source_properties=<properties for the source> "
|
||||||
"address=<address of the device> "
|
"address=<address of the device> "
|
||||||
"profile=<a2dp|hsp> "
|
"profile=<a2dp|hsp|hfgw> "
|
||||||
"rate=<sample rate> "
|
"rate=<sample rate> "
|
||||||
"channels=<number of channels> "
|
"channels=<number of channels> "
|
||||||
"path=<device object path> "
|
"path=<device object path> "
|
||||||
|
|
@ -133,6 +133,7 @@ enum profile {
|
||||||
PROFILE_A2DP,
|
PROFILE_A2DP,
|
||||||
PROFILE_A2DP_SOURCE,
|
PROFILE_A2DP_SOURCE,
|
||||||
PROFILE_HSP,
|
PROFILE_HSP,
|
||||||
|
PROFILE_HFGW,
|
||||||
PROFILE_OFF
|
PROFILE_OFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -318,12 +319,12 @@ static int parse_caps(struct userdata *u, uint8_t seid, const struct bt_get_capa
|
||||||
pa_log_debug("Payload size is %lu %lu", (unsigned long) bytes_left, (unsigned long) sizeof(*codec));
|
pa_log_debug("Payload size is %lu %lu", (unsigned long) bytes_left, (unsigned long) sizeof(*codec));
|
||||||
|
|
||||||
if (((u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE) && codec->transport != BT_CAPABILITIES_TRANSPORT_A2DP) ||
|
if (((u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE) && codec->transport != BT_CAPABILITIES_TRANSPORT_A2DP) ||
|
||||||
(u->profile == PROFILE_HSP && codec->transport != BT_CAPABILITIES_TRANSPORT_SCO)) {
|
((u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW) && codec->transport != BT_CAPABILITIES_TRANSPORT_SCO)) {
|
||||||
pa_log_error("Got capabilities for wrong codec.");
|
pa_log_error("Got capabilities for wrong codec.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u->profile == PROFILE_HSP) {
|
if (u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW) {
|
||||||
|
|
||||||
if (bytes_left <= 0 || codec->length != sizeof(u->hsp.pcm_capabilities))
|
if (bytes_left <= 0 || codec->length != sizeof(u->hsp.pcm_capabilities))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -401,7 +402,7 @@ static int get_caps(struct userdata *u, uint8_t seid) {
|
||||||
if (u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE)
|
if (u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE)
|
||||||
msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP;
|
msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP;
|
||||||
else {
|
else {
|
||||||
pa_assert(u->profile == PROFILE_HSP);
|
pa_assert(u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW);
|
||||||
msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_SCO;
|
msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_SCO;
|
||||||
}
|
}
|
||||||
msg.getcaps_req.flags = u->auto_connect ? BT_FLAG_AUTOCONNECT : 0;
|
msg.getcaps_req.flags = u->auto_connect ? BT_FLAG_AUTOCONNECT : 0;
|
||||||
|
|
@ -697,7 +698,7 @@ static int set_conf(struct userdata *u) {
|
||||||
if (setup_a2dp(u) < 0)
|
if (setup_a2dp(u) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
pa_assert(u->profile == PROFILE_HSP);
|
pa_assert(u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW);
|
||||||
|
|
||||||
u->sample_spec.format = PA_SAMPLE_S16LE;
|
u->sample_spec.format = PA_SAMPLE_S16LE;
|
||||||
u->sample_spec.channels = 1;
|
u->sample_spec.channels = 1;
|
||||||
|
|
@ -995,7 +996,7 @@ static int hsp_process_render(struct userdata *u) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
pa_assert(u->profile == PROFILE_HSP);
|
pa_assert(u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW);
|
||||||
pa_assert(u->sink);
|
pa_assert(u->sink);
|
||||||
|
|
||||||
/* First, render some data */
|
/* First, render some data */
|
||||||
|
|
@ -1060,7 +1061,7 @@ static int hsp_process_push(struct userdata *u) {
|
||||||
pa_memchunk memchunk;
|
pa_memchunk memchunk;
|
||||||
|
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
pa_assert(u->profile == PROFILE_HSP);
|
pa_assert(u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW);
|
||||||
pa_assert(u->source);
|
pa_assert(u->source);
|
||||||
pa_assert(u->read_smoother);
|
pa_assert(u->read_smoother);
|
||||||
|
|
||||||
|
|
@ -1434,7 +1435,7 @@ static void thread_func(void *userdata) {
|
||||||
if (pollfd && (pollfd->revents & POLLIN)) {
|
if (pollfd && (pollfd->revents & POLLIN)) {
|
||||||
int n_read;
|
int n_read;
|
||||||
|
|
||||||
if (u->profile == PROFILE_HSP)
|
if (u->profile == PROFILE_HSP || PROFILE_HFGW)
|
||||||
n_read = hsp_process_push(u);
|
n_read = hsp_process_push(u);
|
||||||
else
|
else
|
||||||
n_read = a2dp_process_push(u);
|
n_read = a2dp_process_push(u);
|
||||||
|
|
@ -1842,7 +1843,7 @@ static int add_source(struct userdata *u) {
|
||||||
data.module = u->module;
|
data.module = u->module;
|
||||||
pa_source_new_data_set_sample_spec(&data, &u->sample_spec);
|
pa_source_new_data_set_sample_spec(&data, &u->sample_spec);
|
||||||
pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP_SOURCE ? "a2dp_source" : "hsp");
|
pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP_SOURCE ? "a2dp_source" : "hsp");
|
||||||
if (u->profile == PROFILE_HSP)
|
if ((u->profile == PROFILE_HSP) || (u->profile == PROFILE_HFGW))
|
||||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
|
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
|
||||||
data.card = u->card;
|
data.card = u->card;
|
||||||
data.name = get_name("source", u->modargs, u->address, &b);
|
data.name = get_name("source", u->modargs, u->address, &b);
|
||||||
|
|
@ -1870,8 +1871,10 @@ static int add_source(struct userdata *u) {
|
||||||
pa_bytes_to_usec(u->block_size, &u->sample_spec));
|
pa_bytes_to_usec(u->block_size, &u->sample_spec));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u->profile == PROFILE_HSP) {
|
if (u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW)
|
||||||
pa_proplist_sets(u->source->proplist, "bluetooth.nrec", (u->hsp.pcm_capabilities.flags & BT_PCM_FLAG_NREC) ? "1" : "0");
|
pa_proplist_sets(u->source->proplist, "bluetooth.nrec", (u->hsp.pcm_capabilities.flags & BT_PCM_FLAG_NREC) ? "1" : "0");
|
||||||
|
|
||||||
|
if (u->profile == PROFILE_HSP) {
|
||||||
u->source->set_volume = source_set_volume_cb;
|
u->source->set_volume = source_set_volume_cb;
|
||||||
u->source->n_volume_steps = 16;
|
u->source->n_volume_steps = 16;
|
||||||
}
|
}
|
||||||
|
|
@ -1959,12 +1962,14 @@ static int init_profile(struct userdata *u) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (u->profile == PROFILE_A2DP ||
|
if (u->profile == PROFILE_A2DP ||
|
||||||
u->profile == PROFILE_HSP)
|
u->profile == PROFILE_HSP ||
|
||||||
|
u->profile == PROFILE_HFGW)
|
||||||
if (add_sink(u) < 0)
|
if (add_sink(u) < 0)
|
||||||
r = -1;
|
r = -1;
|
||||||
|
|
||||||
if (u->profile == PROFILE_HSP ||
|
if (u->profile == PROFILE_HSP ||
|
||||||
u->profile == PROFILE_A2DP_SOURCE)
|
u->profile == PROFILE_A2DP_SOURCE ||
|
||||||
|
u->profile == PROFILE_HFGW)
|
||||||
if (add_source(u) < 0)
|
if (add_source(u) < 0)
|
||||||
r = -1;
|
r = -1;
|
||||||
|
|
||||||
|
|
@ -2099,6 +2104,10 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
|
||||||
pa_log_warn("A2DP is not connected, refused to switch profile");
|
pa_log_warn("A2DP is not connected, refused to switch profile");
|
||||||
return -PA_ERR_IO;
|
return -PA_ERR_IO;
|
||||||
}
|
}
|
||||||
|
else if (device->hfgw_state <= PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_HFGW) {
|
||||||
|
pa_log_warn("HandsfreeGateway is not connected, refused to switch profile");
|
||||||
|
return -PA_ERR_IO;
|
||||||
|
}
|
||||||
|
|
||||||
if (u->sink) {
|
if (u->sink) {
|
||||||
inputs = pa_sink_move_all_start(u->sink, NULL);
|
inputs = pa_sink_move_all_start(u->sink, NULL);
|
||||||
|
|
@ -2234,6 +2243,20 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
|
||||||
pa_hashmap_put(data.profiles, p->name, p);
|
pa_hashmap_put(data.profiles, p->name, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pa_bluetooth_uuid_has(device->uuids, HFP_AG_UUID)) {
|
||||||
|
p = pa_card_profile_new("hfgw", _("Handsfree Gateway"), sizeof(enum profile));
|
||||||
|
p->priority = 20;
|
||||||
|
p->n_sinks = 1;
|
||||||
|
p->n_sources = 1;
|
||||||
|
p->max_sink_channels = 1;
|
||||||
|
p->max_source_channels = 1;
|
||||||
|
|
||||||
|
d = PA_CARD_PROFILE_DATA(p);
|
||||||
|
*d = PROFILE_HFGW;
|
||||||
|
|
||||||
|
pa_hashmap_put(data.profiles, p->name, p);
|
||||||
|
}
|
||||||
|
|
||||||
pa_assert(!pa_hashmap_isempty(data.profiles));
|
pa_assert(!pa_hashmap_isempty(data.profiles));
|
||||||
|
|
||||||
p = pa_card_profile_new("off", _("Off"), sizeof(enum profile));
|
p = pa_card_profile_new("off", _("Off"), sizeof(enum profile));
|
||||||
|
|
@ -2262,7 +2285,8 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
|
||||||
d = PA_CARD_PROFILE_DATA(u->card->active_profile);
|
d = PA_CARD_PROFILE_DATA(u->card->active_profile);
|
||||||
|
|
||||||
if ((device->headset_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_HSP) ||
|
if ((device->headset_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_HSP) ||
|
||||||
(device->audio_sink_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_A2DP)) {
|
(device->audio_sink_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_A2DP) ||
|
||||||
|
(device->hfgw_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_HFGW)) {
|
||||||
pa_log_warn("Default profile not connected, selecting off profile");
|
pa_log_warn("Default profile not connected, selecting off profile");
|
||||||
u->card->active_profile = pa_hashmap_get(u->card->profiles, "off");
|
u->card->active_profile = pa_hashmap_get(u->card->profiles, "off");
|
||||||
u->card->save_profile = FALSE;
|
u->card->save_profile = FALSE;
|
||||||
|
|
|
||||||
|
|
@ -83,8 +83,10 @@ static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const
|
||||||
|
|
||||||
mi = pa_hashmap_get(u->hashmap, d->path);
|
mi = pa_hashmap_get(u->hashmap, d->path);
|
||||||
|
|
||||||
if (!d->dead &&
|
if (!d->dead && d->device_connected > 0 &&
|
||||||
d->device_connected > 0 && (d->audio_state >= PA_BT_AUDIO_STATE_CONNECTED || d->audio_source_state >= PA_BT_AUDIO_STATE_CONNECTED)) {
|
(d->audio_state >= PA_BT_AUDIO_STATE_CONNECTED ||
|
||||||
|
d->audio_source_state >= PA_BT_AUDIO_STATE_CONNECTED ||
|
||||||
|
d->hfgw_state > PA_BT_AUDIO_STATE_CONNECTED)) {
|
||||||
|
|
||||||
if (!mi) {
|
if (!mi) {
|
||||||
pa_module *m = NULL;
|
pa_module *m = NULL;
|
||||||
|
|
@ -119,6 +121,9 @@ static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const
|
||||||
if (d->audio_source_state >= PA_BT_AUDIO_STATE_CONNECTED)
|
if (d->audio_source_state >= PA_BT_AUDIO_STATE_CONNECTED)
|
||||||
args = pa_sprintf_malloc("%s profile=\"a2dp_source\" auto_connect=no", args);
|
args = pa_sprintf_malloc("%s profile=\"a2dp_source\" auto_connect=no", args);
|
||||||
|
|
||||||
|
if (d->hfgw_state > PA_BT_AUDIO_STATE_CONNECTED)
|
||||||
|
args = pa_sprintf_malloc("%s profile=\"hfgw\"", args);
|
||||||
|
|
||||||
pa_log_debug("Loading module-bluetooth-device %s", args);
|
pa_log_debug("Loading module-bluetooth-device %s", args);
|
||||||
m = pa_module_load(u->module->core, "module-bluetooth-device", args);
|
m = pa_module_load(u->module->core, "module-bluetooth-device", args);
|
||||||
pa_xfree(args);
|
pa_xfree(args);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue