From 5106d36bb06873317918c4efe1d94a6d319bb1de Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Wed, 11 May 2016 19:23:33 +0530 Subject: [PATCH] audio: Enable 24 bit packed direct pcm support. -Add support for 24 bit packed audio in audio hal. -Disable gapless for AV playback and direct pcm usecase, this ensures that the buffering in DSP is not more. -Simulate rendered time stamp for direct pcm usecase based on the number of frames written to the compress driver, bufferring in the driver and DSP latency. -Pass mixer instance to offload effects library to avoid an unnecessary mixer_open call, this optimizes audio start delay in compress playback. Change-Id: I422a53af5632eaf6cc362a6c44f62ff8412965f7 --- hal/audio_extn/audio_extn.h | 11 --- hal/audio_extn/utils.c | 4 +- hal/audio_hw.c | 168 ++++++++++++++++++++++++------------ hal/audio_hw.h | 3 +- hal/msm8916/platform.c | 41 +++++---- hal/msm8960/platform.c | 5 -- hal/msm8974/platform.c | 43 ++++----- hal/platform_api.h | 1 - post_proc/bundle.c | 13 ++- 9 files changed, 164 insertions(+), 125 deletions(-) diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index 91d7c0a5..3ce83b19 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -40,17 +40,6 @@ #include -#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) -#define OFFLOAD_USE_SMALL_BUFFER false -#else -#define OFFLOAD_USE_SMALL_BUFFER ((info->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM_OFFLOAD) -#endif - #ifndef AFE_PROXY_ENABLED #define AUDIO_DEVICE_OUT_PROXY 0x40000 #endif diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c index b3ba2b5a..cd9ead7d 100644 --- a/hal/audio_extn/utils.c +++ b/hal/audio_extn/utils.c @@ -97,6 +97,8 @@ const struct string_to_enum s_flag_name_to_enum_table[] = { const struct string_to_enum s_format_name_to_enum_table[] = { STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT), + STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED), + STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT), STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT), STRING_TO_ENUM(AUDIO_FORMAT_MP3), STRING_TO_ENUM(AUDIO_FORMAT_AAC), @@ -117,8 +119,6 @@ const struct string_to_enum s_format_name_to_enum_table[] = { STRING_TO_ENUM(AUDIO_FORMAT_QCELP), STRING_TO_ENUM(AUDIO_FORMAT_MP2), STRING_TO_ENUM(AUDIO_FORMAT_EVRCNW), - STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD), - STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD), STRING_TO_ENUM(AUDIO_FORMAT_FLAC), STRING_TO_ENUM(AUDIO_FORMAT_ALAC), STRING_TO_ENUM(AUDIO_FORMAT_APE), diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 8486e186..c53f124e 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -74,6 +74,8 @@ #include "sound/asound.h" #define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4 +/*DIRECT PCM has same buffer sizes as DEEP Buffer*/ +#define DIRECT_PCM_NUM_FRAGMENTS 2 /* ToDo: Check and update a proper value in msec */ #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 @@ -287,17 +289,17 @@ bool audio_hw_send_gain_dep_calibration(int level) { return ret_val; } -static int check_and_set_gapless_mode(struct audio_device *adev) { - - - char value[PROPERTY_VALUE_MAX] = {0}; +static int check_and_set_gapless_mode(struct audio_device *adev, bool enable_gapless) +{ bool gapless_enabled = false; const char *mixer_ctl_name = "Compress Gapless Playback"; struct mixer_ctl *ctl; ALOGV("%s:", __func__); - property_get("audio.offload.gapless.enabled", value, NULL); - gapless_enabled = atoi(value) || !strncmp("true", value, 4); + gapless_enabled = property_get_bool("audio.offload.gapless.enabled", false); + + /*Disable gapless if its AV playback*/ + gapless_enabled = gapless_enabled && enable_gapless; ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); if (!ctl) { @@ -323,8 +325,8 @@ static bool is_supported_format(audio_format_t format) format == AUDIO_FORMAT_AAC_ADTS_LC || format == AUDIO_FORMAT_AAC_ADTS_HE_V1 || format == AUDIO_FORMAT_AAC_ADTS_HE_V2 || - format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD || - format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD || + format == AUDIO_FORMAT_PCM_24_BIT_PACKED || + format == AUDIO_FORMAT_PCM_8_24_BIT || format == AUDIO_FORMAT_PCM_16_BIT || format == AUDIO_FORMAT_FLAC || format == AUDIO_FORMAT_ALAC || @@ -351,7 +353,6 @@ static int get_snd_codec_id(audio_format_t format) case AUDIO_FORMAT_AAC_ADTS: id = SND_AUDIOCODEC_AAC; break; - case AUDIO_FORMAT_PCM_OFFLOAD: case AUDIO_FORMAT_PCM: id = SND_AUDIOCODEC_PCM; break; @@ -1956,7 +1957,7 @@ int start_output_stream(struct stream_out *out) for the default max poll time (20s) in the event of an SSR. Reduce the poll time to observe and deal with SSR faster. */ - if (out->use_small_bufs) { + if (!out->non_blocking) { compress_set_max_poll_wait(out->compr, 1000); } @@ -1973,7 +1974,7 @@ int start_output_stream(struct stream_out *out) if (adev->visualizer_start_output != NULL) adev->visualizer_start_output(out->handle, out->pcm_device_id); if (adev->offload_effects_start_output != NULL) - adev->offload_effects_start_output(out->handle, out->pcm_device_id); + adev->offload_effects_start_output(out->handle, out->pcm_device_id, adev->mixer); audio_extn_check_and_set_dts_hpx_state(adev); } } @@ -2061,6 +2062,37 @@ static size_t get_input_buffer_size(uint32_t sample_rate, return size; } +static uint64_t get_actual_pcm_frames_rendered(struct stream_out *out) +{ + uint64_t actual_frames_rendered = 0; + size_t kernel_buffer_size = out->compr_config.fragment_size * out->compr_config.fragments; + + /* This adjustment accounts for buffering after app processor. + * It is based on estimated DSP latency per use case, rather than exact. + */ + int64_t platform_latency = platform_render_latency(out->usecase) * + out->sample_rate / 1000000LL; + + /* not querying actual state of buffering in kernel as it would involve an ioctl call + * which then needs protection, this causes delay in TS query for pcm_offload usecase + * hence only estimate. + */ + int64_t signed_frames = out->written - kernel_buffer_size; + + signed_frames = signed_frames / (audio_bytes_per_sample(out->format) * popcount(out->channel_mask)) - platform_latency; + + if (signed_frames > 0) + actual_frames_rendered = signed_frames; + + ALOGVV("%s signed frames %lld out_written %lld kernel_buffer_size %d" + "bytes/sample %zu channel count %d", __func__,(long long int)signed_frames, + (long long int)out->written, (int)kernel_buffer_size, + audio_bytes_per_sample(out->compr_config.codec->format), + popcount(out->channel_mask)); + + return actual_frames_rendered; +} + static uint32_t out_get_sample_rate(const struct audio_stream *stream) { struct stream_out *out = (struct stream_out *)stream; @@ -2553,6 +2585,9 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, out_standby(&out->stream.common); return ret; } + if ( ret == (ssize_t)bytes && !out->non_blocking) + out->written += bytes; + if (!out->playback_started && ret >= 0) { compress_start(out->compr); audio_extn_dts_eagle_fade(adev, true, out); @@ -2627,14 +2662,24 @@ static int out_get_render_position(const struct audio_stream_out *stream, *dsp_frames = 0; if (is_offload_usecase(out->usecase)) { ssize_t ret = 0; + + /* Below piece of code is not guarded against any lock beacuse audioFliner serializes + * this operation and adev_close_output_stream(where out gets reset). + */ + if (!out->non_blocking && (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)) { + *dsp_frames = get_actual_pcm_frames_rendered(out); + ALOGVV("dsp_frames %d sampleRate %d",(int)*dsp_frames,out->sample_rate); + return 0; + } + lock_output_stream(out); - if (out->compr != NULL) { + if (out->compr != NULL && out->non_blocking) { 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); + __func__, *dsp_frames, out->sample_rate); } pthread_mutex_unlock(&out->lock); if (-ENETRESET == ret) { @@ -2686,27 +2731,37 @@ static int out_get_presentation_position(const struct audio_stream_out *stream, int ret = -1; unsigned long dsp_frames; + /* below piece of code is not guarded against any lock because audioFliner serializes + * this operation and adev_close_output_stream( where out gets reset). + */ + if (is_offload_usecase(out->usecase) && !out->non_blocking && + (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)) { + *frames = get_actual_pcm_frames_rendered(out); + /* this is the best we can do */ + clock_gettime(CLOCK_MONOTONIC, timestamp); + ALOGVV("frames %lld playedat %lld",(long long int)*frames, + timestamp->tv_sec * 1000000LL + timestamp->tv_nsec / 1000); + return 0; + } + lock_output_stream(out); - if (is_offload_usecase(out->usecase)) { - if (out->compr != NULL) { - ret = compress_get_tstamp(out->compr, &dsp_frames, - &out->sample_rate); - ALOGVV("%s rendered frames %ld sample_rate %d", - __func__, dsp_frames, out->sample_rate); - *frames = dsp_frames; - if (ret < 0) - ret = -errno; - if (-ENETRESET == ret) { - ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver"); - set_snd_card_state(adev,SND_CARD_STATE_OFFLINE); - ret = -EINVAL; - } else - ret = 0; - - /* this is the best we can do */ - clock_gettime(CLOCK_MONOTONIC, timestamp); - } + if (is_offload_usecase(out->usecase) && out->compr != NULL && out->non_blocking) { + ret = compress_get_tstamp(out->compr, &dsp_frames, + &out->sample_rate); + ALOGVV("%s rendered frames %ld sample_rate %d", + __func__, dsp_frames, out->sample_rate); + *frames = dsp_frames; + if (ret < 0) + ret = -errno; + if (-ENETRESET == ret) { + ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver"); + set_snd_card_state(adev,SND_CARD_STATE_OFFLINE); + ret = -EINVAL; + } else + ret = 0; + /* this is the best we can do */ + clock_gettime(CLOCK_MONOTONIC, timestamp); } else { if (out->pcm) { unsigned int avail; @@ -2837,6 +2892,7 @@ static int out_flush(struct audio_stream_out* stream) ALOGD("copl(%p):calling compress flush", out); lock_output_stream(out); stop_compressed_output_l(out); + out->written = 0; pthread_mutex_unlock(&out->lock); ALOGD("copl(%p):out of compress flush", out); return 0; @@ -3238,7 +3294,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->handle = handle; out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; out->non_blocking = 0; - out->use_small_bufs = false; if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL && (flags & AUDIO_OUTPUT_FLAG_DIRECT)) { @@ -3337,6 +3392,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev, } if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) { + out->stream.pause = out_pause; + out->stream.flush = out_flush; + out->stream.resume = out_resume; out->usecase = get_offload_usecase(adev, true); ALOGV("DIRECT_PCM usecase ... usecase selected %d ", out->usecase); } else { @@ -3381,18 +3439,19 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format); - if (((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM_OFFLOAD)|| - ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM)) { + if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) { out->compr_config.fragment_size = platform_get_pcm_offload_buffer_size(&config->offload_info); + out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS; } else if (audio_extn_dolby_is_passthrough_stream(out)) { out->compr_config.fragment_size = audio_extn_dolby_get_passt_buffer_size(&config->offload_info); + out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; } else { 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.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; out->compr_config.codec->sample_rate = config->offload_info.sample_rate; out->compr_config.codec->bit_rate = @@ -3408,16 +3467,12 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW; if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS) out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4ADTS; - 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 (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE; - - if (out->bit_width == 24) { + if (config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_PACKED) + out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_3LE; + if (config->offload_info.format == AUDIO_FORMAT_PCM_8_24_BIT) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE; - } if (config->offload_info.format == AUDIO_FORMAT_FLAC) out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH; @@ -3425,14 +3480,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) out->non_blocking = 1; - if (platform_use_small_buffer(&config->offload_info)) { - //this flag is set from framework only if its for PCM formats - //no need to check for PCM format again - out->non_blocking = 0; - out->use_small_bufs = true; - ALOGI("Keep write blocking for small buff: non_blockling %d", - out->non_blocking); - } out->send_new_metadata = 1; out->send_next_track_params = false; @@ -3446,11 +3493,18 @@ static int adev_open_output_stream(struct audio_hw_device *dev, ALOGV("%s: offloaded output offload_info version %04x bit rate %d", __func__, config->offload_info.version, config->offload_info.bit_rate); - //Decide if we need to use gapless mode by default - if (!audio_extn_dolby_is_passthrough_stream(out)) { - ALOGV("%s: don't enable gapless for passthrough", __func__); - check_and_set_gapless_mode(adev); - } + + /* Disable gapless if any of the following is true + * passthrough playback + * AV playback + * Direct PCM playback + */ + if (audio_extn_dolby_is_passthrough_stream(out) || + config->offload_info.has_video || + out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) { + check_and_set_gapless_mode(adev, false); + } else + check_and_set_gapless_mode(adev, true); if (audio_extn_dolby_is_passthrough_stream(out)) { out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH; @@ -4288,7 +4342,7 @@ static int adev_open(const hw_module_t *module, const char *name, ALOGV("%s: DLOPEN successful for %s", __func__, OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH); adev->offload_effects_start_output = - (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib, + (int (*)(audio_io_handle_t, int, struct mixer *))dlsym(adev->offload_effects_lib, "offload_effects_bundle_hal_start_output"); adev->offload_effects_stop_output = (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib, diff --git a/hal/audio_hw.h b/hal/audio_hw.h index 31184d58..6c978403 100644 --- a/hal/audio_hw.h +++ b/hal/audio_hw.h @@ -209,7 +209,6 @@ struct stream_out { struct stream_app_type_cfg app_type_cfg; int non_blocking; - bool use_small_bufs; int playback_started; int offload_state; pthread_cond_t offload_cond; @@ -343,7 +342,7 @@ struct audio_device { int (*visualizer_start_output)(audio_io_handle_t, int); int (*visualizer_stop_output)(audio_io_handle_t, int); void *offload_effects_lib; - int (*offload_effects_start_output)(audio_io_handle_t, int); + int (*offload_effects_start_output)(audio_io_handle_t, int, struct mixer *); int (*offload_effects_stop_output)(audio_io_handle_t, int); struct sound_card_status snd_card_status; diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c index 857d9e11..46611fc3 100644 --- a/hal/msm8916/platform.c +++ b/hal/msm8916/platform.c @@ -760,6 +760,7 @@ static int msm_device_to_be_id_external_codec [][NO_COLS] = { #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) +#define PCM_OFFLOAD_PLATFORM_DELAY (30*1000LL) #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) static bool is_misc_usecase(audio_usecase_t usecase) { @@ -3651,7 +3652,7 @@ void platform_get_parameters(void *platform, free(kv_pairs); } -/* Delay in Us */ +/* Delay in Us, only to be used for PCM formats */ int64_t platform_render_latency(audio_usecase_t usecase) { switch (usecase) { @@ -3659,6 +3660,9 @@ int64_t platform_render_latency(audio_usecase_t usecase) return DEEP_BUFFER_PLATFORM_DELAY; case USECASE_AUDIO_PLAYBACK_LOW_LATENCY: return LOW_LATENCY_PLATFORM_DELAY; + case USECASE_AUDIO_PLAYBACK_OFFLOAD: + case USECASE_AUDIO_PLAYBACK_OFFLOAD2: + return PCM_OFFLOAD_PLATFORM_DELAY; default: return 0; } @@ -3846,19 +3850,17 @@ uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info) 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 bytes_per_sample; uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION; - if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) { - bits_per_sample = 32; - } + bytes_per_sample = audio_bytes_per_sample(info->format); //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) + * bytes_per_sample * popcount(info->channel_mask))/1000; if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE) fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE; @@ -3867,23 +3869,18 @@ uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info) // 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 - fragment_size = ALIGN(fragment_size, ((bits_per_sample >> 3)* popcount(info->channel_mask) * 32)); + fragment_size = ALIGN(fragment_size, (bytes_per_sample * popcount(info->channel_mask) * 32)); ALOGI("PCM offload Fragment size to %d bytes", fragment_size); return fragment_size; } -bool platform_use_small_buffer(audio_offload_info_t* info) -{ - return OFFLOAD_USE_SMALL_BUFFER; -} - /* * configures afe with bit width and Sample Rate */ static int platform_set_codec_backend_cfg(struct audio_device* adev, - snd_device_t snd_device, - unsigned int bit_width, unsigned int sample_rate) + snd_device_t snd_device, unsigned int bit_width, + unsigned int sample_rate, audio_format_t format) { int ret = 0; int backend_idx = DEFAULT_CODEC_BACKEND; @@ -3908,13 +3905,17 @@ static int platform_set_codec_backend_cfg(struct audio_device* adev, } if (bit_width == 24) { + if (format == AUDIO_FORMAT_PCM_24_BIT_PACKED) + mixer_ctl_set_enum_by_string(ctl, "S24_3LE"); + else mixer_ctl_set_enum_by_string(ctl, "S24_LE"); } else { mixer_ctl_set_enum_by_string(ctl, "S16_LE"); } my_data->current_backend_cfg[backend_idx].bit_width = bit_width; - ALOGD("%s:becf: afe: %s mixer set to %d bit", __func__, - my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width); + ALOGD("%s:becf: afe: %s mixer set to %d bit for %x format", __func__, + my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl, + bit_width, format); } /* @@ -4150,11 +4151,13 @@ bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, int new_snd_devices[SND_DEVICE_OUT_END]; int i, num_devices = 1; bool ret = false; + audio_format_t format; backend_idx = platform_get_backend_index(snd_device); new_bit_width = usecase->stream.out->bit_width; new_sample_rate = usecase->stream.out->sample_rate; + format = usecase->stream.out->format; ALOGI("%s:becf: afe: bitwidth %d, samplerate %d" ", backend_idx %d usecase = %d device (%s)", __func__, new_bit_width, @@ -4171,7 +4174,7 @@ bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, if (platform_check_codec_backend_cfg(adev, usecase, new_snd_devices[i], &new_bit_width, &new_sample_rate)) { platform_set_codec_backend_cfg(adev, new_snd_devices[i], - new_bit_width, new_sample_rate); + new_bit_width, new_sample_rate, format); ret = true; } } @@ -4691,8 +4694,8 @@ unsigned char platform_map_to_edid_format(int audio_format) format = DTS_HD; break; case AUDIO_FORMAT_PCM_16_BIT: - case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD: - case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD: + case AUDIO_FORMAT_PCM_24_BIT_PACKED: + case AUDIO_FORMAT_PCM_8_24_BIT: ALOGV("%s:PCM", __func__); format = LPCM; break; diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c index 5a41b077..2c60f3ba 100644 --- a/hal/msm8960/platform.c +++ b/hal/msm8960/platform.c @@ -1119,11 +1119,6 @@ uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info __unuse return 0; } -bool platform_use_small_buffer(audio_offload_info_t* info) -{ - return false; -} - int platform_get_edid_info(void *platform __unused) { return -ENOSYS; diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c index 385d20b3..f1ec7a94 100644 --- a/hal/msm8974/platform.c +++ b/hal/msm8974/platform.c @@ -757,6 +757,7 @@ static int msm_be_id_array_len = #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) +#define PCM_OFFLOAD_PLATFORM_DELAY (30*1000LL) #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) bool platform_send_gain_dep_cal(void *platform, int level) { @@ -3677,7 +3678,7 @@ void platform_get_parameters(void *platform, free(kv_pairs); } -/* Delay in Us */ +/* Delay in Us, only to be used for PCM formats */ int64_t platform_render_latency(audio_usecase_t usecase) { switch (usecase) { @@ -3685,6 +3686,9 @@ int64_t platform_render_latency(audio_usecase_t usecase) return DEEP_BUFFER_PLATFORM_DELAY; case USECASE_AUDIO_PLAYBACK_LOW_LATENCY: return LOW_LATENCY_PLATFORM_DELAY; + case USECASE_AUDIO_PLAYBACK_OFFLOAD: + case USECASE_AUDIO_PLAYBACK_OFFLOAD2: + return PCM_OFFLOAD_PLATFORM_DELAY; default: return 0; } @@ -3782,44 +3786,38 @@ uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info) 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 bytes_per_sample; uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION; - if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) { - bits_per_sample = 32; - } + bytes_per_sample = audio_bytes_per_sample(info->format); //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) + * bytes_per_sample * popcount(info->channel_mask))/1000; 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; + // 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 - fragment_size = ALIGN(fragment_size, ((bits_per_sample >> 3)* popcount(info->channel_mask) * 32)); + fragment_size = ALIGN(fragment_size, ((bytes_per_sample) * popcount(info->channel_mask) * 32)); ALOGI("PCM offload Fragment size to %d bytes", fragment_size); return fragment_size; } -bool platform_use_small_buffer(audio_offload_info_t* info) -{ - return OFFLOAD_USE_SMALL_BUFFER; -} - /* * configures afe with bit width and Sample Rate */ static int platform_set_codec_backend_cfg(struct audio_device* adev, - snd_device_t snd_device, - unsigned int bit_width, unsigned int sample_rate) + snd_device_t snd_device, unsigned int bit_width, + unsigned int sample_rate, audio_format_t format) { int ret = 0; int backend_idx = DEFAULT_CODEC_BACKEND; @@ -3845,13 +3843,16 @@ static int platform_set_codec_backend_cfg(struct audio_device* adev, } if (bit_width == 24) { - mixer_ctl_set_enum_by_string(ctl, "S24_LE"); + if (format == AUDIO_FORMAT_PCM_24_BIT_PACKED) + mixer_ctl_set_enum_by_string(ctl, "S24_3LE"); + else + mixer_ctl_set_enum_by_string(ctl, "S24_LE"); } else { mixer_ctl_set_enum_by_string(ctl, "S16_LE"); } my_data->current_backend_cfg[backend_idx].bit_width = bit_width; - ALOGD("%s:becf: afe: %s mixer set to %d bit", __func__, - my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width); + ALOGD("%s:becf: afe: %s mixer set to %d bit for %x format", __func__, + my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width, format); } /* @@ -4053,11 +4054,13 @@ bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, int i, num_devices = 1; bool ret = false; struct platform_data *my_data = (struct platform_data *)adev->platform; + audio_format_t format; backend_idx = platform_get_backend_index(snd_device); new_bit_width = usecase->stream.out->bit_width; new_sample_rate = usecase->stream.out->sample_rate; + format = usecase->stream.out->format; ALOGI("%s:becf: afe: bitwidth %d, samplerate %d" ", backend_idx %d usecase = %d device (%s)", __func__, new_bit_width, @@ -4073,7 +4076,7 @@ bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, if (platform_check_codec_backend_cfg(adev, usecase, new_snd_devices[i], &new_bit_width, &new_sample_rate)) { platform_set_codec_backend_cfg(adev, new_snd_devices[i], - new_bit_width, new_sample_rate); + new_bit_width, new_sample_rate, format); ret = true; } } @@ -4591,8 +4594,8 @@ unsigned char platform_map_to_edid_format(int audio_format) format = DTS_HD; break; case AUDIO_FORMAT_PCM_16_BIT: - case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD: - case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD: + case AUDIO_FORMAT_PCM_24_BIT_PACKED: + case AUDIO_FORMAT_PCM_8_24_BIT: ALOGV("%s:PCM", __func__); format = LPCM; break; diff --git a/hal/platform_api.h b/hal/platform_api.h index df80a0c9..cb177b6e 100644 --- a/hal/platform_api.h +++ b/hal/platform_api.h @@ -109,7 +109,6 @@ void platform_snd_card_update(void *platform, int snd_scard_state); struct audio_offload_info_t; uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info); uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info); -bool platform_use_small_buffer(audio_offload_info_t* info); uint32_t platform_get_compress_passthrough_buffer_size(audio_offload_info_t* info); bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, diff --git a/post_proc/bundle.c b/post_proc/bundle.c index d39a8b72..464bc0dc 100644 --- a/post_proc/bundle.c +++ b/post_proc/bundle.c @@ -209,7 +209,7 @@ bool effects_enabled() * Interface from audio HAL */ __attribute__ ((visibility ("default"))) -int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id) +int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id, struct mixer *mixer) { int ret = 0; struct listnode *node; @@ -245,19 +245,19 @@ int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id /* populate the mixer control to send offload parameters */ snprintf(mixer_string, sizeof(mixer_string), "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id); - out_ctxt->mixer = mixer_open(MIXER_CARD); - if (!out_ctxt->mixer) { - ALOGE("Failed to open mixer"); + + if (!mixer) { + ALOGE("Invalid mixer"); out_ctxt->ctl = NULL; out_ctxt->ref_ctl = NULL; ret = -EINVAL; free(out_ctxt); goto exit; } else { + out_ctxt->mixer = mixer; out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string); if (!out_ctxt->ctl) { ALOGE("mixer_get_ctl_by_name failed"); - mixer_close(out_ctxt->mixer); out_ctxt->mixer = NULL; ret = -EINVAL; free(out_ctxt); @@ -314,9 +314,6 @@ int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id) fx_ctxt->ops.stop(fx_ctxt, out_ctxt); } - if (out_ctxt->mixer) - mixer_close(out_ctxt->mixer); - list_remove(&out_ctxt->outputs_list_node); #ifdef DTS_EAGLE