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
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 2b80302..853ee3e 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -104,7 +104,7 @@
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 @@
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 a493763..97b7688 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -216,6 +216,9 @@
//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_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 @@
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 fd47b8b..bc630a3 100644
--- a/hal/audio_extn/compress_in.c
+++ b/hal/audio_extn/compress_in.c
@@ -100,7 +100,7 @@
* 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 @@
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 @@
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 d66b368..171f69e 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 <sound/compress_params.h>
#include <sound/compress_offload.h>
@@ -1249,6 +1250,88 @@
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 @@
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 7656292..76c14ab 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -8829,7 +8829,7 @@
(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 @@
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;
}