Loading hal/audio_extn/a2dp.c +259 −39 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ #define MEDIA_FMT_LDAC 0x00013224 #define MEDIA_FMT_MP3 0x00010BE9 #define MEDIA_FMT_APTX_ADAPTIVE 0x00013204 #define MEDIA_FMT_APTX_AD_SPEECH 0x00013208 #define MEDIA_FMT_AAC_AOT_LC 2 #define MEDIA_FMT_AAC_AOT_SBR 5 #define MEDIA_FMT_AAC_AOT_PS 29 Loading @@ -85,6 +86,7 @@ #define MIXER_SAMPLE_RATE_DEFAULT "BT SampleRate" #define MIXER_AFE_IN_CHANNELS "AFE Input Channels" #define MIXER_ABR_TX_FEEDBACK_PATH "A2DP_SLIM7_UL_HL Switch" #define MIXER_ABR_RX_FEEDBACK_PATH "SCO_SLIM7_DL_HL Switch" #define MIXER_SET_FEEDBACK_CHANNEL "BT set feedback channel" #define MIXER_SINK_SAMPLE_RATE "BT_TX SampleRate" #define MIXER_AFE_SINK_CHANNELS "AFE Output Channels" Loading Loading @@ -125,6 +127,9 @@ // Slimbus Tx sample rate for ABR feedback channel #define ABR_TX_SAMPLE_RATE "KHZ_8" // Slimbus Tx sample rate for APTX AD SPEECH #define SPEECH_TX_SAMPLE_RATE "KHZ_96" // Purpose ID for Inter Module Communication (IMC) in AFE #define IMC_PURPOSE_ID_BT_INFO 0x000132E2 Loading @@ -134,8 +139,13 @@ // Instance identifier for A2DP #define MAX_INSTANCE_ID (UINT32_MAX / 2) // Instance identifier for SWB #define APTX_AD_SPEECH_INSTANCE_ID 37 #define SAMPLING_RATE_96K 96000 #define SAMPLING_RATE_48K 48000 #define SAMPLING_RATE_441K 44100 #define SAMPLING_RATE_32K 32000 #define CH_STEREO 2 #define CH_MONO 1 #define SOURCE 0 Loading Loading @@ -172,6 +182,7 @@ typedef enum { CODEC_TYPE_LDAC = AUDIO_FORMAT_LDAC, // 0x23000000UL CODEC_TYPE_CELT = 603979776u, // 0x24000000UL CODEC_TYPE_APTX_AD = 620756992u, // 0x25000000UL CODEC_TYPE_APTX_AD_SPEECH = 637534208u, //0x26000000UL CODEC_TYPE_PCM = AUDIO_FORMAT_PCM_16_BIT, // 0x1u }codec_t; Loading Loading @@ -236,6 +247,11 @@ typedef enum { IMC_ENABLE, } imc_status_t; typedef enum { SWAP_DISABLE, SWAP_ENABLE, } swap_status_t; typedef enum { MTU_SIZE, PEAK_BIT_RATE, Loading Loading @@ -265,6 +281,8 @@ struct a2dp_abr_config { bool abr_started; /* ABR Tx path pcm handle */ struct pcm *abr_tx_handle; /* ABR Rx path pcm handle */ struct pcm *abr_rx_handle; /* ABR Inter Module Communication (IMC) instance ID */ uint32_t imc_instance; }; Loading Loading @@ -319,6 +337,7 @@ struct a2dp_data { uint32_t dec_channels; bool a2dp_sink_started; int a2dp_sink_total_active_session_requests; bool swb_configured; }; struct a2dp_data a2dp; Loading Loading @@ -400,6 +419,18 @@ struct abr_dec_cfg_t { struct imc_dec_enc_info imc_info; } __attribute__ ((packed)); struct aptx_ad_speech_mode_cfg_t { uint32_t mode; uint32_t swapping; } __attribute__ ((packed)); /* Structure for SWB voice dec config */ struct aptx_ad_speech_dec_cfg_t { struct abr_dec_cfg_t abr_cfg; struct aptx_ad_speech_mode_cfg_t speech_mode; } __attribute__ ((packed)); /* START of DSP configurable structures * These values should match with DSP interface defintion */ Loading Loading @@ -546,6 +577,15 @@ struct aptx_ad_enc_cfg_t struct abr_enc_cfg_t abr_cfg; } __attribute__ ((packed)); /* APTX AD SPEECH structure */ struct aptx_ad_speech_enc_cfg_t { struct custom_enc_cfg_t custom_cfg; /* Information to set up IMC between decoder and encoder */ struct imc_dec_enc_info imc_info; struct aptx_ad_speech_mode_cfg_t speech_mode; } __attribute__ ((packed)); struct ldac_specific_enc_cfg_t { uint32_t bit_rate; Loading Loading @@ -715,7 +755,9 @@ static void update_offload_codec_capabilities() static int stop_abr() { struct mixer_ctl *ctl_abr_tx_path = NULL; struct mixer_ctl *ctl_abr_rx_path = NULL; struct mixer_ctl *ctl_set_bt_feedback_channel = NULL; int ret = 0; /* This function can be used if !abr_started for clean up */ ALOGV("%s: enter", __func__); Loading @@ -725,6 +767,10 @@ static int stop_abr() pcm_close(a2dp.abr_config.abr_tx_handle); a2dp.abr_config.abr_tx_handle = NULL; } if (a2dp.abr_config.abr_rx_handle != NULL) { pcm_close(a2dp.abr_config.abr_rx_handle); a2dp.abr_config.abr_rx_handle = NULL; } a2dp.abr_config.abr_started = false; a2dp.abr_config.imc_instance = 0; Loading @@ -733,11 +779,10 @@ static int stop_abr() MIXER_SET_FEEDBACK_CHANNEL); if (!ctl_set_bt_feedback_channel) { ALOGE("%s: ERROR Set usecase mixer control not identifed", __func__); return -ENOSYS; } if (mixer_ctl_set_value(ctl_set_bt_feedback_channel, 0, 0) != 0) { ret = -ENOSYS; } else if (mixer_ctl_set_value(ctl_set_bt_feedback_channel, 0, 0) != 0) { ALOGE("%s: Failed to set BT usecase", __func__); return -ENOSYS; ret = -ENOSYS; } // Reset ABR Tx feedback path Loading @@ -746,19 +791,31 @@ static int stop_abr() MIXER_ABR_TX_FEEDBACK_PATH); if (!ctl_abr_tx_path) { ALOGE("%s: ERROR ABR Tx feedback path mixer control not identifed", __func__); return -ENOSYS; } if (mixer_ctl_set_value(ctl_abr_tx_path, 0, 0) != 0) { ret = -ENOSYS; } else if (mixer_ctl_set_value(ctl_abr_tx_path, 0, 0) != 0) { ALOGE("%s: Failed to set ABR Tx feedback path", __func__); return -ENOSYS; ret = -ENOSYS; } return 0; // Reset ABR Rx feedback path ALOGV("%s: Disable ABR Rx feedback path", __func__); ctl_abr_rx_path = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_ABR_RX_FEEDBACK_PATH); if (!ctl_abr_rx_path) { ALOGE("%s: ERROR ABR Rx feedback path mixer control not identifed", __func__); ret = -ENOSYS; } else if (mixer_ctl_set_value(ctl_abr_rx_path, 0, 0) != 0) { ALOGE("%s: Failed to set ABR Rx feedback path", __func__); ret = -ENOSYS; } return ret; } static int start_abr() { struct mixer_ctl *ctl_abr_tx_path = NULL; struct mixer_ctl *ctl_abr_rx_path = NULL; struct mixer_ctl *ctl_set_bt_feedback_channel = NULL; int abr_device_id; int ret = 0; Loading Loading @@ -792,11 +849,11 @@ static int start_abr() MIXER_SET_FEEDBACK_CHANNEL); if (!ctl_set_bt_feedback_channel) { ALOGE("%s: ERROR Set usecase mixer control not identifed", __func__); return -ENOSYS; goto fail; } if (mixer_ctl_set_value(ctl_set_bt_feedback_channel, 0, 1) != 0) { ALOGE("%s: Failed to set BT usecase", __func__); return -ENOSYS; goto fail; } // Open hostless front end and prepare ABR Tx path Loading @@ -806,19 +863,60 @@ static int start_abr() a2dp.abr_config.abr_tx_handle = pcm_open(a2dp.adev->snd_card, abr_device_id, PCM_IN, &pcm_config_abr); if (a2dp.abr_config.abr_tx_handle == NULL || !pcm_is_ready(a2dp.abr_config.abr_tx_handle)) if (a2dp.abr_config.abr_tx_handle == NULL) { ALOGE("%s: Can't open abr tx device", __func__); goto fail; } ret = pcm_start(a2dp.abr_config.abr_tx_handle); if (ret < 0) if (!(pcm_is_ready(a2dp.abr_config.abr_tx_handle) && !pcm_start(a2dp.abr_config.abr_tx_handle))) { ALOGE("%s: tx: %s", __func__, pcm_get_error(a2dp.abr_config.abr_tx_handle)); goto fail; } } // Enable Slimbus 7 Rx feedback path for HD Voice use case if (a2dp.bt_encoder_format == CODEC_TYPE_APTX_AD_SPEECH) { ALOGV("%s: Enable ABR Rx feedback path", __func__); ctl_abr_rx_path = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_ABR_RX_FEEDBACK_PATH); if (!ctl_abr_rx_path) { ALOGE("%s: ERROR ABR Rx feedback path mixer control not identifed", __func__); goto fail; } if (mixer_ctl_set_value(ctl_abr_rx_path, 0, 1) != 0) { ALOGE("%s: Failed to set ABR Rx feedback path", __func__); goto fail; } if (mixer_ctl_set_value(ctl_set_bt_feedback_channel, 0, 1) != 0) { ALOGE("%s: Failed to set BT usecase", __func__); goto fail; } // Open hostless front end and prepare ABR Rx path abr_device_id = fp_platform_get_pcm_device_id(USECASE_AUDIO_A2DP_ABR_FEEDBACK, PCM_PLAYBACK); if (!a2dp.abr_config.abr_rx_handle) { a2dp.abr_config.abr_rx_handle = pcm_open(a2dp.adev->snd_card, abr_device_id, PCM_OUT, &pcm_config_abr); if (a2dp.abr_config.abr_rx_handle == NULL) { ALOGE("%s: Can't open abr rx device", __func__); goto fail; } if (!(pcm_is_ready(a2dp.abr_config.abr_rx_handle) && !pcm_start(a2dp.abr_config.abr_rx_handle))) { ALOGE("%s: rx: %s", __func__, pcm_get_error(a2dp.abr_config.abr_rx_handle)); goto fail; } } } a2dp.abr_config.abr_started = true; return ret; fail: ALOGE("%s: %s", __func__, pcm_get_error(a2dp.abr_config.abr_tx_handle)); stop_abr(); return -ENOSYS; } Loading Loading @@ -965,6 +1063,7 @@ static int close_a2dp_output() a2dp.abr_config.abr_started = false; a2dp.abr_config.imc_instance = 0; a2dp.abr_config.abr_tx_handle = NULL; a2dp.abr_config.abr_rx_handle = NULL; a2dp.bt_state_source = A2DP_STATE_DISCONNECTED; return 0; Loading Loading @@ -1079,9 +1178,12 @@ static bool a2dp_set_backend_cfg(uint8_t direction) if (direction == SOURCE) { /* Set Tx backend sample rate */ if (a2dp.abr_config.is_abr_enabled) if (a2dp.abr_config.is_abr_enabled) { if (a2dp.bt_encoder_format == CODEC_TYPE_APTX_AD_SPEECH) rate_str = SPEECH_TX_SAMPLE_RATE; else rate_str = ABR_TX_SAMPLE_RATE; } ALOGD("%s: set backend tx sample rate = %s", __func__, rate_str); ctl_sample_rate = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_SOURCE_SAMPLE_RATE_TX); Loading Loading @@ -1282,7 +1384,7 @@ static int a2dp_reset_backend_cfg(uint8_t direction) ALOGE("%s: Failed to reset backend sample rate = %s", __func__, rate_str); return -ENOSYS; } if (a2dp.abr_config.is_abr_enabled) { ctl_sample_rate_tx = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_SOURCE_SAMPLE_RATE_TX); if (!ctl_sample_rate_tx) { Loading @@ -1294,6 +1396,7 @@ static int a2dp_reset_backend_cfg(uint8_t direction) ALOGE("%s: Failed to reset Tx backend sample rate = %s", __func__, rate_str); return -ENOSYS; } } } else { ctl_sample_rate = mixer_get_ctl_by_name(a2dp.adev->mixer, Loading Loading @@ -1707,7 +1810,7 @@ static int update_aptx_dsp_config_v1(struct custom_enc_cfg_t *aptx_dsp_cfg, bool configure_aptx_enc_format(audio_aptx_encoder_config *aptx_bt_cfg) { struct mixer_ctl *ctl_enc_data = NULL; int mixer_size; int mixer_size = 0; bool is_configured = false; int ret = 0; int sample_rate_backup; Loading Loading @@ -2209,7 +2312,7 @@ int a2dp_start_playback() return -ENOSYS; } if (a2dp.a2dp_source_suspended == true) { if (a2dp.a2dp_source_suspended || a2dp.swb_configured) { //session will be restarted after suspend completion ALOGD("a2dp start requested during suspend state"); return -ENOSYS; Loading Loading @@ -2434,6 +2537,16 @@ static void reset_a2dp_sink_dec_config_params() } } static void reset_codec_config() { reset_a2dp_enc_config_params(); reset_a2dp_source_dec_config_params(); a2dp_reset_backend_cfg(SOURCE); if (a2dp.abr_config.is_abr_enabled && a2dp.abr_config.abr_started) stop_abr(); a2dp.abr_config.is_abr_enabled = false; } int a2dp_stop_playback() { int ret =0; Loading @@ -2456,14 +2569,9 @@ int a2dp_stop_playback() ALOGE("stop stream to BT IPC lib failed"); else ALOGV("stop steam to BT IPC lib successful"); reset_a2dp_enc_config_params(); reset_a2dp_source_dec_config_params(); a2dp_reset_backend_cfg(SOURCE); if (a2dp.abr_config.is_abr_enabled && a2dp.abr_config.abr_started) stop_abr(); a2dp.abr_config.is_abr_enabled = false; if (!a2dp.a2dp_source_suspended && !a2dp.swb_configured) reset_codec_config(); a2dp.a2dp_source_started = false; a2dp_reset_backend_cfg(SOURCE); } if (!a2dp.a2dp_source_total_active_session_requests) a2dp.a2dp_source_started = false; Loading Loading @@ -2578,8 +2686,8 @@ int a2dp_set_parameters(struct str_parms *parms, bool *reconfig) pthread_mutex_lock(&a2dp.adev->lock); } } reset_a2dp_enc_config_params(); reset_a2dp_source_dec_config_params(); if (!a2dp.swb_configured) reset_codec_config(); if (a2dp.audio_source_suspend) a2dp.audio_source_suspend(); } else if (a2dp.a2dp_source_suspended == true) { Loading Loading @@ -2699,8 +2807,11 @@ void a2dp_init(void *adev, a2dp.abr_config.abr_started = false; a2dp.abr_config.imc_instance = 0; a2dp.abr_config.abr_tx_handle = NULL; a2dp.abr_config.abr_rx_handle = NULL; a2dp.is_tws_mono_mode_on = false; a2dp_source_init(); a2dp.swb_configured = false; // init function pointers fp_platform_get_pcm_device_id = init_config.fp_platform_get_pcm_device_id; Loading Loading @@ -2802,3 +2913,112 @@ int a2dp_get_parameters(struct str_parms *query, return 0; } bool configure_aptx_ad_speech_enc_fmt() { struct mixer_ctl *ctl_enc_data = NULL; int mixer_size = 0; int ret = 0; struct aptx_ad_speech_enc_cfg_t aptx_dsp_cfg; ctl_enc_data = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_ENC_CONFIG_BLOCK); if (!ctl_enc_data) { ALOGE(" ERROR a2dp encoder CONFIG data mixer control not identifed"); return false; } /* Initialize dsp configuration params */ memset(&aptx_dsp_cfg, 0x0, sizeof(struct aptx_ad_speech_enc_cfg_t)); aptx_dsp_cfg.custom_cfg.enc_format = MEDIA_FMT_APTX_AD_SPEECH; aptx_dsp_cfg.custom_cfg.sample_rate = SAMPLING_RATE_32K; aptx_dsp_cfg.custom_cfg.num_channels = CH_MONO; aptx_dsp_cfg.custom_cfg.channel_mapping[0] = PCM_CHANNEL_L; aptx_dsp_cfg.imc_info.direction = IMC_RECEIVE; aptx_dsp_cfg.imc_info.enable = IMC_ENABLE; aptx_dsp_cfg.imc_info.purpose = IMC_PURPOSE_ID_BT_INFO; aptx_dsp_cfg.imc_info.comm_instance = APTX_AD_SPEECH_INSTANCE_ID; aptx_dsp_cfg.speech_mode.mode = a2dp.adev->swb_speech_mode; aptx_dsp_cfg.speech_mode.swapping = SWAP_ENABLE; /* Configure AFE DSP configuration */ mixer_size = sizeof(struct aptx_ad_speech_enc_cfg_t); ret = mixer_ctl_set_array(ctl_enc_data, (void *)&aptx_dsp_cfg, mixer_size); if (ret != 0) { ALOGE("%s: Failed to set SWB encoder config", __func__); return false; } /* Configure AFE Input Bit Format as PCM_16 */ ret = a2dp_set_bit_format(DEFAULT_ENCODER_BIT_FORMAT); if (ret != 0) { ALOGE("%s: Failed to set SWB bit format", __func__); return false; } return true; } bool configure_aptx_ad_speech_dec_fmt() { struct mixer_ctl *ctl_dec_data = NULL; struct aptx_ad_speech_dec_cfg_t dec_cfg; int ret = 0; ctl_dec_data = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_SOURCE_DEC_CONFIG_BLOCK); if (!ctl_dec_data) { ALOGE("%s: ERROR codec config data mixer control not identifed", __func__); return false; } memset(&dec_cfg, 0x0, sizeof(dec_cfg)); dec_cfg.abr_cfg.dec_format = MEDIA_FMT_APTX_AD_SPEECH; dec_cfg.abr_cfg.imc_info.direction = IMC_TRANSMIT; dec_cfg.abr_cfg.imc_info.enable = IMC_ENABLE; dec_cfg.abr_cfg.imc_info.purpose = IMC_PURPOSE_ID_BT_INFO; dec_cfg.abr_cfg.imc_info.comm_instance = APTX_AD_SPEECH_INSTANCE_ID; dec_cfg.speech_mode.mode = a2dp.adev->swb_speech_mode; dec_cfg.speech_mode.swapping = SWAP_ENABLE; ret = mixer_ctl_set_array(ctl_dec_data, &dec_cfg, sizeof(dec_cfg)); if (ret != 0) { ALOGE("%s: Failed to set decoder config", __func__); return false; } return true; } int sco_start_configuration() { ALOGD("sco_start_configuration start"); if (!a2dp.swb_configured) { a2dp.bt_encoder_format = CODEC_TYPE_APTX_AD_SPEECH; /* Configure AFE codec*/ if (configure_aptx_ad_speech_enc_fmt() && configure_aptx_ad_speech_dec_fmt()) { ALOGD("%s: SCO enc/dec configured successfully", __func__); } else { ALOGE("%s: failed to send SCO configuration", __func__); return -ETIMEDOUT; } /* Configure backend*/ a2dp.enc_sampling_rate = SAMPLING_RATE_96K; a2dp.enc_channels = CH_MONO; a2dp.abr_config.is_abr_enabled = true; a2dp_set_backend_cfg(SOURCE); /* Start abr*/ start_abr(); a2dp.swb_configured = true; } return 0; } void sco_reset_configuration() { ALOGD("sco_reset_configuration start"); reset_codec_config(); a2dp.bt_encoder_format = CODEC_TYPE_INVALID; a2dp.swb_configured = false; } hal/audio_extn/audio_extn.c +26 −0 Original line number Diff line number Diff line Loading @@ -3791,6 +3791,13 @@ static a2dp_start_capture_t a2dp_start_capture; typedef int (*a2dp_stop_capture_t)(); static a2dp_stop_capture_t a2dp_stop_capture; typedef int (*sco_start_configuration_t)(); static sco_start_configuration_t sco_start_configuration; typedef void (*sco_reset_configuration_t)(); static sco_reset_configuration_t sco_reset_configuration; int a2dp_offload_feature_init(bool is_feature_enabled) { ALOGD("%s: Called with feature %s", __func__, Loading Loading @@ -3842,6 +3849,15 @@ int a2dp_offload_feature_init(bool is_feature_enabled) ALOGE("%s: dlsym failed", __func__); goto feature_disabled; } // initialize APIs for SWB extension if (!(sco_start_configuration = (sco_start_configuration_t)dlsym(a2dp_lib_handle, "sco_start_configuration")) || !(sco_reset_configuration = (sco_reset_configuration_t)dlsym(a2dp_lib_handle, "sco_reset_configuration"))) { ALOGE("%s: dlsym failed for swb APIs", __func__); sco_start_configuration = NULL; sco_reset_configuration = NULL; } ALOGD("%s:: ---- Feature A2DP_OFFLOAD is Enabled ----", __func__); return 0; } Loading Loading @@ -3965,6 +3981,16 @@ int audio_extn_a2dp_stop_capture() return (a2dp_stop_capture ? a2dp_stop_capture() : 0); } int audio_extn_sco_start_configuration() { return (sco_start_configuration? sco_start_configuration() : 0); } void audio_extn_sco_reset_configuration() { return (sco_reset_configuration? sco_reset_configuration() : 0); } // END: A2DP_OFFLOAD ===================================================================== // START: HFP ====================================================================== Loading hal/audio_extn/audio_extn.h +3 −0 Original line number Diff line number Diff line Loading @@ -313,6 +313,9 @@ bool audio_extn_a2dp_source_is_ready(); bool audio_extn_a2dp_source_is_suspended(); int audio_extn_a2dp_start_capture(); int audio_extn_a2dp_stop_capture(); int audio_extn_sco_start_configuration(); void audio_extn_sco_reset_configuration(); // --- Function pointers from audio_extn needed by A2DP_OFFLOAD typedef int (*fp_check_a2dp_restore_t)(struct audio_device *, Loading hal/audio_hw.c +23 −1 Original line number Diff line number Diff line Loading @@ -1189,6 +1189,14 @@ int enable_snd_device(struct audio_device *adev, goto err; } if (((SND_DEVICE_OUT_BT_SCO_SWB == snd_device) || (SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC == snd_device) || (SND_DEVICE_IN_BT_SCO_MIC_SWB == snd_device)) && (audio_extn_sco_start_configuration() < 0)) { ALOGE(" fail to configure sco control path "); goto err; } /* due to the possibility of calibration overwrite between listen and audio, notify listen hal before audio calibration is sent */ audio_extn_sound_trigger_update_device_status(snd_device, Loading Loading @@ -1281,7 +1289,14 @@ int disable_snd_device(struct audio_device *adev, audio_extn_a2dp_stop_playback(); else if (snd_device == SND_DEVICE_IN_BT_A2DP) audio_extn_a2dp_stop_capture(); else if ((snd_device == SND_DEVICE_OUT_HDMI) || else if ((snd_device == SND_DEVICE_OUT_BT_SCO_SWB) || (snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC) || (snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB)) { if ((adev->snd_dev_ref_cnt[SND_DEVICE_OUT_BT_SCO_SWB] == 0) && (adev->snd_dev_ref_cnt[SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC] == 0) && (adev->snd_dev_ref_cnt[SND_DEVICE_IN_BT_SCO_MIC_SWB] == 0)) audio_extn_sco_reset_configuration(); } else if ((snd_device == SND_DEVICE_OUT_HDMI) || (snd_device == SND_DEVICE_OUT_DISPLAY_PORT)) adev->is_channel_status_set = false; else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) && Loading Loading @@ -7659,6 +7674,12 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) adev->bt_wb_speech_enabled = false; } ret = str_parms_get_str(parms, "bt_swb", value, sizeof(value)); if (ret >= 0) { val = atoi(value); adev->swb_speech_mode = val; } ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value)); if (ret >= 0) { val = atoi(value); Loading Loading @@ -9104,6 +9125,7 @@ static int adev_open(const hw_module_t *module, const char *name, adev->enable_voicerx = false; adev->bt_wb_speech_enabled = false; adev->swb_speech_mode = SPEECH_MODE_INVALID; //initialize this to false for now, //this will be set to true through set param adev->vr_audio_mode_enabled = false; Loading hal/audio_hw.h +4 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,9 @@ #define ACDB_DEV_TYPE_OUT 1 #define ACDB_DEV_TYPE_IN 2 /* SCO SWB codec mode */ #define SPEECH_MODE_INVALID 0xFFFF /* support positional and index masks to 8ch */ #define MAX_SUPPORTED_CHANNEL_MASKS (2 * FCC_8) #define MAX_SUPPORTED_FORMATS 15 Loading Loading @@ -527,6 +530,7 @@ struct audio_device { unsigned int cur_hdmi_bit_width; unsigned int cur_wfd_channels; bool bt_wb_speech_enabled; unsigned int swb_speech_mode; bool allow_afe_proxy_usage; bool is_charging; // from battery listener bool mic_break_enabled; Loading Loading
hal/audio_extn/a2dp.c +259 −39 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ #define MEDIA_FMT_LDAC 0x00013224 #define MEDIA_FMT_MP3 0x00010BE9 #define MEDIA_FMT_APTX_ADAPTIVE 0x00013204 #define MEDIA_FMT_APTX_AD_SPEECH 0x00013208 #define MEDIA_FMT_AAC_AOT_LC 2 #define MEDIA_FMT_AAC_AOT_SBR 5 #define MEDIA_FMT_AAC_AOT_PS 29 Loading @@ -85,6 +86,7 @@ #define MIXER_SAMPLE_RATE_DEFAULT "BT SampleRate" #define MIXER_AFE_IN_CHANNELS "AFE Input Channels" #define MIXER_ABR_TX_FEEDBACK_PATH "A2DP_SLIM7_UL_HL Switch" #define MIXER_ABR_RX_FEEDBACK_PATH "SCO_SLIM7_DL_HL Switch" #define MIXER_SET_FEEDBACK_CHANNEL "BT set feedback channel" #define MIXER_SINK_SAMPLE_RATE "BT_TX SampleRate" #define MIXER_AFE_SINK_CHANNELS "AFE Output Channels" Loading Loading @@ -125,6 +127,9 @@ // Slimbus Tx sample rate for ABR feedback channel #define ABR_TX_SAMPLE_RATE "KHZ_8" // Slimbus Tx sample rate for APTX AD SPEECH #define SPEECH_TX_SAMPLE_RATE "KHZ_96" // Purpose ID for Inter Module Communication (IMC) in AFE #define IMC_PURPOSE_ID_BT_INFO 0x000132E2 Loading @@ -134,8 +139,13 @@ // Instance identifier for A2DP #define MAX_INSTANCE_ID (UINT32_MAX / 2) // Instance identifier for SWB #define APTX_AD_SPEECH_INSTANCE_ID 37 #define SAMPLING_RATE_96K 96000 #define SAMPLING_RATE_48K 48000 #define SAMPLING_RATE_441K 44100 #define SAMPLING_RATE_32K 32000 #define CH_STEREO 2 #define CH_MONO 1 #define SOURCE 0 Loading Loading @@ -172,6 +182,7 @@ typedef enum { CODEC_TYPE_LDAC = AUDIO_FORMAT_LDAC, // 0x23000000UL CODEC_TYPE_CELT = 603979776u, // 0x24000000UL CODEC_TYPE_APTX_AD = 620756992u, // 0x25000000UL CODEC_TYPE_APTX_AD_SPEECH = 637534208u, //0x26000000UL CODEC_TYPE_PCM = AUDIO_FORMAT_PCM_16_BIT, // 0x1u }codec_t; Loading Loading @@ -236,6 +247,11 @@ typedef enum { IMC_ENABLE, } imc_status_t; typedef enum { SWAP_DISABLE, SWAP_ENABLE, } swap_status_t; typedef enum { MTU_SIZE, PEAK_BIT_RATE, Loading Loading @@ -265,6 +281,8 @@ struct a2dp_abr_config { bool abr_started; /* ABR Tx path pcm handle */ struct pcm *abr_tx_handle; /* ABR Rx path pcm handle */ struct pcm *abr_rx_handle; /* ABR Inter Module Communication (IMC) instance ID */ uint32_t imc_instance; }; Loading Loading @@ -319,6 +337,7 @@ struct a2dp_data { uint32_t dec_channels; bool a2dp_sink_started; int a2dp_sink_total_active_session_requests; bool swb_configured; }; struct a2dp_data a2dp; Loading Loading @@ -400,6 +419,18 @@ struct abr_dec_cfg_t { struct imc_dec_enc_info imc_info; } __attribute__ ((packed)); struct aptx_ad_speech_mode_cfg_t { uint32_t mode; uint32_t swapping; } __attribute__ ((packed)); /* Structure for SWB voice dec config */ struct aptx_ad_speech_dec_cfg_t { struct abr_dec_cfg_t abr_cfg; struct aptx_ad_speech_mode_cfg_t speech_mode; } __attribute__ ((packed)); /* START of DSP configurable structures * These values should match with DSP interface defintion */ Loading Loading @@ -546,6 +577,15 @@ struct aptx_ad_enc_cfg_t struct abr_enc_cfg_t abr_cfg; } __attribute__ ((packed)); /* APTX AD SPEECH structure */ struct aptx_ad_speech_enc_cfg_t { struct custom_enc_cfg_t custom_cfg; /* Information to set up IMC between decoder and encoder */ struct imc_dec_enc_info imc_info; struct aptx_ad_speech_mode_cfg_t speech_mode; } __attribute__ ((packed)); struct ldac_specific_enc_cfg_t { uint32_t bit_rate; Loading Loading @@ -715,7 +755,9 @@ static void update_offload_codec_capabilities() static int stop_abr() { struct mixer_ctl *ctl_abr_tx_path = NULL; struct mixer_ctl *ctl_abr_rx_path = NULL; struct mixer_ctl *ctl_set_bt_feedback_channel = NULL; int ret = 0; /* This function can be used if !abr_started for clean up */ ALOGV("%s: enter", __func__); Loading @@ -725,6 +767,10 @@ static int stop_abr() pcm_close(a2dp.abr_config.abr_tx_handle); a2dp.abr_config.abr_tx_handle = NULL; } if (a2dp.abr_config.abr_rx_handle != NULL) { pcm_close(a2dp.abr_config.abr_rx_handle); a2dp.abr_config.abr_rx_handle = NULL; } a2dp.abr_config.abr_started = false; a2dp.abr_config.imc_instance = 0; Loading @@ -733,11 +779,10 @@ static int stop_abr() MIXER_SET_FEEDBACK_CHANNEL); if (!ctl_set_bt_feedback_channel) { ALOGE("%s: ERROR Set usecase mixer control not identifed", __func__); return -ENOSYS; } if (mixer_ctl_set_value(ctl_set_bt_feedback_channel, 0, 0) != 0) { ret = -ENOSYS; } else if (mixer_ctl_set_value(ctl_set_bt_feedback_channel, 0, 0) != 0) { ALOGE("%s: Failed to set BT usecase", __func__); return -ENOSYS; ret = -ENOSYS; } // Reset ABR Tx feedback path Loading @@ -746,19 +791,31 @@ static int stop_abr() MIXER_ABR_TX_FEEDBACK_PATH); if (!ctl_abr_tx_path) { ALOGE("%s: ERROR ABR Tx feedback path mixer control not identifed", __func__); return -ENOSYS; } if (mixer_ctl_set_value(ctl_abr_tx_path, 0, 0) != 0) { ret = -ENOSYS; } else if (mixer_ctl_set_value(ctl_abr_tx_path, 0, 0) != 0) { ALOGE("%s: Failed to set ABR Tx feedback path", __func__); return -ENOSYS; ret = -ENOSYS; } return 0; // Reset ABR Rx feedback path ALOGV("%s: Disable ABR Rx feedback path", __func__); ctl_abr_rx_path = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_ABR_RX_FEEDBACK_PATH); if (!ctl_abr_rx_path) { ALOGE("%s: ERROR ABR Rx feedback path mixer control not identifed", __func__); ret = -ENOSYS; } else if (mixer_ctl_set_value(ctl_abr_rx_path, 0, 0) != 0) { ALOGE("%s: Failed to set ABR Rx feedback path", __func__); ret = -ENOSYS; } return ret; } static int start_abr() { struct mixer_ctl *ctl_abr_tx_path = NULL; struct mixer_ctl *ctl_abr_rx_path = NULL; struct mixer_ctl *ctl_set_bt_feedback_channel = NULL; int abr_device_id; int ret = 0; Loading Loading @@ -792,11 +849,11 @@ static int start_abr() MIXER_SET_FEEDBACK_CHANNEL); if (!ctl_set_bt_feedback_channel) { ALOGE("%s: ERROR Set usecase mixer control not identifed", __func__); return -ENOSYS; goto fail; } if (mixer_ctl_set_value(ctl_set_bt_feedback_channel, 0, 1) != 0) { ALOGE("%s: Failed to set BT usecase", __func__); return -ENOSYS; goto fail; } // Open hostless front end and prepare ABR Tx path Loading @@ -806,19 +863,60 @@ static int start_abr() a2dp.abr_config.abr_tx_handle = pcm_open(a2dp.adev->snd_card, abr_device_id, PCM_IN, &pcm_config_abr); if (a2dp.abr_config.abr_tx_handle == NULL || !pcm_is_ready(a2dp.abr_config.abr_tx_handle)) if (a2dp.abr_config.abr_tx_handle == NULL) { ALOGE("%s: Can't open abr tx device", __func__); goto fail; } ret = pcm_start(a2dp.abr_config.abr_tx_handle); if (ret < 0) if (!(pcm_is_ready(a2dp.abr_config.abr_tx_handle) && !pcm_start(a2dp.abr_config.abr_tx_handle))) { ALOGE("%s: tx: %s", __func__, pcm_get_error(a2dp.abr_config.abr_tx_handle)); goto fail; } } // Enable Slimbus 7 Rx feedback path for HD Voice use case if (a2dp.bt_encoder_format == CODEC_TYPE_APTX_AD_SPEECH) { ALOGV("%s: Enable ABR Rx feedback path", __func__); ctl_abr_rx_path = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_ABR_RX_FEEDBACK_PATH); if (!ctl_abr_rx_path) { ALOGE("%s: ERROR ABR Rx feedback path mixer control not identifed", __func__); goto fail; } if (mixer_ctl_set_value(ctl_abr_rx_path, 0, 1) != 0) { ALOGE("%s: Failed to set ABR Rx feedback path", __func__); goto fail; } if (mixer_ctl_set_value(ctl_set_bt_feedback_channel, 0, 1) != 0) { ALOGE("%s: Failed to set BT usecase", __func__); goto fail; } // Open hostless front end and prepare ABR Rx path abr_device_id = fp_platform_get_pcm_device_id(USECASE_AUDIO_A2DP_ABR_FEEDBACK, PCM_PLAYBACK); if (!a2dp.abr_config.abr_rx_handle) { a2dp.abr_config.abr_rx_handle = pcm_open(a2dp.adev->snd_card, abr_device_id, PCM_OUT, &pcm_config_abr); if (a2dp.abr_config.abr_rx_handle == NULL) { ALOGE("%s: Can't open abr rx device", __func__); goto fail; } if (!(pcm_is_ready(a2dp.abr_config.abr_rx_handle) && !pcm_start(a2dp.abr_config.abr_rx_handle))) { ALOGE("%s: rx: %s", __func__, pcm_get_error(a2dp.abr_config.abr_rx_handle)); goto fail; } } } a2dp.abr_config.abr_started = true; return ret; fail: ALOGE("%s: %s", __func__, pcm_get_error(a2dp.abr_config.abr_tx_handle)); stop_abr(); return -ENOSYS; } Loading Loading @@ -965,6 +1063,7 @@ static int close_a2dp_output() a2dp.abr_config.abr_started = false; a2dp.abr_config.imc_instance = 0; a2dp.abr_config.abr_tx_handle = NULL; a2dp.abr_config.abr_rx_handle = NULL; a2dp.bt_state_source = A2DP_STATE_DISCONNECTED; return 0; Loading Loading @@ -1079,9 +1178,12 @@ static bool a2dp_set_backend_cfg(uint8_t direction) if (direction == SOURCE) { /* Set Tx backend sample rate */ if (a2dp.abr_config.is_abr_enabled) if (a2dp.abr_config.is_abr_enabled) { if (a2dp.bt_encoder_format == CODEC_TYPE_APTX_AD_SPEECH) rate_str = SPEECH_TX_SAMPLE_RATE; else rate_str = ABR_TX_SAMPLE_RATE; } ALOGD("%s: set backend tx sample rate = %s", __func__, rate_str); ctl_sample_rate = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_SOURCE_SAMPLE_RATE_TX); Loading Loading @@ -1282,7 +1384,7 @@ static int a2dp_reset_backend_cfg(uint8_t direction) ALOGE("%s: Failed to reset backend sample rate = %s", __func__, rate_str); return -ENOSYS; } if (a2dp.abr_config.is_abr_enabled) { ctl_sample_rate_tx = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_SOURCE_SAMPLE_RATE_TX); if (!ctl_sample_rate_tx) { Loading @@ -1294,6 +1396,7 @@ static int a2dp_reset_backend_cfg(uint8_t direction) ALOGE("%s: Failed to reset Tx backend sample rate = %s", __func__, rate_str); return -ENOSYS; } } } else { ctl_sample_rate = mixer_get_ctl_by_name(a2dp.adev->mixer, Loading Loading @@ -1707,7 +1810,7 @@ static int update_aptx_dsp_config_v1(struct custom_enc_cfg_t *aptx_dsp_cfg, bool configure_aptx_enc_format(audio_aptx_encoder_config *aptx_bt_cfg) { struct mixer_ctl *ctl_enc_data = NULL; int mixer_size; int mixer_size = 0; bool is_configured = false; int ret = 0; int sample_rate_backup; Loading Loading @@ -2209,7 +2312,7 @@ int a2dp_start_playback() return -ENOSYS; } if (a2dp.a2dp_source_suspended == true) { if (a2dp.a2dp_source_suspended || a2dp.swb_configured) { //session will be restarted after suspend completion ALOGD("a2dp start requested during suspend state"); return -ENOSYS; Loading Loading @@ -2434,6 +2537,16 @@ static void reset_a2dp_sink_dec_config_params() } } static void reset_codec_config() { reset_a2dp_enc_config_params(); reset_a2dp_source_dec_config_params(); a2dp_reset_backend_cfg(SOURCE); if (a2dp.abr_config.is_abr_enabled && a2dp.abr_config.abr_started) stop_abr(); a2dp.abr_config.is_abr_enabled = false; } int a2dp_stop_playback() { int ret =0; Loading @@ -2456,14 +2569,9 @@ int a2dp_stop_playback() ALOGE("stop stream to BT IPC lib failed"); else ALOGV("stop steam to BT IPC lib successful"); reset_a2dp_enc_config_params(); reset_a2dp_source_dec_config_params(); a2dp_reset_backend_cfg(SOURCE); if (a2dp.abr_config.is_abr_enabled && a2dp.abr_config.abr_started) stop_abr(); a2dp.abr_config.is_abr_enabled = false; if (!a2dp.a2dp_source_suspended && !a2dp.swb_configured) reset_codec_config(); a2dp.a2dp_source_started = false; a2dp_reset_backend_cfg(SOURCE); } if (!a2dp.a2dp_source_total_active_session_requests) a2dp.a2dp_source_started = false; Loading Loading @@ -2578,8 +2686,8 @@ int a2dp_set_parameters(struct str_parms *parms, bool *reconfig) pthread_mutex_lock(&a2dp.adev->lock); } } reset_a2dp_enc_config_params(); reset_a2dp_source_dec_config_params(); if (!a2dp.swb_configured) reset_codec_config(); if (a2dp.audio_source_suspend) a2dp.audio_source_suspend(); } else if (a2dp.a2dp_source_suspended == true) { Loading Loading @@ -2699,8 +2807,11 @@ void a2dp_init(void *adev, a2dp.abr_config.abr_started = false; a2dp.abr_config.imc_instance = 0; a2dp.abr_config.abr_tx_handle = NULL; a2dp.abr_config.abr_rx_handle = NULL; a2dp.is_tws_mono_mode_on = false; a2dp_source_init(); a2dp.swb_configured = false; // init function pointers fp_platform_get_pcm_device_id = init_config.fp_platform_get_pcm_device_id; Loading Loading @@ -2802,3 +2913,112 @@ int a2dp_get_parameters(struct str_parms *query, return 0; } bool configure_aptx_ad_speech_enc_fmt() { struct mixer_ctl *ctl_enc_data = NULL; int mixer_size = 0; int ret = 0; struct aptx_ad_speech_enc_cfg_t aptx_dsp_cfg; ctl_enc_data = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_ENC_CONFIG_BLOCK); if (!ctl_enc_data) { ALOGE(" ERROR a2dp encoder CONFIG data mixer control not identifed"); return false; } /* Initialize dsp configuration params */ memset(&aptx_dsp_cfg, 0x0, sizeof(struct aptx_ad_speech_enc_cfg_t)); aptx_dsp_cfg.custom_cfg.enc_format = MEDIA_FMT_APTX_AD_SPEECH; aptx_dsp_cfg.custom_cfg.sample_rate = SAMPLING_RATE_32K; aptx_dsp_cfg.custom_cfg.num_channels = CH_MONO; aptx_dsp_cfg.custom_cfg.channel_mapping[0] = PCM_CHANNEL_L; aptx_dsp_cfg.imc_info.direction = IMC_RECEIVE; aptx_dsp_cfg.imc_info.enable = IMC_ENABLE; aptx_dsp_cfg.imc_info.purpose = IMC_PURPOSE_ID_BT_INFO; aptx_dsp_cfg.imc_info.comm_instance = APTX_AD_SPEECH_INSTANCE_ID; aptx_dsp_cfg.speech_mode.mode = a2dp.adev->swb_speech_mode; aptx_dsp_cfg.speech_mode.swapping = SWAP_ENABLE; /* Configure AFE DSP configuration */ mixer_size = sizeof(struct aptx_ad_speech_enc_cfg_t); ret = mixer_ctl_set_array(ctl_enc_data, (void *)&aptx_dsp_cfg, mixer_size); if (ret != 0) { ALOGE("%s: Failed to set SWB encoder config", __func__); return false; } /* Configure AFE Input Bit Format as PCM_16 */ ret = a2dp_set_bit_format(DEFAULT_ENCODER_BIT_FORMAT); if (ret != 0) { ALOGE("%s: Failed to set SWB bit format", __func__); return false; } return true; } bool configure_aptx_ad_speech_dec_fmt() { struct mixer_ctl *ctl_dec_data = NULL; struct aptx_ad_speech_dec_cfg_t dec_cfg; int ret = 0; ctl_dec_data = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_SOURCE_DEC_CONFIG_BLOCK); if (!ctl_dec_data) { ALOGE("%s: ERROR codec config data mixer control not identifed", __func__); return false; } memset(&dec_cfg, 0x0, sizeof(dec_cfg)); dec_cfg.abr_cfg.dec_format = MEDIA_FMT_APTX_AD_SPEECH; dec_cfg.abr_cfg.imc_info.direction = IMC_TRANSMIT; dec_cfg.abr_cfg.imc_info.enable = IMC_ENABLE; dec_cfg.abr_cfg.imc_info.purpose = IMC_PURPOSE_ID_BT_INFO; dec_cfg.abr_cfg.imc_info.comm_instance = APTX_AD_SPEECH_INSTANCE_ID; dec_cfg.speech_mode.mode = a2dp.adev->swb_speech_mode; dec_cfg.speech_mode.swapping = SWAP_ENABLE; ret = mixer_ctl_set_array(ctl_dec_data, &dec_cfg, sizeof(dec_cfg)); if (ret != 0) { ALOGE("%s: Failed to set decoder config", __func__); return false; } return true; } int sco_start_configuration() { ALOGD("sco_start_configuration start"); if (!a2dp.swb_configured) { a2dp.bt_encoder_format = CODEC_TYPE_APTX_AD_SPEECH; /* Configure AFE codec*/ if (configure_aptx_ad_speech_enc_fmt() && configure_aptx_ad_speech_dec_fmt()) { ALOGD("%s: SCO enc/dec configured successfully", __func__); } else { ALOGE("%s: failed to send SCO configuration", __func__); return -ETIMEDOUT; } /* Configure backend*/ a2dp.enc_sampling_rate = SAMPLING_RATE_96K; a2dp.enc_channels = CH_MONO; a2dp.abr_config.is_abr_enabled = true; a2dp_set_backend_cfg(SOURCE); /* Start abr*/ start_abr(); a2dp.swb_configured = true; } return 0; } void sco_reset_configuration() { ALOGD("sco_reset_configuration start"); reset_codec_config(); a2dp.bt_encoder_format = CODEC_TYPE_INVALID; a2dp.swb_configured = false; }
hal/audio_extn/audio_extn.c +26 −0 Original line number Diff line number Diff line Loading @@ -3791,6 +3791,13 @@ static a2dp_start_capture_t a2dp_start_capture; typedef int (*a2dp_stop_capture_t)(); static a2dp_stop_capture_t a2dp_stop_capture; typedef int (*sco_start_configuration_t)(); static sco_start_configuration_t sco_start_configuration; typedef void (*sco_reset_configuration_t)(); static sco_reset_configuration_t sco_reset_configuration; int a2dp_offload_feature_init(bool is_feature_enabled) { ALOGD("%s: Called with feature %s", __func__, Loading Loading @@ -3842,6 +3849,15 @@ int a2dp_offload_feature_init(bool is_feature_enabled) ALOGE("%s: dlsym failed", __func__); goto feature_disabled; } // initialize APIs for SWB extension if (!(sco_start_configuration = (sco_start_configuration_t)dlsym(a2dp_lib_handle, "sco_start_configuration")) || !(sco_reset_configuration = (sco_reset_configuration_t)dlsym(a2dp_lib_handle, "sco_reset_configuration"))) { ALOGE("%s: dlsym failed for swb APIs", __func__); sco_start_configuration = NULL; sco_reset_configuration = NULL; } ALOGD("%s:: ---- Feature A2DP_OFFLOAD is Enabled ----", __func__); return 0; } Loading Loading @@ -3965,6 +3981,16 @@ int audio_extn_a2dp_stop_capture() return (a2dp_stop_capture ? a2dp_stop_capture() : 0); } int audio_extn_sco_start_configuration() { return (sco_start_configuration? sco_start_configuration() : 0); } void audio_extn_sco_reset_configuration() { return (sco_reset_configuration? sco_reset_configuration() : 0); } // END: A2DP_OFFLOAD ===================================================================== // START: HFP ====================================================================== Loading
hal/audio_extn/audio_extn.h +3 −0 Original line number Diff line number Diff line Loading @@ -313,6 +313,9 @@ bool audio_extn_a2dp_source_is_ready(); bool audio_extn_a2dp_source_is_suspended(); int audio_extn_a2dp_start_capture(); int audio_extn_a2dp_stop_capture(); int audio_extn_sco_start_configuration(); void audio_extn_sco_reset_configuration(); // --- Function pointers from audio_extn needed by A2DP_OFFLOAD typedef int (*fp_check_a2dp_restore_t)(struct audio_device *, Loading
hal/audio_hw.c +23 −1 Original line number Diff line number Diff line Loading @@ -1189,6 +1189,14 @@ int enable_snd_device(struct audio_device *adev, goto err; } if (((SND_DEVICE_OUT_BT_SCO_SWB == snd_device) || (SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC == snd_device) || (SND_DEVICE_IN_BT_SCO_MIC_SWB == snd_device)) && (audio_extn_sco_start_configuration() < 0)) { ALOGE(" fail to configure sco control path "); goto err; } /* due to the possibility of calibration overwrite between listen and audio, notify listen hal before audio calibration is sent */ audio_extn_sound_trigger_update_device_status(snd_device, Loading Loading @@ -1281,7 +1289,14 @@ int disable_snd_device(struct audio_device *adev, audio_extn_a2dp_stop_playback(); else if (snd_device == SND_DEVICE_IN_BT_A2DP) audio_extn_a2dp_stop_capture(); else if ((snd_device == SND_DEVICE_OUT_HDMI) || else if ((snd_device == SND_DEVICE_OUT_BT_SCO_SWB) || (snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC) || (snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB)) { if ((adev->snd_dev_ref_cnt[SND_DEVICE_OUT_BT_SCO_SWB] == 0) && (adev->snd_dev_ref_cnt[SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC] == 0) && (adev->snd_dev_ref_cnt[SND_DEVICE_IN_BT_SCO_MIC_SWB] == 0)) audio_extn_sco_reset_configuration(); } else if ((snd_device == SND_DEVICE_OUT_HDMI) || (snd_device == SND_DEVICE_OUT_DISPLAY_PORT)) adev->is_channel_status_set = false; else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) && Loading Loading @@ -7659,6 +7674,12 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) adev->bt_wb_speech_enabled = false; } ret = str_parms_get_str(parms, "bt_swb", value, sizeof(value)); if (ret >= 0) { val = atoi(value); adev->swb_speech_mode = val; } ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value)); if (ret >= 0) { val = atoi(value); Loading Loading @@ -9104,6 +9125,7 @@ static int adev_open(const hw_module_t *module, const char *name, adev->enable_voicerx = false; adev->bt_wb_speech_enabled = false; adev->swb_speech_mode = SPEECH_MODE_INVALID; //initialize this to false for now, //this will be set to true through set param adev->vr_audio_mode_enabled = false; Loading
hal/audio_hw.h +4 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,9 @@ #define ACDB_DEV_TYPE_OUT 1 #define ACDB_DEV_TYPE_IN 2 /* SCO SWB codec mode */ #define SPEECH_MODE_INVALID 0xFFFF /* support positional and index masks to 8ch */ #define MAX_SUPPORTED_CHANNEL_MASKS (2 * FCC_8) #define MAX_SUPPORTED_FORMATS 15 Loading Loading @@ -527,6 +530,7 @@ struct audio_device { unsigned int cur_hdmi_bit_width; unsigned int cur_wfd_channels; bool bt_wb_speech_enabled; unsigned int swb_speech_mode; bool allow_afe_proxy_usage; bool is_charging; // from battery listener bool mic_break_enabled; Loading