mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez5: support LC3-SWB in HFP RFCOMM & add codec id for it
HFP 1.9 adds LC3 as a possible codec in addition to CVSD & mSBC. E.g. Pixel Buds Pro latest firmware supports it. Add the RFCOMM side and codec selection for it.
This commit is contained in:
parent
237d282c05
commit
fe412784a4
6 changed files with 130 additions and 53 deletions
|
|
@ -39,6 +39,7 @@ enum spa_bluetooth_audio_codec {
|
|||
/* HFP */
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_CVSD = 0x100,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_MSBC,
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_LC3_SWB,
|
||||
|
||||
/* BAP */
|
||||
SPA_BLUETOOTH_AUDIO_CODEC_LC3 = 0x200,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ static const struct spa_type_info spa_type_bluetooth_audio_codec[] = {
|
|||
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_CVSD, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "cvsd", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_MSBC, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "msbc", NULL },
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_LC3_SWB, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "lc3_swb", NULL },
|
||||
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_LC3, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "lc3", NULL },
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ if get_option('spa-plugins').allowed()
|
|||
mm_dep = dependency('ModemManager', version : '>= 1.10.0', required : get_option('bluez5-backend-native-mm'))
|
||||
summary({'ModemManager': mm_dep.found()}, bool_yn: true, section: 'Bluetooth backends')
|
||||
endif
|
||||
cdata.set('HAVE_LC3', get_option('bluez5-codec-lc3').allowed() and lc3_dep.found())
|
||||
endif
|
||||
jack_dep = dependency('jack', version : '>= 1.9.10', required: get_option('jack'))
|
||||
summary({'JACK2': jack_dep.found()}, bool_yn: true, section: 'Backend')
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ struct rfcomm {
|
|||
unsigned int slc_configured:1;
|
||||
unsigned int codec_negotiation_supported:1;
|
||||
unsigned int msbc_supported_by_hfp:1;
|
||||
unsigned int lc3_supported_by_hfp:1;
|
||||
unsigned int hfp_ag_switching_codec:1;
|
||||
unsigned int hfp_ag_initial_codec_setup:2;
|
||||
unsigned int cind_call_active:1;
|
||||
|
|
@ -615,28 +616,48 @@ fail:
|
|||
|
||||
#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
|
||||
|
||||
static bool device_supports_required_mSBC_transport_modes(
|
||||
struct impl *backend, struct spa_bt_device *device)
|
||||
static bool device_supports_codec(struct impl *backend, struct spa_bt_device *device, int codec)
|
||||
{
|
||||
int res;
|
||||
bool msbc_ok, msbc_alt1_ok;
|
||||
bool alt6_ok = true, alt1_ok = true;
|
||||
bool msbc_alt6_ok = true, msbc_alt1_ok = true;
|
||||
uint32_t bt_features;
|
||||
|
||||
if (device->adapter == NULL)
|
||||
return false;
|
||||
|
||||
if (backend->quirks && spa_bt_quirks_get_features(backend->quirks, device->adapter, device, &bt_features) == 0) {
|
||||
msbc_ok = bt_features & SPA_BT_FEATURE_MSBC;
|
||||
msbc_alt1_ok = bt_features & (SPA_BT_FEATURE_MSBC_ALT1 | SPA_BT_FEATURE_MSBC_ALT1_RTL);
|
||||
} else {
|
||||
msbc_ok = true;
|
||||
msbc_alt1_ok = true;
|
||||
msbc_alt1_ok = (bt_features & (SPA_BT_FEATURE_MSBC_ALT1 | SPA_BT_FEATURE_MSBC_ALT1_RTL));
|
||||
msbc_alt6_ok = (bt_features & SPA_BT_FEATURE_MSBC);
|
||||
}
|
||||
|
||||
switch (codec) {
|
||||
case HFP_AUDIO_CODEC_CVSD:
|
||||
return true;
|
||||
case HFP_AUDIO_CODEC_MSBC:
|
||||
alt1_ok = msbc_alt1_ok;
|
||||
alt6_ok = msbc_alt6_ok;
|
||||
break;
|
||||
case HFP_AUDIO_CODEC_LC3:
|
||||
#ifdef HAVE_LC3
|
||||
/* LC3-SWB has same transport requirements as msbc.
|
||||
* However, ALT1/ALT5 modes don't appear to work, seem
|
||||
* to lose frame sync so output is garbled.
|
||||
*/
|
||||
alt1_ok = false;
|
||||
alt6_ok = msbc_alt6_ok;
|
||||
break;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
spa_log_info(backend->log,
|
||||
"bluez-monitor/hardware.conf: msbc:%d msbc-alt1:%d", (int)msbc_ok, (int)msbc_alt1_ok);
|
||||
"bluez-monitor/hardware.conf: alt6:%d alt1/5:%d", (int)alt6_ok, (int)alt1_ok);
|
||||
|
||||
if (!msbc_ok && !msbc_alt1_ok)
|
||||
if (!alt6_ok && !alt1_ok)
|
||||
return false;
|
||||
|
||||
res = spa_bt_adapter_has_msbc(device->adapter);
|
||||
|
|
@ -656,26 +677,26 @@ static bool device_supports_required_mSBC_transport_modes(
|
|||
}
|
||||
|
||||
/* Check if USB ALT6 is really available on the device */
|
||||
if (device->adapter->bus_type == BUS_TYPE_USB && !msbc_alt1_ok && msbc_ok) {
|
||||
if (device->adapter->bus_type == BUS_TYPE_USB && !alt1_ok && alt6_ok) {
|
||||
#ifdef HAVE_LIBUSB
|
||||
if (device->adapter->source_id == SOURCE_ID_USB) {
|
||||
msbc_ok = check_usb_altsetting_6(backend, device->adapter->vendor_id,
|
||||
alt6_ok = check_usb_altsetting_6(backend, device->adapter->vendor_id,
|
||||
device->adapter->product_id);
|
||||
} else {
|
||||
msbc_ok = false;
|
||||
alt6_ok = false;
|
||||
}
|
||||
if (!msbc_ok)
|
||||
if (!alt6_ok)
|
||||
spa_log_info(backend->log, "bluetooth host adapter does not support USB ALT6");
|
||||
#else
|
||||
spa_log_info(backend->log,
|
||||
"compiled without libusb; can't check if bluetooth adapter has USB ALT6");
|
||||
msbc_ok = false;
|
||||
"compiled without libusb; can't check if bluetooth adapter has USB ALT6, assuming no");
|
||||
alt6_ok = false;
|
||||
#endif
|
||||
}
|
||||
if (device->adapter->bus_type != BUS_TYPE_USB)
|
||||
msbc_alt1_ok = false;
|
||||
alt1_ok = false;
|
||||
|
||||
return msbc_ok || msbc_alt1_ok;
|
||||
return alt6_ok || alt1_ok;
|
||||
}
|
||||
|
||||
static int codec_switch_start_timer(struct rfcomm *rfcomm, int timeout_msec);
|
||||
|
|
@ -779,6 +800,8 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
|||
|
||||
if (sscanf(buf, "AT+BRSF=%u", &features) == 1) {
|
||||
unsigned int ag_features = SPA_BT_HFP_AG_FEATURE_NONE;
|
||||
bool codecs = device_supports_codec(backend, rfcomm->device, HFP_AUDIO_CODEC_MSBC) ||
|
||||
device_supports_codec(backend, rfcomm->device, HFP_AUDIO_CODEC_LC3);
|
||||
|
||||
/*
|
||||
* Determine device volume control. Some headsets only support control of
|
||||
|
|
@ -787,10 +810,9 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
|||
*/
|
||||
rfcomm->has_volume = (features & SPA_BT_HFP_HF_FEATURE_REMOTE_VOLUME_CONTROL);
|
||||
|
||||
/* Decide if we want to signal that the computer supports mSBC negotiation
|
||||
/* Decide if we want to signal that the computer supports codec negotiation
|
||||
This should be done when the computers bluetooth adapter supports the necessary transport mode */
|
||||
if (device_supports_required_mSBC_transport_modes(backend, rfcomm->device)) {
|
||||
|
||||
if (codecs) {
|
||||
/* set the feature bit that indicates AG (=computer) supports codec negotiation */
|
||||
ag_features |= SPA_BT_HFP_AG_FEATURE_CODEC_NEGOTIATION;
|
||||
|
||||
|
|
@ -802,6 +824,7 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
|||
/* Prepare reply: Audio Gateway (=computer) supports codec negotiation */
|
||||
rfcomm->codec_negotiation_supported = true;
|
||||
rfcomm->msbc_supported_by_hfp = false;
|
||||
rfcomm->lc3_supported_by_hfp = false;
|
||||
} else {
|
||||
/* Codec negotiation not supported */
|
||||
spa_log_debug(backend->log,
|
||||
|
|
@ -810,6 +833,7 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
|||
|
||||
rfcomm->codec_negotiation_supported = false;
|
||||
rfcomm->msbc_supported_by_hfp = false;
|
||||
rfcomm->lc3_supported_by_hfp = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -832,14 +856,22 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
|||
/* skip token 0 i.e. the "AT+BAC=" part */
|
||||
if (cntr > 0 && sscanf(token, "%u", &codec_id) == 1) {
|
||||
spa_log_debug(backend->log, "RFCOMM AT+BAC found codec %u", codec_id);
|
||||
if (codec_id == HFP_AUDIO_CODEC_MSBC) {
|
||||
rfcomm->msbc_supported_by_hfp = true;
|
||||
spa_log_debug(backend->log, "RFCOMM headset supports mSBC codec");
|
||||
}
|
||||
|
||||
if (codec_id == HFP_AUDIO_CODEC_MSBC)
|
||||
rfcomm->msbc_supported_by_hfp =
|
||||
device_supports_codec(backend, rfcomm->device, HFP_AUDIO_CODEC_MSBC);
|
||||
else if (codec_id == HFP_AUDIO_CODEC_LC3)
|
||||
rfcomm->lc3_supported_by_hfp =
|
||||
device_supports_codec(backend, rfcomm->device, HFP_AUDIO_CODEC_LC3);
|
||||
}
|
||||
cntr++;
|
||||
}
|
||||
|
||||
if (rfcomm->msbc_supported_by_hfp)
|
||||
spa_log_debug(backend->log, "mSBC codec is supported");
|
||||
if (rfcomm->lc3_supported_by_hfp)
|
||||
spa_log_debug(backend->log, "LC3 codec is supported");
|
||||
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else if (spa_strstartswith(buf, "AT+CIND=?")) {
|
||||
rfcomm_send_reply(rfcomm, "+CIND:%s", CIND_INDICATORS);
|
||||
|
|
@ -851,6 +883,7 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
|||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else if (spa_strstartswith(buf, "AT+CMER")) {
|
||||
int mode, keyp, disp, ind;
|
||||
bool have_codecs = rfcomm->msbc_supported_by_hfp || rfcomm->lc3_supported_by_hfp;
|
||||
|
||||
rfcomm->slc_configured = true;
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
|
|
@ -862,10 +895,13 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
|||
rfcomm->cind_call_notify = false;
|
||||
|
||||
/* switch codec to mSBC by sending unsolicited +BCS message */
|
||||
if (rfcomm->codec_negotiation_supported && rfcomm->msbc_supported_by_hfp) {
|
||||
if (rfcomm->codec_negotiation_supported && have_codecs) {
|
||||
spa_log_debug(backend->log, "RFCOMM initial codec setup");
|
||||
rfcomm->hfp_ag_initial_codec_setup = HFP_AG_INITIAL_CODEC_SETUP_SEND;
|
||||
rfcomm_send_reply(rfcomm, "+BCS: 2");
|
||||
if (rfcomm->lc3_supported_by_hfp)
|
||||
rfcomm_send_reply(rfcomm, "+BCS: 3");
|
||||
else
|
||||
rfcomm_send_reply(rfcomm, "+BCS: 2");
|
||||
codec_switch_start_timer(rfcomm, HFP_CODEC_SWITCH_INITIAL_TIMEOUT_MSEC);
|
||||
} else {
|
||||
rfcomm->transport = _transport_create(rfcomm);
|
||||
|
|
@ -898,7 +934,8 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
|||
codec_switch_stop_timer(rfcomm);
|
||||
volume_sync_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 &&
|
||||
selected_codec != HFP_AUDIO_CODEC_LC3) {
|
||||
spa_log_warn(backend->log, "unsupported codec negotiation: %d", selected_codec);
|
||||
rfcomm_send_error(rfcomm, CMEE_AG_FAILURE);
|
||||
if (was_switching_codec)
|
||||
|
|
@ -1179,10 +1216,11 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
|
|||
|
||||
if (sscanf(token, "+BRSF:%u", &features) == 1) {
|
||||
if (((features & (SPA_BT_HFP_AG_FEATURE_CODEC_NEGOTIATION)) != 0) &&
|
||||
rfcomm->msbc_supported_by_hfp)
|
||||
(rfcomm->msbc_supported_by_hfp || rfcomm->lc3_supported_by_hfp))
|
||||
rfcomm->codec_negotiation_supported = true;
|
||||
} else if (sscanf(token, "+BCS:%u", &selected_codec) == 1 && rfcomm->codec_negotiation_supported) {
|
||||
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 &&
|
||||
selected_codec != HFP_AUDIO_CODEC_LC3) {
|
||||
spa_log_warn(backend->log, "unsupported codec negotiation: %d", selected_codec);
|
||||
} else {
|
||||
spa_log_debug(backend->log, "RFCOMM selected_codec = %i", selected_codec);
|
||||
|
|
@ -1263,7 +1301,17 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
|
|||
switch(rfcomm->hf_state) {
|
||||
case hfp_hf_brsf:
|
||||
if (rfcomm->codec_negotiation_supported) {
|
||||
rfcomm_send_cmd(rfcomm, "AT+BAC=1,2");
|
||||
char buf[64];
|
||||
struct spa_strbuf str;
|
||||
|
||||
spa_strbuf_init(&str, buf, sizeof(buf));
|
||||
spa_strbuf_append(&str, "1");
|
||||
if (rfcomm->msbc_supported_by_hfp)
|
||||
spa_strbuf_append(&str, ",2");
|
||||
if (rfcomm->lc3_supported_by_hfp)
|
||||
spa_strbuf_append(&str, ",3");
|
||||
|
||||
rfcomm_send_cmd(rfcomm, "AT+BAC=%s", buf);
|
||||
rfcomm->hf_state = hfp_hf_bac;
|
||||
} else {
|
||||
rfcomm_send_cmd(rfcomm, "AT+CIND=?");
|
||||
|
|
@ -1395,7 +1443,7 @@ static void rfcomm_event(struct spa_source *source)
|
|||
}
|
||||
}
|
||||
|
||||
static int sco_create_socket(struct impl *backend, struct spa_bt_adapter *adapter, bool msbc)
|
||||
static int sco_create_socket(struct impl *backend, struct spa_bt_adapter *adapter, bool transparent)
|
||||
{
|
||||
struct sockaddr_sco addr;
|
||||
socklen_t len;
|
||||
|
|
@ -1419,9 +1467,9 @@ static int sco_create_socket(struct impl *backend, struct spa_bt_adapter *adapte
|
|||
return -1;
|
||||
}
|
||||
|
||||
spa_log_debug(backend->log, "msbc=%d", (int)msbc);
|
||||
if (msbc) {
|
||||
/* set correct socket options for mSBC */
|
||||
spa_log_debug(backend->log, "transparent=%d", (int)transparent);
|
||||
if (transparent) {
|
||||
/* set correct socket options for mSBC/LC3 */
|
||||
struct bt_voice voice_config;
|
||||
memset(&voice_config, 0, sizeof(voice_config));
|
||||
voice_config.setting = BT_VOICE_TRANSPARENT;
|
||||
|
|
@ -1455,7 +1503,8 @@ static int sco_do_connect(struct spa_bt_transport *t)
|
|||
str2ba(d->address, &addr.sco_bdaddr);
|
||||
|
||||
for (int retry = 2;;) {
|
||||
spa_autoclose int sock = sco_create_socket(backend, d->adapter, (t->codec == HFP_AUDIO_CODEC_MSBC));
|
||||
bool transparent = (t->codec == HFP_AUDIO_CODEC_MSBC || t->codec == HFP_AUDIO_CODEC_LC3);
|
||||
spa_autoclose int sock = sco_create_socket(backend, d->adapter, transparent);
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
|
||||
|
|
@ -1468,12 +1517,13 @@ static int sco_do_connect(struct spa_bt_transport *t)
|
|||
} else if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
|
||||
spa_log_error(backend->log, "connect(): %s", strerror(errno));
|
||||
#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
|
||||
if (errno == EOPNOTSUPP && t->codec == HFP_AUDIO_CODEC_MSBC &&
|
||||
td->rfcomm->msbc_supported_by_hfp) {
|
||||
/* Adapter doesn't support msbc. Renegotiate. */
|
||||
if (errno == EOPNOTSUPP && t->codec != HFP_AUDIO_CODEC_CVSD &&
|
||||
td->rfcomm->codec_negotiation_supported) {
|
||||
/* Adapter doesn't support msbc/lc3. Renegotiate. */
|
||||
d->adapter->msbc_probed = true;
|
||||
d->adapter->has_msbc = false;
|
||||
td->rfcomm->msbc_supported_by_hfp = false;
|
||||
td->rfcomm->lc3_supported_by_hfp = false;
|
||||
if (t->profile == SPA_BT_PROFILE_HFP_HF) {
|
||||
td->rfcomm->hfp_ag_switching_codec = true;
|
||||
rfcomm_send_reply(td->rfcomm, "+BCS: 1");
|
||||
|
|
@ -1784,8 +1834,8 @@ static void sco_listen_event(struct spa_source *source)
|
|||
* accepted socket. */
|
||||
char buff;
|
||||
|
||||
if (t->codec == HFP_AUDIO_CODEC_MSBC) {
|
||||
/* set correct socket options for mSBC */
|
||||
if (t->codec == HFP_AUDIO_CODEC_MSBC || t->codec == HFP_AUDIO_CODEC_LC3) {
|
||||
/* set correct socket options for mSBC/LC3 */
|
||||
struct bt_voice voice_config;
|
||||
memset(&voice_config, 0, sizeof(voice_config));
|
||||
voice_config.setting = BT_VOICE_TRANSPARENT;
|
||||
|
|
@ -1956,11 +2006,19 @@ static int backend_native_supports_codec(void *data, struct spa_bt_device *devic
|
|||
if (codec == HFP_AUDIO_CODEC_CVSD)
|
||||
return 1;
|
||||
|
||||
return (codec == HFP_AUDIO_CODEC_MSBC &&
|
||||
(rfcomm->profile == SPA_BT_PROFILE_HFP_AG ||
|
||||
rfcomm->profile == SPA_BT_PROFILE_HFP_HF) &&
|
||||
rfcomm->msbc_supported_by_hfp &&
|
||||
rfcomm->codec_negotiation_supported) ? 1 : 0;
|
||||
if (rfcomm->profile != SPA_BT_PROFILE_HFP_AG &&
|
||||
rfcomm->profile != SPA_BT_PROFILE_HFP_HF)
|
||||
return 0;
|
||||
|
||||
if (!rfcomm->codec_negotiation_supported)
|
||||
return 0;
|
||||
|
||||
if (codec == HFP_AUDIO_CODEC_MSBC)
|
||||
return rfcomm->msbc_supported_by_hfp;
|
||||
else if (codec == HFP_AUDIO_CODEC_LC3)
|
||||
return rfcomm->lc3_supported_by_hfp;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
|
|
@ -2261,16 +2319,20 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
|||
} else if (profile == SPA_BT_PROFILE_HFP_AG) {
|
||||
/* Start SLC connection */
|
||||
unsigned int hf_features = SPA_BT_HFP_HF_FEATURE_NONE;
|
||||
bool has_msbc = device_supports_codec(backend, rfcomm->device, HFP_AUDIO_CODEC_MSBC);
|
||||
bool has_lc3 = device_supports_codec(backend, rfcomm->device, HFP_AUDIO_CODEC_LC3);
|
||||
|
||||
/* Decide if we want to signal that the HF supports mSBC negotiation
|
||||
/* Decide if we want to signal that the HF supports mSBC/LC3 negotiation
|
||||
This should be done when the bluetooth adapter supports the necessary transport mode */
|
||||
if (device_supports_required_mSBC_transport_modes(backend, rfcomm->device)) {
|
||||
if (has_msbc || has_lc3) {
|
||||
/* set the feature bit that indicates HF supports codec negotiation */
|
||||
hf_features |= SPA_BT_HFP_HF_FEATURE_CODEC_NEGOTIATION;
|
||||
rfcomm->msbc_supported_by_hfp = true;
|
||||
rfcomm->msbc_supported_by_hfp = has_msbc;
|
||||
rfcomm->lc3_supported_by_hfp = has_lc3;
|
||||
rfcomm->codec_negotiation_supported = false;
|
||||
} else {
|
||||
rfcomm->msbc_supported_by_hfp = false;
|
||||
rfcomm->lc3_supported_by_hfp = false;
|
||||
rfcomm->codec_negotiation_supported = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -247,6 +247,8 @@ static unsigned int get_hfp_codec(enum spa_bluetooth_audio_codec id)
|
|||
return HFP_AUDIO_CODEC_CVSD;
|
||||
case SPA_BLUETOOTH_AUDIO_CODEC_MSBC:
|
||||
return HFP_AUDIO_CODEC_MSBC;
|
||||
case SPA_BLUETOOTH_AUDIO_CODEC_LC3_SWB:
|
||||
return HFP_AUDIO_CODEC_LC3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -257,6 +259,8 @@ static enum spa_bluetooth_audio_codec get_hfp_codec_id(unsigned int codec)
|
|||
switch (codec) {
|
||||
case HFP_AUDIO_CODEC_MSBC:
|
||||
return SPA_BLUETOOTH_AUDIO_CODEC_MSBC;
|
||||
case HFP_AUDIO_CODEC_LC3:
|
||||
return SPA_BLUETOOTH_AUDIO_CODEC_LC3_SWB;
|
||||
case HFP_AUDIO_CODEC_CVSD:
|
||||
return SPA_BLUETOOTH_AUDIO_CODEC_CVSD;
|
||||
}
|
||||
|
|
@ -268,6 +272,8 @@ static const char *get_hfp_codec_description(unsigned int codec)
|
|||
switch (codec) {
|
||||
case HFP_AUDIO_CODEC_MSBC:
|
||||
return "mSBC";
|
||||
case HFP_AUDIO_CODEC_LC3:
|
||||
return "LC3-SWB";
|
||||
case HFP_AUDIO_CODEC_CVSD:
|
||||
return "CVSD";
|
||||
}
|
||||
|
|
@ -279,6 +285,8 @@ static const char *get_hfp_codec_name(unsigned int codec)
|
|||
switch (codec) {
|
||||
case HFP_AUDIO_CODEC_MSBC:
|
||||
return "msbc";
|
||||
case HFP_AUDIO_CODEC_LC3:
|
||||
return "lc3_swb";
|
||||
case HFP_AUDIO_CODEC_CVSD:
|
||||
return "cvsd";
|
||||
}
|
||||
|
|
@ -1900,7 +1908,7 @@ static struct spa_pod *build_profile(struct impl *this, struct spa_pod_builder *
|
|||
desc_and_codec = spa_aprintf(_("Headset Head Unit (HSP/HFP, codec %s)"),
|
||||
get_hfp_codec_description(hfp_codec));
|
||||
desc = desc_and_codec;
|
||||
priority = 1 + hfp_codec; /* prefer msbc over cvsd */
|
||||
priority = 1 + hfp_codec; /* prefer lc3_swb > msbc > cvsd */
|
||||
} else {
|
||||
desc = _("Headset Head Unit (HSP/HFP)");
|
||||
priority = 1;
|
||||
|
|
@ -2256,7 +2264,7 @@ static struct spa_pod *build_prop_info_codec(struct impl *this, struct spa_pod_b
|
|||
#define FOR_EACH_MEDIA_CODEC(j, codec) \
|
||||
for (j = -1; iterate_supported_media_codecs(this, &j, &codec);)
|
||||
#define FOR_EACH_HFP_CODEC(j) \
|
||||
for (j = HFP_AUDIO_CODEC_MSBC; j >= HFP_AUDIO_CODEC_CVSD; --j) \
|
||||
for (j = HFP_AUDIO_CODEC_LC3; j >= HFP_AUDIO_CODEC_CVSD; --j) \
|
||||
if (spa_bt_device_supports_hfp_codec(this->bt_dev, j) == 1)
|
||||
|
||||
spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_PropInfo, id);
|
||||
|
|
@ -2739,6 +2747,9 @@ static int impl_set_param(void *object,
|
|||
} else if (codec_id == SPA_BLUETOOTH_AUDIO_CODEC_MSBC &&
|
||||
spa_bt_device_supports_hfp_codec(this->bt_dev, HFP_AUDIO_CODEC_MSBC) == 1) {
|
||||
return set_profile(this, this->profile, codec_id, true);
|
||||
} else if (codec_id == SPA_BLUETOOTH_AUDIO_CODEC_LC3_SWB &&
|
||||
spa_bt_device_supports_hfp_codec(this->bt_dev, HFP_AUDIO_CODEC_LC3) == 1) {
|
||||
return set_profile(this, this->profile, codec_id, true);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -141,8 +141,9 @@ extern "C" {
|
|||
#define BUS_TYPE_USB 1
|
||||
#define BUS_TYPE_OTHER 255
|
||||
|
||||
#define HFP_AUDIO_CODEC_CVSD 0x01
|
||||
#define HFP_AUDIO_CODEC_MSBC 0x02
|
||||
#define HFP_AUDIO_CODEC_CVSD 0x01
|
||||
#define HFP_AUDIO_CODEC_MSBC 0x02
|
||||
#define HFP_AUDIO_CODEC_LC3 0x03
|
||||
|
||||
#define A2DP_OBJECT_MANAGER_PATH "/MediaEndpoint"
|
||||
#define A2DP_SINK_ENDPOINT A2DP_OBJECT_MANAGER_PATH "/A2DPSink"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue