diff options
Diffstat (limited to 'hal')
-rw-r--r-- | hal/Android.mk | 20 | ||||
-rw-r--r-- | hal/audio_extn/audio_defs.h | 78 | ||||
-rw-r--r-- | hal/audio_extn/audio_extn.c | 43 | ||||
-rw-r--r-- | hal/audio_extn/audio_extn.h | 22 | ||||
-rw-r--r-- | hal/audio_extn/hfp.c | 16 | ||||
-rw-r--r-- | hal/audio_extn/sound_trigger_prop_intf.h | 61 | ||||
-rw-r--r-- | hal/audio_extn/soundtrigger.c | 20 | ||||
-rw-r--r-- | hal/audio_extn/spkr_protection.c | 1 | ||||
-rw-r--r-- | hal/audio_hw.c | 298 | ||||
-rw-r--r-- | hal/audio_hw.h | 8 | ||||
-rw-r--r-- | hal/msm8960/platform.c | 8 | ||||
-rw-r--r-- | hal/msm8974/platform.c | 291 | ||||
-rw-r--r-- | hal/msm8974/platform.h | 22 | ||||
-rw-r--r-- | hal/platform_api.h | 10 | ||||
-rw-r--r-- | hal/voice.c | 3 |
15 files changed, 824 insertions, 77 deletions
diff --git a/hal/Android.mk b/hal/Android.mk index 549d2f98..03696354 100644 --- a/hal/Android.mk +++ b/hal/Android.mk @@ -68,11 +68,18 @@ ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MULTI_VOICE_SESSIONS)),true) LOCAL_SRC_FILES += voice_extn/voice_extn.c endif +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HFP)),true) LOCAL_CFLAGS += -DHFP_ENABLED LOCAL_SRC_FILES += audio_extn/hfp.c endif +ifeq ($(strip $(AUDIO_FEATURE_SUPPORTED_EXTERNAL_BT)),true) + LOCAL_CFLAGS += -DEXTERNAL_BT_SUPPORTED +endif + ifeq ($(strip $(AUDIO_FEATURE_NO_AUDIO_OUT)),true) LOCAL_CFLAGS += -DNO_AUDIO_OUT endif @@ -101,6 +108,19 @@ ifneq ($(filter msm8992 msm8994,$(TARGET_BOARD_PLATFORM)),) LOCAL_SRC_FILES += audio_extn/hwdep_cal.c endif +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PCM_OFFLOAD)),true) + LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED +endif + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FLAC_OFFLOAD)),true) + LOCAL_CFLAGS += -DFLAC_OFFLOAD_ENABLED + LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED + LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED +endif + +LOCAL_COPY_HEADERS_TO := mm-audio +LOCAL_COPY_HEADERS := audio_extn/audio_defs.h + LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_RELATIVE_PATH := hw diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h new file mode 100644 index 00000000..335a6295 --- /dev/null +++ b/hal/audio_extn/audio_defs.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AUDIO_DEFS_H +#define AUDIO_DEFS_H + + +/** + * extended audio codec parameters + */ + +#define AUDIO_OFFLOAD_CODEC_WMA_FORMAT_TAG "music_offload_wma_format_tag" +#define AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN "music_offload_wma_block_align" +#define AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE "music_offload_wma_bit_per_sample" +#define AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK "music_offload_wma_channel_mask" +#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION "music_offload_wma_encode_option" +#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1 "music_offload_wma_encode_option1" +#define AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2 "music_offload_wma_encode_option2" +#define AUDIO_OFFLOAD_CODEC_FORMAT "music_offload_codec_format" +#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE "music_offload_flac_min_blk_size" +#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE "music_offload_flac_max_blk_size" +#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE "music_offload_flac_min_frame_size" +#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE "music_offload_flac_max_frame_size" + +/* Query handle fm parameter*/ +#define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm" + +/* Query fm volume */ +#define AUDIO_PARAMETER_KEY_FM_VOLUME "fm_volume" + +/* Query Fluence type */ +#define AUDIO_PARAMETER_KEY_FLUENCE "fluence" +#define AUDIO_PARAMETER_VALUE_QUADMIC "quadmic" +#define AUDIO_PARAMETER_VALUE_DUALMIC "dualmic" +#define AUDIO_PARAMETER_KEY_NO_FLUENCE "none" + +/* Query if surround sound recording is supported */ +#define AUDIO_PARAMETER_KEY_SSR "ssr" + +/* Query if a2dp is supported */ +#define AUDIO_PARAMETER_KEY_HANDLE_A2DP_DEVICE "isA2dpDeviceSupported" + +/* Query ADSP Status */ +#define AUDIO_PARAMETER_KEY_ADSP_STATUS "ADSP_STATUS" + +/* Query Sound Card Status */ +#define AUDIO_PARAMETER_KEY_SND_CARD_STATUS "SND_CARD_STATUS" + +/* Query if Proxy can be Opend */ +#define AUDIO_PARAMETER_KEY_CAN_OPEN_PROXY "can_open_proxy" + +#endif /* AUDIO_DEFS_H */ diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 7583f835..c9d805bf 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -29,7 +29,50 @@ #include "platform.h" #include "platform_api.h" +#include "sound/compress_params.h" +#ifndef COMPRESS_METADATA_NEEDED +#define audio_extn_parse_compress_metadata(out, parms) (0) +#else +int audio_extn_parse_compress_metadata(struct stream_out *out, + struct str_parms *parms) +{ + int ret = 0; + char value[32]; + +#ifdef FLAC_OFFLOAD_ENABLED + if (out->format == AUDIO_FORMAT_FLAC) { + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE, value, sizeof(value)); + if (ret >= 0) { + out->compr_config.codec->options.flac_dec.min_blk_size = atoi(value); + out->is_compr_metadata_avail = true; + } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE, value, sizeof(value)); + if (ret >= 0) { + out->compr_config.codec->options.flac_dec.max_blk_size = atoi(value); + out->is_compr_metadata_avail = true; + } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE, value, sizeof(value)); + if (ret >= 0) { + out->compr_config.codec->options.flac_dec.min_frame_size = atoi(value); + out->is_compr_metadata_avail = true; + } + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE, value, sizeof(value)); + if (ret >= 0) { + out->compr_config.codec->options.flac_dec.max_frame_size = atoi(value); + out->is_compr_metadata_avail = true; + } + ALOGV("FLAC metadata: min_blk_size %d, max_blk_size %d min_frame_size %d max_frame_size %d", + out->compr_config.codec->options.flac_dec.min_blk_size, + out->compr_config.codec->options.flac_dec.max_blk_size, + out->compr_config.codec->options.flac_dec.min_frame_size, + out->compr_config.codec->options.flac_dec.max_frame_size); + } +#endif + + return ret; +} +#endif #ifdef KPI_OPTIMIZE_ENABLED typedef int (*perf_lock_acquire_t)(int, int, int*, int); diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index c518faa7..3d3db003 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -25,6 +25,28 @@ void audio_extn_extspk_update(void* extn); void audio_extn_extspk_set_mode(void* extn, audio_mode_t mode); void audio_extn_extspk_set_voice_vol(void* extn, float vol); +#ifndef PCM_OFFLOAD_ENABLED +#define AUDIO_FORMAT_PCM_OFFLOAD 0x1A000000UL +#define AUDIO_FORMAT_PCM_16_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_16_BIT) +#define AUDIO_FORMAT_PCM_24_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_8_24_BIT) +#define AUDIO_OFFLOAD_CODEC_FORMAT "music_offload_codec_format" +#define audio_is_offload_pcm(format) (0) +#endif + +#ifndef FLAC_OFFLOAD_ENABLED +#define AUDIO_FORMAT_FLAC 0x1B000000UL +#endif + +#ifndef COMPRESS_METADATA_NEEDED +#define audio_extn_parse_compress_metadata(out, parms) (0) +#else +int audio_extn_parse_compress_metadata(struct stream_out *out, + struct str_parms *parms); +#endif + +#define AUDIO_OUTPUT_BIT_WIDTH ((config->offload_info.bit_width == 32) ? 24\ + :config->offload_info.bit_width) + #ifndef SPKR_PROT_ENABLED #define audio_extn_spkr_prot_init(adev) (0) #define audio_extn_spkr_prot_start_processing(snd_device) (-EINVAL) diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c index a1087309..f3075cfa 100644 --- a/hal/audio_extn/hfp.c +++ b/hal/audio_extn/hfp.c @@ -71,7 +71,11 @@ static int32_t hfp_set_volume(struct audio_device *adev, float value) { int32_t vol, ret = 0; struct mixer_ctl *ctl; +#ifdef EXTERNAL_BT_SUPPORTED + const char *mixer_ctl_name = "PRI AUXPCM LOOPBACK Volume"; +#else const char *mixer_ctl_name = "Internal HFP RX Volume"; +#endif ALOGV("%s: entry", __func__); ALOGD("%s: (%f)\n", __func__, value); @@ -115,6 +119,8 @@ static int32_t start_hfp(struct audio_device *adev, int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id; ALOGD("%s: enter", __func__); + adev->enable_hfp = true; + platform_set_mic_mute(adev->platform, false); uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); uc_info->id = hfpmod.ucid; @@ -238,6 +244,16 @@ static int32_t stop_hfp(struct audio_device *adev) disable_snd_device(adev, uc_info->out_snd_device); disable_snd_device(adev, uc_info->in_snd_device); + /* Disable the echo reference for HFP Tx */ + platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE); + + /* Set the unmute Tx mixer control */ + if (voice_get_mic_mute(adev)) { + platform_set_mic_mute(adev->platform, false); + ALOGD("%s: unMute HFP Tx", __func__); + } + adev->enable_hfp = false; + list_remove(&uc_info->list); free(uc_info); diff --git a/hal/audio_extn/sound_trigger_prop_intf.h b/hal/audio_extn/sound_trigger_prop_intf.h new file mode 100644 index 00000000..90a9aa97 --- /dev/null +++ b/hal/audio_extn/sound_trigger_prop_intf.h @@ -0,0 +1,61 @@ +/* + * Extrapolated / reversed header for Sound Trigger + */ + +#ifndef SOUND_TRIGGER_PROP_INTF_H +#define SOUND_TRIGGER_PROP_INTF_H + +struct sound_trigger_session_info { + int capture_handle; + struct pcm *pcm; + struct pcm_config config; +}; + +enum audio_event_type { + AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE, + AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE, + dummy1, + dummy2, + AUDIO_EVENT_STOP_LAB, + AUDIO_EVENT_SSR, + AUDIO_EVENT_NUM_ST_SESSIONS, + AUDIO_EVENT_READ_SAMPLES, +}; + +enum sound_trigger_event_type { + ST_EVENT_SESSION_REGISTER, + ST_EVENT_SESSION_DEREGISTER +}; +typedef enum sound_trigger_event_type sound_trigger_event_type_t; + +enum ssr_event_status { + SND_CARD_STATUS_OFFLINE, + SND_CARD_STATUS_ONLINE, + CPE_STATUS_OFFLINE, + CPE_STATUS_ONLINE +}; + +struct sound_trigger_event_info { + struct sound_trigger_session_info st_ses; +}; +typedef struct sound_trigger_event_info sound_trigger_event_info_t; + +struct audio_read_samples_info { + struct sound_trigger_session_info *ses_info; + void *buf; + size_t num_bytes; +}; + +struct audio_event_info { + union { + enum ssr_event_status status; + int value; + struct sound_trigger_session_info ses_info; + struct audio_read_samples_info aud_info; + }u; +}; +typedef struct audio_event_info audio_event_info_t; + +typedef int (*sound_trigger_hw_call_back_t)(enum audio_event_type, + struct audio_event_info*); +#endif diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c index b5475a17..1630b2df 100644 --- a/hal/audio_extn/soundtrigger.c +++ b/hal/audio_extn/soundtrigger.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 The Android Open Source Project + * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +15,7 @@ * limitations under the License. */ #define LOG_TAG "soundtrigger" -/* #define LOG_NDEBUG 0 */ +/*#define LOG_NDEBUG 0*/ #define LOG_NDDEBUG 0 #include <errno.h> @@ -133,15 +134,17 @@ int audio_extn_sound_trigger_read(struct stream_in *in, void *buffer, if (in->standby) in->standby = false; + ALOGD("audio_extn_sound_trigger_read"); + pthread_mutex_lock(&st_dev->lock); st_info = get_sound_trigger_info(in->capture_handle); - pthread_mutex_unlock(&st_dev->lock); if (st_info) { event.u.aud_info.ses_info = &st_info->st_ses; event.u.aud_info.buf = buffer; event.u.aud_info.num_bytes = bytes; ret = st_dev->st_callback(AUDIO_EVENT_READ_SAMPLES, &event); } + pthread_mutex_unlock(&st_dev->lock); exit: if (ret) { @@ -149,7 +152,7 @@ exit: in->is_st_session_active = false; memset(buffer, 0, bytes); ALOGV("%s: read failed status %d - sleep", __func__, ret); - usleep((bytes * 1000000) / (audio_stream_in_frame_size((struct audio_stream_in *)in) * + usleep(((int64_t)bytes * 1000000) / (audio_stream_in_frame_size((struct audio_stream_in *)in) * in->config.rate)); } return ret; @@ -161,17 +164,20 @@ void audio_extn_sound_trigger_stop_lab(struct stream_in *in) struct sound_trigger_info *st_ses_info = NULL; audio_event_info_t event; - if (!st_dev || !in) + if (!st_dev || !in || !in->is_st_session_active) return; + ALOGD("audio_extn_sound_trigger_stop_lab"); + pthread_mutex_lock(&st_dev->lock); st_ses_info = get_sound_trigger_info(in->capture_handle); - pthread_mutex_unlock(&st_dev->lock); if (st_ses_info) { event.u.ses_info = st_ses_info->st_ses; ALOGV("%s: AUDIO_EVENT_STOP_LAB pcm %p", __func__, st_ses_info->st_ses.pcm); st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event); + in->is_st_session_active = false; } + pthread_mutex_unlock(&st_dev->lock); } void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in) { @@ -225,6 +231,7 @@ void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device, ALOGI("%s: device 0x%x of type %d for Event %d", __func__, snd_device, device_type, event); if (device_type == PCM_CAPTURE) { + pthread_mutex_lock(&st_dev->lock); switch(event) { case ST_EVENT_SND_DEVICE_FREE: st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE, NULL); @@ -236,6 +243,7 @@ void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device, ALOGW("%s:invalid event %d for device 0x%x", __func__, event, snd_device); } + pthread_mutex_unlock(&st_dev->lock); }/*Events for output device, if required can be placed here in else*/ } @@ -251,6 +259,7 @@ void audio_extn_sound_trigger_set_parameters(struct audio_device *adev __unused, return; } + pthread_mutex_lock(&st_dev->lock); ret = str_parms_get_str(params, "SND_CARD_STATUS", value, sizeof(value)); if (ret > 0) { @@ -285,6 +294,7 @@ void audio_extn_sound_trigger_set_parameters(struct audio_device *adev __unused, event.u.value = val; st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event); } + pthread_mutex_unlock(&st_dev->lock); } int audio_extn_sound_trigger_init(struct audio_device *adev) diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c index 4d8b2337..3f9a654b 100644 --- a/hal/audio_extn/spkr_protection.c +++ b/hal/audio_extn/spkr_protection.c @@ -338,6 +338,7 @@ static int spkr_calibrate(int t0) uc_info_rx->out_snd_device = SND_DEVICE_OUT_SPEAKER_PROTECTED; disable_rx = true; list_add_tail(&adev->usecase_list, &uc_info_rx->list); + platform_check_and_set_codec_backend_cfg(adev, uc_info_rx); enable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED); enable_audio_route(adev, uc_info_rx); diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 2e954d67..ada5ecec 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -1,5 +1,8 @@ /* - * Copyright (C) 2013-2014 The Android Open Source Project + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,12 +54,13 @@ #include "voice_extn.h" #include "sound/compress_params.h" +#include "sound/asound.h" #define COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024) // 2 buffers causes problems with high bitrate files #define COMPRESS_OFFLOAD_NUM_FRAGMENTS 3 /* ToDo: Check and update a proper value in msec */ -#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96 +#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 #define PROXY_OPEN_RETRY_COUNT 100 @@ -222,15 +226,24 @@ bool audio_hw_send_gain_dep_calibration(int level) { static bool is_supported_format(audio_format_t format) { - switch (format) { - case AUDIO_FORMAT_MP3: - case AUDIO_FORMAT_AAC_LC: - case AUDIO_FORMAT_AAC_HE_V1: - case AUDIO_FORMAT_AAC_HE_V2: - return true; - default: - break; - } + if (format == AUDIO_FORMAT_MP3 || + format == AUDIO_FORMAT_AAC || + format == AUDIO_FORMAT_AAC_LC || + format == AUDIO_FORMAT_AAC_HE_V1 || + format == AUDIO_FORMAT_AAC_HE_V2) + return true; + +#ifdef PCM_OFFLOAD_ENABLED + if (format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD || + format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) + return true; +#endif + +#ifdef FLAC_OFFLOAD_ENABLED + if (format == AUDIO_FORMAT_FLAC) + return true; +#endif + return false; } @@ -245,8 +258,19 @@ static int get_snd_codec_id(audio_format_t format) case AUDIO_FORMAT_AAC: id = SND_AUDIOCODEC_AAC; break; +#ifdef PCM_OFFLOAD_ENABLED + case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD: + case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD: + id = SND_AUDIOCODEC_PCM; + break; +#endif +#ifdef FLAC_OFFLOAD_ENABLED + case AUDIO_FORMAT_FLAC: + id = SND_AUDIOCODEC_FLAC; + break; +#endif default: - ALOGE("%s: Unsupported audio format", __func__); + ALOGE("%s: Unsupported audio format %x", __func__, format); } return id; @@ -312,8 +336,6 @@ int enable_snd_device(struct audio_device *adev, return -EINVAL; } - platform_send_audio_calibration(adev->platform, snd_device); - adev->snd_dev_ref_cnt[snd_device]++; if (adev->snd_dev_ref_cnt[snd_device] > 1) { ALOGV("%s: snd_device(%d: %s) is already active", @@ -321,11 +343,6 @@ int enable_snd_device(struct audio_device *adev, return 0; } - /* due to the possibility of calibration overwrite between listen - and audio, notify sound trigger hal before audio calibration is sent */ - audio_extn_sound_trigger_update_device_status(snd_device, - ST_EVENT_SND_DEVICE_BUSY); - if (audio_extn_spkr_prot_is_enabled()) audio_extn_spkr_prot_calib_cancel(adev); @@ -335,12 +352,11 @@ int enable_snd_device(struct audio_device *adev, snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) && audio_extn_spkr_prot_is_enabled()) { if (audio_extn_spkr_prot_get_acdb_id(snd_device) < 0) { - adev->snd_dev_ref_cnt[snd_device]--; - return -EINVAL; + goto out_error; } if (audio_extn_spkr_prot_start_processing(snd_device)) { ALOGE("%s: spkr_start_processing failed", __func__); - return -EINVAL; + goto out_error; } } else if (platform_can_split_snd_device(snd_device, &num_devices, new_snd_devices)) { for (i = 0; i < num_devices; i++) { @@ -349,11 +365,21 @@ int enable_snd_device(struct audio_device *adev, platform_set_speaker_gain_in_combo(adev, snd_device, true); } else { const char * dev_path = platform_get_snd_device_name(snd_device); - ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, dev_path); + audio_extn_sound_trigger_update_device_status(snd_device, + ST_EVENT_SND_DEVICE_BUSY); + /* due to the possibility of calibration overwrite between listen + and audio, notify sound trigger hal before audio calibration is sent */ + ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, dev_path); + platform_send_audio_calibration(adev->platform, snd_device); audio_route_apply_and_update_path(adev->audio_route, dev_path); } return 0; + +out_error: + adev->snd_dev_ref_cnt[snd_device]--; + audio_extn_sound_trigger_update_device_status(snd_device, ST_EVENT_SND_DEVICE_FREE); + return -EINVAL; } int disable_snd_device(struct audio_device *adev, @@ -415,6 +441,15 @@ static void check_and_route_playback_usecases(struct audio_device *adev, * because of the limitation that both the devices cannot be enabled * at the same time as they share the same backend. */ + /* + * This call is to check if we need to force routing for a particular stream + * If there is a backend configuration change for the device when a + * new stream starts, then ADM needs to be closed and re-opened with the new + * configuraion. This call check if we need to re-route all the streams + * associated with the backend. Touch tone + 24 bit playback. + */ + bool force_routing = platform_check_and_set_codec_backend_cfg(adev, uc_info); + /* Disable all the usecases on the shared backend other than the specified usecase */ for (i = 0; i < AUDIO_USECASE_MAX; i++) @@ -424,7 +459,7 @@ static void check_and_route_playback_usecases(struct audio_device *adev, usecase = node_to_item(node, struct audio_usecase, list); if (usecase->type != PCM_CAPTURE && usecase != uc_info && - usecase->out_snd_device != snd_device && + (usecase->out_snd_device != snd_device || force_routing) && usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND && platform_check_backends_match(snd_device, usecase->out_snd_device)) { ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..", @@ -845,7 +880,13 @@ int start_input_stream(struct stream_in *in) } ALOGV("%s: pcm_prepare start", __func__); - pcm_prepare(in->pcm); + ret = pcm_prepare(in->pcm); + if (ret < 0) { + ALOGE("%s: pcm_prepare returned %d", __func__, ret); + pcm_close(in->pcm); + in->pcm = NULL; + goto error_open; + } audio_extn_perf_lock_release(); @@ -909,6 +950,7 @@ static void *offload_thread_loop(void *context) { struct stream_out *out = (struct stream_out *) context; struct listnode *item; + int ret = 0; out->offload_state = OFFLOAD_STATE_IDLE; out->playback_started = 0; @@ -961,12 +1003,24 @@ static void *offload_thread_loop(void *context) event = STREAM_CBK_EVENT_WRITE_READY; break; case OFFLOAD_CMD_PARTIAL_DRAIN: - compress_next_track(out->compr); - compress_partial_drain(out->compr); + ret = compress_next_track(out->compr); + if(ret == 0) { + ALOGD("copl(%p):calling compress_partial_drain", out); + compress_partial_drain(out->compr); + ALOGD("copl(%p):out of compress_partial_drain", out); + } + else if(ret == -ETIMEDOUT) + compress_drain(out->compr); + else + ALOGE("%s: Next track returned error %d",__func__, ret); + send_callback = true; event = STREAM_CBK_EVENT_DRAIN_READY; + pthread_mutex_lock(&out->lock); /* Resend the metadata for next iteration */ out->send_new_metadata = 1; + out->send_next_track_params = true; + pthread_mutex_unlock(&out->lock); break; case OFFLOAD_CMD_DRAIN: compress_drain(out->compr); @@ -980,7 +1034,7 @@ static void *offload_thread_loop(void *context) lock_output_stream(out); out->offload_thread_blocked = false; pthread_cond_signal(&out->cond); - if (send_callback) { + if (send_callback && out->offload_callback) { ALOGVV("%s: sending offload_callback event %d", __func__, event); out->offload_callback(event, NULL, out->offload_cookie); } @@ -1204,9 +1258,15 @@ int start_output_stream(struct stream_out *out) break; } ALOGV("%s: pcm_prepare start", __func__); - if (pcm_is_ready(out->pcm)) - pcm_prepare(out->pcm); - + if (pcm_is_ready(out->pcm)) { + ret = pcm_prepare(out->pcm); + if (ret < 0) { + ALOGE("%s: pcm_prepare returned %d", __func__, ret); + pcm_close(out->pcm); + out->pcm = NULL; + goto error_open; + } + } } else { out->pcm = NULL; out->compr = compress_open(adev->snd_card, out->pcm_device_id, @@ -1218,6 +1278,9 @@ int start_output_stream(struct stream_out *out) ret = -EIO; goto error_open; } + /* compress_open sends params of the track, so reset the flag here */ + out->is_compr_metadata_avail = false; + if (out->offload_callback) compress_nonblock(out->compr, out->non_blocking); @@ -1362,6 +1425,8 @@ static int out_standby(struct audio_stream *stream) } } else { stop_compressed_output_l(out); + out->send_next_track_params = false; + out->is_compr_metadata_avail = false; out->gapless_mdata.encoder_delay = 0; out->gapless_mdata.encoder_padding = 0; if (out->compr != NULL) { @@ -1386,28 +1451,23 @@ static int parse_compress_metadata(struct stream_out *out, struct str_parms *par { int ret = 0; char value[32]; - struct compr_gapless_mdata tmp_mdata; if (!out || !parms) { + ALOGE("%s: return invalid ",__func__); return -EINVAL; } + ret = audio_extn_parse_compress_metadata(out, parms); + ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value)); if (ret >= 0) { - tmp_mdata.encoder_delay = atoi(value); //whats a good limit check? - } else { - return -EINVAL; + out->gapless_mdata.encoder_delay = atoi(value); //whats a good limit check? } - ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value)); if (ret >= 0) { - tmp_mdata.encoder_padding = atoi(value); - } else { - return -EINVAL; + out->gapless_mdata.encoder_padding = atoi(value); } - out->gapless_mdata = tmp_mdata; - out->send_new_metadata = 1; ALOGV("%s new encoder delay %u and padding %u", __func__, out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding); @@ -1497,7 +1557,9 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) } if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + pthread_mutex_lock(&out->lock); parse_compress_metadata(out, parms); + pthread_mutex_unlock(&out->lock); } str_parms_destroy(parms); @@ -1547,12 +1609,17 @@ static char* out_get_parameters(const struct audio_stream *stream, const char *k static uint32_t out_get_latency(const struct audio_stream_out *stream) { struct stream_out *out = (struct stream_out *)stream; + uint32_t latency = 0; - if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) - return COMPRESS_OFFLOAD_PLAYBACK_LATENCY; - - return (out->config.period_count * out->config.period_size * 1000) / + if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { + latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY; + } else { + latency = (out->config.period_count * out->config.period_size * 1000) / (out->config.rate); + } + + ALOGV("%s: Latency %d", __func__, latency); + return latency; } static int out_set_volume(struct audio_stream_out *stream, float left, @@ -1602,7 +1669,7 @@ static ssize_t out_write_for_no_output(struct audio_stream_out *stream, * Sleep for the amount of buffer duration */ lock_output_stream(out); - usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) / + usleep((uint64_t)bytes * 1000000 / audio_stream_out_frame_size(&out->stream.common) / out_get_sample_rate(&out->stream.common)); pthread_mutex_unlock(&out->lock); return bytes; @@ -1632,14 +1699,22 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, } if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { - ALOGVV("%s: writing buffer (%d bytes) to compress device", __func__, bytes); + ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes); if (out->send_new_metadata) { ALOGVV("send new gapless metadata"); compress_set_gapless_metadata(out->compr, &out->gapless_mdata); out->send_new_metadata = 0; + if (out->send_next_track_params && out->is_compr_metadata_avail) { + ALOGD("copl(%p):send next track params in gapless", out); + compress_set_next_track_param(out->compr, &(out->compr_config.codec->options)); + out->send_next_track_params = false; + out->is_compr_metadata_avail = false; + } } ret = compress_write(out->compr, buffer, bytes); + if (ret < 0) + ret = -errno; ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret); if (ret >= 0 && ret < (ssize_t)bytes) { send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER); @@ -1666,7 +1741,9 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, else ret = pcm_write(out->pcm, (void *)buffer, bytes); - if (ret == 0) + if (ret < 0) + ret = -errno; + else if (ret == 0) out->written += bytes / (out->config.channels * sizeof(short)); if (adev->adm_abandon_focus) @@ -1691,19 +1768,22 @@ static int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames) { struct stream_out *out = (struct stream_out *)stream; + ssize_t ret = 0; *dsp_frames = 0; if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) { lock_output_stream(out); if (out->compr != NULL) { - compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, + ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, &out->sample_rate); + if (ret < 0) + ret = -errno; ALOGVV("%s rendered frames %d sample_rate %d", __func__, *dsp_frames, out->sample_rate); } pthread_mutex_unlock(&out->lock); return 0; - } else - return -EINVAL; + } + return ret; } static int out_add_audio_effect(const struct audio_stream *stream __unused, @@ -1935,11 +2015,13 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) ALOGV("%s: enter: kvpairs=%s", __func__, kvpairs); parms = str_parms_create_str(kvpairs); - ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value)); - + if (!parms) + goto error; lock_input_stream(in); - pthread_mutex_lock(&adev->lock); + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value)); + if (ret >= 0) { val = atoi(value); /* no audio source uses val == 0 */ @@ -1955,7 +2037,7 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) if (((int)in->device != val) && (val != 0)) { in->device = val; /* If recording is in progress, change the tx device to new device */ - if (!in->standby) + if (!in->standby && !in->is_st_session) status = select_devices(adev, in->usecase); } } @@ -1964,6 +2046,8 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) pthread_mutex_unlock(&in->lock); str_parms_destroy(parms); + +error: ALOGV("%s: exit: status(%d)", __func__, status); return status; } @@ -1971,7 +2055,20 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) static char* in_get_parameters(const struct audio_stream *stream __unused, const char *keys __unused) { - return strdup(""); + struct str_parms *reply = str_parms_create_str(keys); + char *str; + + if (!reply) { + ALOGE("in_get_parameters: failed to create query or reply"); + return NULL; + } + + ALOGV("%s: enter: keys - %s", __func__, keys); + + str = str_parms_to_str(reply); + str_parms_destroy(reply); + + return str; } static int in_set_gain(struct audio_stream_in *stream __unused, float gain __unused) @@ -2014,8 +2111,13 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, if (in->pcm) { if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) { ret = pcm_mmap_read(in->pcm, buffer, bytes); - } else + } else { + ALOGVV("%s: reading buffer (%d bytes) from pcm device (handle=%d)", __func__, + bytes, in->capture_handle); ret = pcm_read(in->pcm, buffer, bytes); + } + if (ret < 0) + ret = -errno; } if (adev->adm_abandon_focus) @@ -2033,9 +2135,10 @@ exit: pthread_mutex_unlock(&in->lock); if (ret != 0) { + memset(buffer, 0, bytes); in_standby(&in->stream.common); ALOGV("%s: read failed - sleeping for buffer duration", __func__); - usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) / + usleep((uint64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) / in_get_sample_rate(&in->stream.common)); } return bytes; @@ -2117,13 +2220,23 @@ static int adev_open_output_stream(struct audio_hw_device *dev, { struct audio_device *adev = (struct audio_device *)dev; struct stream_out *out; - int i, ret; + int i, ret = 0; + int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)", __func__, config->sample_rate, config->channel_mask, devices, flags); *stream_out = NULL; out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); + if (!out) { + return -ENOMEM; + } + + pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); + pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL); + pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); + + if (devices == AUDIO_DEVICE_NONE) devices = AUDIO_DEVICE_OUT_SPEAKER; @@ -2135,6 +2248,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->channel_mask = AUDIO_CHANNEL_OUT_STEREO; out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO; out->handle = handle; + out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; + out->non_blocking = 0; + out->use_small_bufs = false; /* Init use case and pcm_config */ if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT && @@ -2177,8 +2293,10 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD; if (config->offload_info.channel_mask) out->channel_mask = config->offload_info.channel_mask; - else if (config->channel_mask) + else if (config->channel_mask) { out->channel_mask = config->channel_mask; + config->offload_info.channel_mask = config->channel_mask; + } out->format = config->offload_info.format; out->sample_rate = config->offload_info.sample_rate; @@ -2187,10 +2305,18 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.resume = out_resume; out->stream.drain = out_drain; out->stream.flush = out_flush; + out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format); - out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; +#ifdef PCM_OFFLOAD_ENABLED + if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM_OFFLOAD) + out->compr_config.fragment_size = + platform_get_pcm_offload_buffer_size(&config->offload_info); + else +#endif + out->compr_config.fragment_size = + platform_get_compress_offload_buffer_size(&config->offload_info); out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; out->compr_config.codec->sample_rate = config->offload_info.sample_rate; out->compr_config.codec->bit_rate = @@ -2198,11 +2324,35 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->compr_config.codec->ch_in = audio_channel_count_from_out_mask(config->channel_mask); out->compr_config.codec->ch_out = out->compr_config.codec->ch_in; + out->bit_width = AUDIO_OUTPUT_BIT_WIDTH; + + if (config->offload_info.format == AUDIO_FORMAT_AAC) + out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW; + +#ifdef PCM_OFFLOAD_ENABLED + if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD) + out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE; + if(config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) + out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE; + if (out->bit_width == 24) { + out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE; + } +#endif + +#ifdef FLAC_OFFLOAD_ENABLED + if (config->offload_info.format == AUDIO_FORMAT_FLAC) + out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH; +#endif if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) out->non_blocking = 1; out->send_new_metadata = 1; + out->send_next_track_params = false; + out->is_compr_metadata_avail = false; + out->offload_state = OFFLOAD_STATE_IDLE; + out->playback_started = 0; + create_offload_callback_thread(out); ALOGV("%s: offloaded output offload_info version %04x bit rate %d", __func__, config->offload_info.version, @@ -2263,8 +2413,17 @@ static int adev_open_output_stream(struct audio_hw_device *dev, ALOGV("%s: Usecase(%s) config->format %#x out->config.format %#x\n", __func__, use_case_table[out->usecase], config->format, out->config.format); + if ((24 == out->bit_width) && + (devices == AUDIO_DEVICE_OUT_SPEAKER)) { + sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; + ALOGI("%s 24-bit playback on Speaker is allowed ONLY at 48khz. Hence changing sample rate to: %d", + __func__, sample_rate); + } else { + sample_rate = out->sample_rate; + } + if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { - if (adev->primary_output == NULL) + if(adev->primary_output == NULL) adev->primary_output = out; else { ALOGE("%s: Primary output is already opened", __func__); @@ -2310,10 +2469,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, /* out->muted = false; by calloc() */ /* out->written = 0; by calloc() */ - pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); - pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL); - pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL); - config->format = out->stream.common.get_format(&out->stream.common); config->channel_mask = out->stream.common.get_channels(&out->stream.common); config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common); @@ -2419,6 +2574,8 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) } audio_extn_hfp_set_parameters(adev, parms); + audio_extn_sound_trigger_set_parameters(adev, parms); + done: str_parms_destroy(parms); pthread_mutex_unlock(&adev->lock); @@ -2643,9 +2800,16 @@ err_open: static void adev_close_input_stream(struct audio_hw_device *dev __unused, struct audio_stream_in *stream) { + struct stream_in *in = (struct stream_in *)stream; + ALOGV("%s", __func__); in_standby(&stream->common); + + if (in->is_st_session) { + ALOGV("%s: sound trigger pcm stop lab", __func__); + audio_extn_sound_trigger_stop_lab(in); + } free(stream); return; @@ -2891,6 +3055,8 @@ static int adev_open(const hw_module_t *module, const char *name, adev->bluetooth_nrec = true; adev->acdb_settings = TTY_MODE_OFF; /* adev->cur_hdmi_channels = 0; by calloc() */ + adev->cur_codec_backend_samplerate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE; + adev->cur_codec_backend_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int)); voice_init(adev); list_init(&adev->usecase_list); diff --git a/hal/audio_hw.h b/hal/audio_hw.h index b82ee8b1..e5a94e62 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -25,6 +25,7 @@ #include <tinycompress/tinycompress.h> #include <audio_route/audio_route.h> +#include "audio_defs.h" #include "voice.h" #define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so" @@ -146,6 +147,7 @@ struct stream_out { audio_io_handle_t handle; int non_blocking; + bool use_small_bufs; int playback_started; int offload_state; pthread_cond_t offload_cond; @@ -157,6 +159,9 @@ struct stream_out { void *offload_cookie; struct compr_gapless_mdata gapless_mdata; int send_new_metadata; + bool send_next_track_params; + bool is_compr_metadata_avail; + unsigned int bit_width; struct audio_device *dev; }; @@ -234,8 +239,11 @@ struct audio_device { bool bt_wb_speech_enabled; bool mic_muted; bool enable_voicerx; + bool enable_hfp; int snd_card; + unsigned int cur_codec_backend_samplerate; + unsigned int cur_codec_backend_bit_width; void *platform; void *extspk; diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index 0ffe8a98..4988dbe5 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -1087,3 +1087,11 @@ bool platform_check_backends_match(snd_device_t snd_device1 __unused, { return true; } + +bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase) { + return false; +} + +uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info) { + return 0; +} diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index c856bb0a..fbe70c29 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -27,13 +27,32 @@ #include "platform.h" #include "audio_extn.h" #include <linux/msm_audio.h> +#include "sound/compress_params.h" #define MIXER_XML_PATH "/system/etc/mixer_paths.xml" +#define MIXER_XML_PATH_WCD9330 "/system/etc/mixer_paths_wcd9330.xml" #define LIB_ACDB_LOADER "libacdbloader.so" #define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID" #define CVD_VERSION_MIXER_CTL "CVD Version" +#define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024) +#define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024) +#define COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING (2 * 1024) +#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024) + +/* Used in calculating fragment size for pcm offload */ +#define PCM_OFFLOAD_BUFFER_DURATION 40 /* 40 millisecs */ + +/* MAX PCM fragment size cannot be increased further due + * to flinger's cblk size of 1mb,and it has to be a multiple of + * 24 - lcm of channels supported by DSP + */ +#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024) +#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (32 * 1024) + +#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y)) +#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y))) /* * This file will have a maximum of 38 bytes: * @@ -201,6 +220,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_TX] = "voice-tx", [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected", [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected", + [SND_DEVICE_OUT_VOICE_SPEAKER_HFP] = "voice-speaker-hfp", /* Capture sound devices */ [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic", @@ -237,6 +257,7 @@ static const char * const device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_DMIC_TMUS] = "voice-dmic-ef-tmus", [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = "voice-speaker-mic", [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef", + [SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP] = "voice-speaker-mic-hfp", [SND_DEVICE_IN_VOICE_HEADSET_MIC] = "voice-headset-mic", [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic", [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic", @@ -286,6 +307,7 @@ static int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_OUT_VOICE_TX] = 45, [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124, [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101, + [SND_DEVICE_OUT_VOICE_SPEAKER_HFP] = ACDB_ID_VOICE_SPEAKER, [SND_DEVICE_IN_HANDSET_MIC] = 4, [SND_DEVICE_IN_HANDSET_MIC_AEC] = 106, @@ -320,6 +342,7 @@ static int acdb_device_table[SND_DEVICE_MAX] = { [SND_DEVICE_IN_VOICE_DMIC] = 41, [SND_DEVICE_IN_VOICE_DMIC_TMUS] = ACDB_ID_VOICE_DMIC_EF_TMUS, [SND_DEVICE_IN_VOICE_SPEAKER_MIC] = 11, + [SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP] = 11, [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43, [SND_DEVICE_IN_VOICE_HEADSET_MIC] = 8, [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16, @@ -363,6 +386,7 @@ static const struct name_to_index snd_device_name_index[SND_DEVICE_MAX] = { {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_SAFE_AND_LINE)}, {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HANDSET)}, {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER)}, + {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_HFP)}, {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HEADPHONES)}, {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_LINE)}, {TO_NAME_INDEX(SND_DEVICE_OUT_HDMI)}, @@ -411,6 +435,7 @@ static const struct name_to_index snd_device_name_index[SND_DEVICE_MAX] = { {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_DMIC)}, {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_DMIC_TMUS)}, {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_MIC)}, + {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP)}, {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_DMIC)}, {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_HEADSET_MIC)}, {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC)}, @@ -948,7 +973,15 @@ void *platform_init(struct audio_device *adev) ALOGD("%s: snd_card_name: %s", __func__, snd_card_name); - adev->audio_route = audio_route_init(snd_card_num, MIXER_XML_PATH); + if (!strncmp(snd_card_name, "msm8226-tomtom-snd-card", + sizeof("msm8226-tomtom-snd-card"))) { + ALOGD("%s: Call MIXER_XML_PATH_WCD9330", __func__); + adev->audio_route = audio_route_init(snd_card_num, + MIXER_XML_PATH_WCD9330); + } else { + adev->audio_route = audio_route_init(snd_card_num, MIXER_XML_PATH); + } + if (!adev->audio_route) { ALOGE("%s: Failed to init audio route controls, aborting.", __func__); goto init_failed; @@ -1592,9 +1625,13 @@ int platform_set_mic_mute(void *platform, bool state) ALL_SESSION_VSID, DEFAULT_MUTE_RAMP_DURATION_MS}; - if (adev->mode != AUDIO_MODE_IN_CALL) + if (adev->mode != AUDIO_MODE_IN_CALL && + adev->mode != AUDIO_MODE_IN_COMMUNICATION) return 0; + if (adev->enable_hfp) + mixer_ctl_name = "HFP Tx Mute"; + set_values[0] = state; ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); if (!ctl) { @@ -1770,7 +1807,11 @@ snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devi snd_device = SND_DEVICE_OUT_BT_SCO; } } else if (devices & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE)) { - snd_device = SND_DEVICE_OUT_VOICE_SPEAKER; + if (!adev->enable_hfp) { + snd_device = SND_DEVICE_OUT_VOICE_SPEAKER; + } else { + snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_HFP; + } } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) { if(adev->voice.hac) snd_device = SND_DEVICE_OUT_VOICE_HAC_HANDSET; @@ -1896,7 +1937,12 @@ snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_d //select default if (snd_device == SND_DEVICE_NONE) { - snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC; + if (!adev->enable_hfp) { + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC; + } else { + snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP; + platform_set_echo_reference(adev, true, out_device); + } } } else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX) { snd_device = SND_DEVICE_IN_VOICE_RX; @@ -2513,3 +2559,240 @@ int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels) } return 0; } + +/* Read offload buffer size from a property. + * If value is not power of 2 round it to + * power of 2. + */ +uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info) +{ + char value[PROPERTY_VALUE_MAX] = {0}; + uint32_t fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE; + if((property_get("audio.offload.buffer.size.kb", value, "")) && + atoi(value)) { + fragment_size = atoi(value) * 1024; + } + +#ifdef FLAC_OFFLOAD_ENABLED + // For FLAC use max size since it is loss less, and has sampling rates + // upto 192kHZ + if (info != NULL && !info->has_video && + info->format == AUDIO_FORMAT_FLAC) { + fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE; + ALOGV("FLAC fragment size %d", fragment_size); + } +#endif + + if (info != NULL && info->has_video && info->is_streaming) { + fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING; + ALOGV("%s: offload fragment size reduced for AV streaming to %d", + __func__, fragment_size); + } + + fragment_size = ALIGN( fragment_size, 1024); + + if(fragment_size < MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE; + else if(fragment_size > MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE; + ALOGV("%s: fragment_size %d", __func__, fragment_size); + return fragment_size; +} + +#ifdef PCM_OFFLOAD_ENABLED +uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info) +{ + uint32_t fragment_size = 0; + uint32_t bits_per_sample = 16; + uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION; + + if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) { + bits_per_sample = 32; + } + + //duration is set to 40 ms worth of stereo data at 48Khz + //with 16 bit per sample, modify this when the channel + //configuration is different + fragment_size = (pcm_offload_time + * info->sample_rate + * (bits_per_sample >> 3) + * popcount(info->channel_mask))/1000; + // To have same PCM samples for all channels, the buffer size requires to + // be multiple of (number of channels * bytes per sample) + // For writes to succeed, the buffer must be written at address which is multiple of 32 + // Alignment of 96 satsfies both of the above requirements + fragment_size = ALIGN(fragment_size, 96); + if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE; + else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE) + fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE; + + ALOGI("PCM offload Fragment size to %d bytes", fragment_size); + return fragment_size; +} +#endif + +int platform_set_codec_backend_cfg(struct audio_device* adev, + unsigned int bit_width, unsigned int sample_rate) +{ + ALOGV("%s bit width: %d, sample rate: %d", __func__, bit_width, sample_rate); + + int ret = 0; + if (bit_width != adev->cur_codec_backend_bit_width) { + const char * mixer_ctl_name = "SLIM_0_RX Format"; + struct mixer_ctl *ctl; + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if (!ctl) { + ALOGE("%s: Could not get ctl for mixer command - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + + if (bit_width == 24) { + mixer_ctl_set_enum_by_string(ctl, "S24_LE"); + } else { + mixer_ctl_set_enum_by_string(ctl, "S16_LE"); + sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE; + } + adev->cur_codec_backend_bit_width = bit_width; + ALOGE("Backend bit width is set to %d ", bit_width); + } + + /* + * Backend sample rate configuration follows: + * 16 bit playback - 48khz for streams at any valid sample rate + * 24 bit playback - 48khz for stream sample rate less than 48khz + * 24 bit playback - 96khz for sample rate range of 48khz to 96khz + * 24 bit playback - 192khz for sample rate range of 96khz to 192 khz + * Upper limit is inclusive in the sample rate range. + */ + // TODO: This has to be more dynamic based on policy file + if (sample_rate != adev->cur_codec_backend_samplerate) { + char *rate_str = NULL; + const char * mixer_ctl_name = "SLIM_0_RX SampleRate"; + struct mixer_ctl *ctl; + + switch (sample_rate) { + case 8000: + case 11025: + case 16000: + case 22050: + case 32000: + case 44100: + case 48000: + rate_str = "KHZ_48"; + break; + case 64000: + case 88200: + case 96000: + rate_str = "KHZ_96"; + break; + case 176400: + case 192000: + rate_str = "KHZ_192"; + break; + default: + rate_str = "KHZ_48"; + break; + } + + ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); + if(!ctl) { + ALOGE("%s: Could not get ctl for mixer command - %s", + __func__, mixer_ctl_name); + return -EINVAL; + } + + ALOGV("Set sample rate as rate_str = %s", rate_str); + mixer_ctl_set_enum_by_string(ctl, rate_str); + adev->cur_codec_backend_samplerate = sample_rate; + } + + return ret; +} + +bool platform_check_codec_backend_cfg(struct audio_device* adev, + struct audio_usecase* usecase, + unsigned int* new_bit_width, + unsigned int* new_sample_rate) +{ + bool backend_change = false; + struct listnode *node; + struct stream_out *out = NULL; + unsigned int bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; + unsigned int sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE; + + // For voice calls use default configuration + // force routing is not required here, caller will do it anyway + if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) { + ALOGW("%s:Use default bw and sr for voice/voip calls ",__func__); + bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; + sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE; + } else { + /* + * The backend should be configured at highest bit width and/or + * sample rate amongst all playback usecases. + * If the selected sample rate and/or bit width differ with + * current backend sample rate and/or bit width, then, we set the + * backend re-configuration flag. + * + * Exception: 16 bit playbacks is allowed through 16 bit/48 khz backend only + */ + list_for_each(node, &adev->usecase_list) { + struct audio_usecase *curr_usecase; + curr_usecase = node_to_item(node, struct audio_usecase, list); + if (curr_usecase->type == PCM_PLAYBACK) { + struct stream_out *out = + (struct stream_out*) curr_usecase->stream.out; + if (out != NULL ) { + ALOGV("Offload playback running bw %d sr %d", + out->bit_width, out->sample_rate); + if (bit_width < out->bit_width) + bit_width = out->bit_width; + if (sample_rate < out->sample_rate) + sample_rate = out->sample_rate; + } + } + } + } + + // 24 bit playback on speakers and all 16 bit playbacks is allowed through + // 16 bit/48 khz backend only + if ((16 == bit_width) || + ((24 == bit_width) && + (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER))) { + sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE; + } + // Force routing if the expected bitwdith or samplerate + // is not same as current backend comfiguration + if ((bit_width != adev->cur_codec_backend_bit_width) || + (sample_rate != adev->cur_codec_backend_samplerate)) { + *new_bit_width = bit_width; + *new_sample_rate = sample_rate; + backend_change = true; + ALOGI("%s Codec backend needs to be updated. new bit width: %d new sample rate: %d", + __func__, *new_bit_width, *new_sample_rate); + } + + return backend_change; +} + +bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase) +{ + ALOGV("platform_check_and_set_codec_backend_cfg usecase = %d",usecase->id ); + + unsigned int new_bit_width, old_bit_width; + unsigned int new_sample_rate, old_sample_rate; + + new_bit_width = old_bit_width = adev->cur_codec_backend_bit_width; + new_sample_rate = old_sample_rate = adev->cur_codec_backend_samplerate; + + ALOGW("Codec backend bitwidth %d, samplerate %d", old_bit_width, old_sample_rate); + if (platform_check_codec_backend_cfg(adev, usecase, + &new_bit_width, &new_sample_rate)) { + platform_set_codec_backend_cfg(adev, new_bit_width, new_sample_rate); + return true; + } + + return false; +} diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h index 4b4332e0..dcd763a9 100644 --- a/hal/msm8974/platform.h +++ b/hal/msm8974/platform.h @@ -77,6 +77,7 @@ enum { SND_DEVICE_OUT_VOICE_TX, SND_DEVICE_OUT_SPEAKER_PROTECTED, SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED, + SND_DEVICE_OUT_VOICE_SPEAKER_HFP, SND_DEVICE_OUT_END, /* @@ -118,6 +119,7 @@ enum { SND_DEVICE_IN_VOICE_DMIC, SND_DEVICE_IN_VOICE_DMIC_TMUS, SND_DEVICE_IN_VOICE_SPEAKER_MIC, + SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP, SND_DEVICE_IN_VOICE_SPEAKER_DMIC, SND_DEVICE_IN_VOICE_HEADSET_MIC, SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC, @@ -204,18 +206,36 @@ enum { #define LOWLATENCY_PCM_DEVICE 15 #define VOICE_VSID 0x10C01000 +#ifdef PLATFORM_MSM8x26 +#define VOICE_CALL_PCM_DEVICE 2 +#define VOICE2_CALL_PCM_DEVICE 14 +#define VOLTE_CALL_PCM_DEVICE 17 +#define QCHAT_CALL_PCM_DEVICE 18 +#define VOWLAN_CALL_PCM_DEVICE 30 +#elif PLATFORM_MSM8084 +#define VOICE_CALL_PCM_DEVICE 20 +#define VOICE2_CALL_PCM_DEVICE 25 +#define VOLTE_CALL_PCM_DEVICE 21 +#define QCHAT_CALL_PCM_DEVICE 33 +#define VOWLAN_CALL_PCM_DEVICE -1 +#else #define VOICE_CALL_PCM_DEVICE 2 #define VOICE2_CALL_PCM_DEVICE 22 #define VOLTE_CALL_PCM_DEVICE 14 #define QCHAT_CALL_PCM_DEVICE 20 #define VOWLAN_CALL_PCM_DEVICE 36 +#endif #define AFE_PROXY_PLAYBACK_PCM_DEVICE 7 #define AFE_PROXY_RECORD_PCM_DEVICE 8 #define HFP_PCM_RX 5 #ifdef PLATFORM_MSM8x26 -#define HFP_SCO_RX 28 +#ifdef EXTERNAL_BT_SUPPORTED +#define HFP_SCO_RX 10 // AUXPCM Hostless +#else +#define HFP_SCO_RX 28 // INT_HFP_BT Hostless +#endif #define HFP_ASM_RX_TX 29 #else #define HFP_SCO_RX 23 diff --git a/hal/platform_api.h b/hal/platform_api.h index 1e413587..c707db18 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -17,6 +17,9 @@ #ifndef AUDIO_PLATFORM_API_H #define AUDIO_PLATFORM_API_H +#define CODEC_BACKEND_DEFAULT_BIT_WIDTH 16 +#define CODEC_BACKEND_DEFAULT_SAMPLE_RATE 48000 + void *platform_init(struct audio_device *adev); void platform_deinit(void *platform); const char *platform_get_snd_device_name(snd_device_t snd_device); @@ -84,4 +87,11 @@ bool platform_check_backends_match(snd_device_t snd_device1, snd_device_t snd_de int platform_set_parameters(void *platform, struct str_parms *parms); +struct audio_offload_info_t; +uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info); +#ifdef PCM_OFFLOAD_ENABLED +uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info); +#endif + +bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase); #endif // AUDIO_PLATFORM_API_H diff --git a/hal/voice.c b/hal/voice.c index a33305d3..d2215b61 100644 --- a/hal/voice.c +++ b/hal/voice.c @@ -350,7 +350,8 @@ int voice_set_mic_mute(struct audio_device *adev, bool state) int err = 0; adev->voice.mic_mute = state; - if (adev->mode == AUDIO_MODE_IN_CALL) + if (adev->mode == AUDIO_MODE_IN_CALL || + adev->mode == AUDIO_MODE_IN_COMMUNICATION) err = platform_set_mic_mute(adev->platform, state); return err; |