diff options
Diffstat (limited to 'cras/src/server/cras_hfp_slc.c')
-rw-r--r-- | cras/src/server/cras_hfp_slc.c | 101 |
1 files changed, 90 insertions, 11 deletions
diff --git a/cras/src/server/cras_hfp_slc.c b/cras/src/server/cras_hfp_slc.c index e4f0127d..28f73edc 100644 --- a/cras/src/server/cras_hfp_slc.c +++ b/cras/src/server/cras_hfp_slc.c @@ -441,12 +441,10 @@ static int available_codecs(struct hfp_slc_handle *handle, const char *cmd) id_str = strtok(NULL, ","); } - for (id = HFP_MAX_CODECS - 1; id > 0; id--) { - if (handle->hf_codec_supported[id]) { - handle->preferred_codec = id; - break; - } - } + if (hfp_slc_get_wideband_speech_supported(handle)) + handle->preferred_codec = HFP_CODEC_ID_MSBC; + else + handle->preferred_codec = HFP_CODEC_ID_CVSD; free(tokens); return hfp_send(handle, AT_CMD("OK")); @@ -609,6 +607,26 @@ static int operator_selection(struct hfp_slc_handle *handle, const char *buf) return hfp_send(handle, AT_CMD("OK")); } +/* The AT+CHLD command is used to control call hold, release, and multiparty + * states. + */ +static int call_hold(struct hfp_slc_handle *handle, const char *buf) +{ + int rc; + + // Chrome OS doesn't yet support CHLD features but we need to reply + // the query with an empty feature list rather than "ERROR" to increase + // interoperability with certain devices (b/172413440). + if (strlen(buf) > 8 && buf[7] == '=' && buf[8] == '?') { + rc = hfp_send(handle, AT_CMD("+CHLD:")); + if (rc) + return rc; + return hfp_send(handle, AT_CMD("OK")); + } + + return hfp_send(handle, AT_CMD("ERROR")); +} + /* AT+CIND command retrieves the supported indicator and its corresponding * range and order index or read current status of indicators. Mandatory * support per spec 4.2. @@ -938,6 +956,70 @@ static int terminate_call(struct hfp_slc_handle *handle, const char *cmd) return cras_telephony_event_terminate_call(); } +/* AT+XEVENT is defined by Android to support vendor specific features. + * Currently, the only known supported case for CrOS is the battery event sent + * by some Plantronics headsets. + */ +static int vendor_specific_features(struct hfp_slc_handle *handle, + const char *cmd) +{ + char *tokens, *event, *level_str, *num_of_level_str; + int level, num_of_level; + + tokens = strdup(cmd); + strtok(tokens, "="); + event = strtok(NULL, ","); + if (!event) + goto error_out; + + /* AT+XEVENT=BATTERY,Level,NumberOfLevel,MinutesOfTalkTime,IsCharging + * Level: The charge level with a zero-based integer. + * NumberOfLevel: How many charging levels there are. + * MinuteOfTalkTime: The estimated number of talk minutes remaining. + * IsCharging: A 0 or 1 value. + * + * We only support the battery level and thus only care about the first + * 3 arguments. + */ + if (!strncmp(event, "BATTERY", 7)) { + level_str = strtok(NULL, ","); + num_of_level_str = strtok(NULL, ","); + if (!level_str || !num_of_level_str) + goto error_out; + + level = atoi(level_str); + num_of_level = atoi(num_of_level_str); + if (level < 0 || num_of_level <= 1 || level >= num_of_level) + goto error_out; + + level = (int64_t)level * 100 / (num_of_level - 1); + if (handle->hf_battery != level) { + handle->hf_supports_battery_indicator |= + CRAS_HFP_BATTERY_INDICATOR_PLANTRONICS; + cras_server_metrics_hfp_battery_report( + CRAS_HFP_BATTERY_INDICATOR_PLANTRONICS); + handle->hf_battery = level; + cras_observer_notify_bt_battery_changed( + cras_bt_device_address(handle->device), + (uint32_t)(level)); + } + } + + free(tokens); + /* For Plantronic headsets, it is required to reply "OK" for the first + * AT+XEVENT=USER-AGENT... command to tell the headset our support of + * the xevent protocol. Otherwise, all following events including + * BATTERY won't be sent. + */ + return hfp_send(handle, AT_CMD("OK")); + +error_out: + syslog(LOG_ERR, "%s: malformed vendor specific command: '%s'", __func__, + cmd); + free(tokens); + return hfp_send(handle, AT_CMD("ERROR")); +} + /* AT commands to support in order to conform HFP specification. * * An initialized service level connection is the pre-condition for all @@ -999,6 +1081,8 @@ static struct at_command at_commands[] = { { "AT+VG", signal_gain_setting }, { "AT+VTS", dtmf_tone }, { "AT+XAPL", apple_supported_features }, + { "AT+XEVENT", vendor_specific_features }, + { "AT+CHLD", call_hold }, { 0 } }; @@ -1314,8 +1398,3 @@ int hfp_slc_get_hf_supports_battery_indicator(struct hfp_slc_handle *handle) { return handle->hf_supports_battery_indicator; } - -int hfp_slc_get_hf_battery_level(struct hfp_slc_handle *handle) -{ - return handle->hf_battery; -} |