mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
bluez5: retry initial HFP codec selection after a timeout
In case headset fails to reply with AT+BCS to the codec selection following AT+CMER, try to retry the codec selection, and if it still fails, assume the headset is configured for CVSD.
This commit is contained in:
parent
87e06783d1
commit
277a9a2577
1 changed files with 40 additions and 2 deletions
|
|
@ -47,8 +47,15 @@
|
||||||
|
|
||||||
#define PROP_KEY_HEADSET_ROLES "bluez5.headset-roles"
|
#define PROP_KEY_HEADSET_ROLES "bluez5.headset-roles"
|
||||||
|
|
||||||
|
#define HFP_CODEC_SWITCH_INITIAL_TIMEOUT_MSEC 2000
|
||||||
#define HFP_CODEC_SWITCH_TIMEOUT_MSEC 5000
|
#define HFP_CODEC_SWITCH_TIMEOUT_MSEC 5000
|
||||||
|
|
||||||
|
enum {
|
||||||
|
HFP_AG_INITIAL_CODEC_SETUP_NONE = 0,
|
||||||
|
HFP_AG_INITIAL_CODEC_SETUP_SEND,
|
||||||
|
HFP_AG_INITIAL_CODEC_SETUP_WAIT
|
||||||
|
};
|
||||||
|
|
||||||
struct impl {
|
struct impl {
|
||||||
struct spa_bt_backend this;
|
struct spa_bt_backend this;
|
||||||
|
|
||||||
|
|
@ -100,6 +107,7 @@ struct rfcomm {
|
||||||
unsigned int msbc_support_enabled_in_config:1;
|
unsigned int msbc_support_enabled_in_config:1;
|
||||||
unsigned int msbc_supported_by_hfp:1;
|
unsigned int msbc_supported_by_hfp:1;
|
||||||
unsigned int hfp_ag_switching_codec:1;
|
unsigned int hfp_ag_switching_codec:1;
|
||||||
|
unsigned int hfp_ag_initial_codec_setup:2;
|
||||||
enum hfp_hf_state hf_state;
|
enum hfp_hf_state hf_state;
|
||||||
unsigned int codec;
|
unsigned int codec;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -343,6 +351,8 @@ static bool device_supports_required_mSBC_transport_modes(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int codec_switch_start_timer(struct rfcomm *rfcomm, int timeout_msec);
|
||||||
|
|
||||||
static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
||||||
{
|
{
|
||||||
struct rfcomm *rfcomm = source->data;
|
struct rfcomm *rfcomm = source->data;
|
||||||
|
|
@ -429,8 +439,10 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
||||||
|
|
||||||
/* switch codec to mSBC by sending unsolicited +BCS message */
|
/* switch codec to mSBC by sending unsolicited +BCS message */
|
||||||
if (rfcomm->codec_negotiation_supported && rfcomm->msbc_supported_by_hfp) {
|
if (rfcomm->codec_negotiation_supported && rfcomm->msbc_supported_by_hfp) {
|
||||||
spa_log_debug(backend->log, NAME": RFCOMM switching codec to mSBC");
|
spa_log_debug(backend->log, NAME": RFCOMM initial codec setup");
|
||||||
rfcomm_send_reply(source, "+BCS: 2");
|
rfcomm->hfp_ag_initial_codec_setup = HFP_AG_INITIAL_CODEC_SETUP_SEND;
|
||||||
|
rfcomm_send_reply(&rfcomm->source, "+BCS: 2");
|
||||||
|
codec_switch_start_timer(rfcomm, HFP_CODEC_SWITCH_INITIAL_TIMEOUT_MSEC);
|
||||||
} else {
|
} else {
|
||||||
rfcomm->transport = _transport_create(rfcomm);
|
rfcomm->transport = _transport_create(rfcomm);
|
||||||
if (rfcomm->transport == NULL) {
|
if (rfcomm->transport == NULL) {
|
||||||
|
|
@ -450,6 +462,7 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
||||||
/* parse BCS(=Bluetooth Codec Selection) reply */
|
/* parse BCS(=Bluetooth Codec Selection) reply */
|
||||||
bool was_switching_codec = rfcomm->hfp_ag_switching_codec && (rfcomm->device != NULL);
|
bool was_switching_codec = rfcomm->hfp_ag_switching_codec && (rfcomm->device != NULL);
|
||||||
rfcomm->hfp_ag_switching_codec = false;
|
rfcomm->hfp_ag_switching_codec = false;
|
||||||
|
rfcomm->hfp_ag_initial_codec_setup = HFP_AG_INITIAL_CODEC_SETUP_NONE;
|
||||||
codec_switch_stop_timer(rfcomm);
|
codec_switch_stop_timer(rfcomm);
|
||||||
|
|
||||||
if (selected_codec != HFP_AUDIO_CODEC_CVSD && selected_codec != HFP_AUDIO_CODEC_MSBC) {
|
if (selected_codec != HFP_AUDIO_CODEC_CVSD && selected_codec != HFP_AUDIO_CODEC_MSBC) {
|
||||||
|
|
@ -1102,6 +1115,31 @@ static void codec_switch_timer_event(struct spa_source *source)
|
||||||
|
|
||||||
spa_log_debug(backend->log, "rfcomm %p: codec switch timeout", rfcomm);
|
spa_log_debug(backend->log, "rfcomm %p: codec switch timeout", rfcomm);
|
||||||
|
|
||||||
|
switch (rfcomm->hfp_ag_initial_codec_setup) {
|
||||||
|
case HFP_AG_INITIAL_CODEC_SETUP_SEND:
|
||||||
|
/* Retry codec selection */
|
||||||
|
rfcomm->hfp_ag_initial_codec_setup = HFP_AG_INITIAL_CODEC_SETUP_WAIT;
|
||||||
|
rfcomm_send_reply(&rfcomm->source, "+BCS: 2");
|
||||||
|
codec_switch_start_timer(rfcomm, HFP_CODEC_SWITCH_TIMEOUT_MSEC);
|
||||||
|
return;
|
||||||
|
case HFP_AG_INITIAL_CODEC_SETUP_WAIT:
|
||||||
|
/* Failure, try falling back to CVSD. */
|
||||||
|
rfcomm->hfp_ag_initial_codec_setup = HFP_AG_INITIAL_CODEC_SETUP_NONE;
|
||||||
|
if (rfcomm->transport == NULL) {
|
||||||
|
rfcomm->transport = _transport_create(rfcomm);
|
||||||
|
if (rfcomm->transport == NULL) {
|
||||||
|
spa_log_warn(backend->log, NAME": can't create transport: %m");
|
||||||
|
} else {
|
||||||
|
rfcomm->transport->codec = HFP_AUDIO_CODEC_CVSD;
|
||||||
|
spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rfcomm_send_reply(&rfcomm->source, "+BCS: 1");
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (rfcomm->hfp_ag_switching_codec) {
|
if (rfcomm->hfp_ag_switching_codec) {
|
||||||
rfcomm->hfp_ag_switching_codec = false;
|
rfcomm->hfp_ag_switching_codec = false;
|
||||||
if (rfcomm->device)
|
if (rfcomm->device)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue