From 1423092192c6a8272eb2804d39386bfb4e44bbf1 Mon Sep 17 00:00:00 2001 From: Deeraj Soman Date: Wed, 30 Jan 2019 16:39:30 +0530 Subject: [PATCH] hal: Add support for low latency compress capture Add support for low latency compress capture. Client may pass the required capture duration as part of config. HAL will decided the buffer size based on this. Change-Id: I39aa6d99c954877449a827468cea4b1d4304637d --- hal/audio_extn/audio_extn.c | 6 +- hal/audio_extn/audio_extn.h | 6 +- hal/audio_extn/compress_in.c | 8 +-- hal/audio_extn/utils.c | 122 +++++++++++++++++++++++++++++++++++ hal/audio_hw.c | 4 +- 5 files changed, 136 insertions(+), 10 deletions(-) diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c index 2b803027..853ee3ea 100644 --- a/hal/audio_extn/audio_extn.c +++ b/hal/audio_extn/audio_extn.c @@ -104,7 +104,7 @@ void cin_close_input_stream(struct stream_in *in); void cin_free_input_stream_resources(struct stream_in *in); int cin_read(struct stream_in *in, void *buffer, size_t bytes, size_t *bytes_read); -int cin_configure_input_stream(struct stream_in *in); +int cin_configure_input_stream(struct stream_in *in, struct audio_config *in_config); void audio_extn_set_snd_card_split(const char* in_snd_card_name) { @@ -5086,9 +5086,9 @@ int audio_extn_cin_read(struct stream_in *in, void *buffer, return (audio_extn_compress_in_enabled? cin_read(in, buffer, bytes, bytes_read): -1); } -int audio_extn_cin_configure_input_stream(struct stream_in *in) +int audio_extn_cin_configure_input_stream(struct stream_in *in, struct audio_config *in_config) { - return (audio_extn_compress_in_enabled? cin_configure_input_stream(in): -1); + return (audio_extn_compress_in_enabled? cin_configure_input_stream(in, in_config): -1); } // END: COMPRESS_IN ==================================================== diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h index a4937631..97b7688e 100644 --- a/hal/audio_extn/audio_extn.h +++ b/hal/audio_extn/audio_extn.h @@ -216,6 +216,9 @@ bool audio_extn_qdsp_supported_usb(); //END: EXTN_QDSP_PLUGIN =========================================== +#define MIN_OFFLOAD_BUFFER_DURATION_MS 5 /* 5ms */ +#define MAX_OFFLOAD_BUFFER_DURATION_MS (100 * 1000) /* 100s */ + void audio_extn_set_parameters(struct audio_device *adev, struct str_parms *parms); @@ -1017,7 +1020,7 @@ void audio_extn_cin_close_input_stream(struct stream_in *in); void audio_extn_cin_free_input_stream_resources(struct stream_in *in); int audio_extn_cin_read(struct stream_in *in, void *buffer, size_t bytes, size_t *bytes_read); -int audio_extn_cin_configure_input_stream(struct stream_in *in); +int audio_extn_cin_configure_input_stream(struct stream_in *in, struct audio_config *in_config); // END: COMPRESS_INPUT_ENABLED =============================== //START: SOURCE_TRACKING_FEATURE ============================================== @@ -1092,6 +1095,7 @@ int audio_extn_utils_compress_get_dsp_presentation_pos(struct stream_out *out, uint64_t *frames, struct timespec *timestamp, int32_t clock_id); int audio_extn_utils_pcm_get_dsp_presentation_pos(struct stream_out *out, uint64_t *frames, struct timespec *timestamp, int32_t clock_id); +size_t audio_extn_utils_get_input_buffer_size(uint32_t, audio_format_t, int, int64_t, bool); #ifdef AUDIO_HW_LOOPBACK_ENABLED /* API to create audio patch */ int audio_extn_hw_loopback_create_audio_patch(struct audio_hw_device *dev, diff --git a/hal/audio_extn/compress_in.c b/hal/audio_extn/compress_in.c index fd47b8ba..bc630a37 100644 --- a/hal/audio_extn/compress_in.c +++ b/hal/audio_extn/compress_in.c @@ -100,7 +100,7 @@ bool cin_applicable_stream(struct stream_in *in) * only after validating that input against cin_attached_usecase * except below calls * 1. cin_applicable_stream(in) - * 2. cin_configure_input_stream(in) + * 2. cin_configure_input_stream(in, in_config) */ bool cin_attached_usecase(audio_usecase_t uc_id) @@ -276,9 +276,8 @@ int cin_read(struct stream_in *in, void *buffer, return ret; } -int cin_configure_input_stream(struct stream_in *in) +int cin_configure_input_stream(struct stream_in *in, struct audio_config *in_config) { - struct audio_device *adev = in->dev; struct audio_config config = {.format = 0}; int ret = 0, buffer_size = 0, meta_size = sizeof(struct snd_codec_metadata); cin_private_data_t *cin_data = NULL; @@ -315,7 +314,8 @@ int cin_configure_input_stream(struct stream_in *in) config.channel_mask = in->channel_mask; config.format = in->format; in->config.channels = audio_channel_count_from_in_mask(in->channel_mask); - buffer_size = adev->device.get_input_buffer_size(&adev->device, &config); + buffer_size = audio_extn_utils_get_input_buffer_size(config.sample_rate, config.format, + in->config.channels, in_config->offload_info.duration_us / 1000, false); cin_data->compr_config.fragment_size = buffer_size; cin_data->compr_config.codec->id = get_snd_codec_id(in->format); diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c index d66b3680..171f69e5 100644 --- a/hal/audio_extn/utils.c +++ b/hal/audio_extn/utils.c @@ -37,6 +37,7 @@ #include "platform.h" #include "platform_api.h" #include "audio_extn.h" +#include "voice_extn.h" #include "voice.h" #include #include @@ -1249,6 +1250,88 @@ exit_send_app_type_cfg: return rc; } +static int audio_extn_utils_check_input_parameters(uint32_t sample_rate, + audio_format_t format, + int channel_count) +{ + int ret = 0; + + if (((format != AUDIO_FORMAT_PCM_16_BIT) && (format != AUDIO_FORMAT_PCM_8_24_BIT) && + (format != AUDIO_FORMAT_PCM_24_BIT_PACKED) && (format != AUDIO_FORMAT_PCM_32_BIT) && + (format != AUDIO_FORMAT_PCM_FLOAT)) && + !voice_extn_compress_voip_is_format_supported(format) && + !audio_extn_compr_cap_format_supported(format) && + !audio_extn_cin_format_supported(format)) + ret = -EINVAL; + + switch (channel_count) { + case 1: + case 2: + case 3: + case 4: + case 6: + case 8: + break; + default: + ret = -EINVAL; + } + + switch (sample_rate) { + case 8000: + case 11025: + case 12000: + case 16000: + case 22050: + case 24000: + case 32000: + case 44100: + case 48000: + case 88200: + case 96000: + case 176400: + case 192000: + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static inline uint32_t audio_extn_utils_nearest_multiple(uint32_t num, uint32_t multiplier) +{ + uint32_t remainder = 0; + + if (!multiplier) + return num; + + remainder = num % multiplier; + if (remainder) + num += (multiplier - remainder); + + return num; +} + +static inline uint32_t audio_extn_utils_lcm(uint32_t num1, uint32_t num2) +{ + uint32_t high = num1, low = num2, temp = 0; + + if (!num1 || !num2) + return 0; + + if (num1 < num2) { + high = num2; + low = num1; + } + + while (low != 0) { + temp = low; + low = high % low; + high = temp; + } + return (num1 * num2)/high; +} + int audio_extn_utils_send_app_type_cfg(struct audio_device *adev, struct audio_usecase *usecase) { @@ -2860,3 +2943,42 @@ int audio_extn_utils_is_vendor_enhanced_fwk() return is_running_with_enhanced_fwk; } + +size_t audio_extn_utils_get_input_buffer_size(uint32_t sample_rate, + audio_format_t format, + int channel_count, + int64_t duration_ms, + bool is_low_latency) +{ + size_t size = 0; + size_t capture_duration = AUDIO_CAPTURE_PERIOD_DURATION_MSEC; + uint32_t bytes_per_period_sample = 0; + + + if (audio_extn_utils_check_input_parameters(sample_rate, format, channel_count) != 0) + return 0; + + if (duration_ms >= MIN_OFFLOAD_BUFFER_DURATION_MS && duration_ms <= MAX_OFFLOAD_BUFFER_DURATION_MS) + capture_duration = duration_ms; + + size = (sample_rate * capture_duration) / 1000; + if (is_low_latency) + size = LOW_LATENCY_CAPTURE_PERIOD_SIZE; + + + bytes_per_period_sample = audio_bytes_per_sample(format) * channel_count; + size *= bytes_per_period_sample; + + /* make sure the size is multiple of 32 bytes and additionally multiple of + * the frame_size (required for 24bit samples and non-power-of-2 channel counts) + * At 48 kHz mono 16-bit PCM: + * 5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15) + * 3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10) + * + * The loop reaches result within 32 iterations, as initial size is + * already a multiple of frame_size + */ + size = audio_extn_utils_nearest_multiple(size, audio_extn_utils_lcm(32, bytes_per_period_sample)); + + return size; +} diff --git a/hal/audio_hw.c b/hal/audio_hw.c index 76562925..76c14ab5 100644 --- a/hal/audio_hw.c +++ b/hal/audio_hw.c @@ -8829,7 +8829,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) { audio_extn_compr_cap_init(in); } else if (audio_extn_cin_applicable_stream(in)) { - ret = audio_extn_cin_configure_input_stream(in); + ret = audio_extn_cin_configure_input_stream(in, config); if (ret) goto err_open; } else { @@ -8880,7 +8880,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, ALOGV("%s: overriding usecase with USECASE_AUDIO_RECORD_COMPRESS2 and appending compress flag", __func__); if (audio_extn_cin_applicable_stream(in)) { in->sample_rate = config->sample_rate; - ret = audio_extn_cin_configure_input_stream(in); + ret = audio_extn_cin_configure_input_stream(in, config); if (ret) goto err_open; }