hal: Add support for compressed capture
- Add support for AMR-WB compressed capture.
Change-Id: Ief591c5d1ccc6f8afb408abfff447787ee7bd7aa
diff --git a/hal/Android.mk b/hal/Android.mk
index 21dc8a0..abafb85 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -82,6 +82,11 @@
LOCAL_SRC_FILES += $(AUDIO_PLATFORM)/hw_info.c
endif
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_COMPRESS_CAPTURE)),true)
+ LOCAL_CFLAGS += -DCOMPRESS_CAPTURE_ENABLED
+ LOCAL_SRC_FILES += audio_extn/compress_capture.c
+endif
+
LOCAL_SHARED_LIBRARIES := \
liblog \
libcutils \
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index a54e5e7..7d04c6d 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -137,4 +137,24 @@
bool audio_extn_spkr_prot_is_enabled();
#endif
+#ifndef COMPRESS_CAPTURE_ENABLED
+#define audio_extn_compr_cap_init(adev,in) (0)
+#define audio_extn_compr_cap_enabled() (0)
+#define audio_extn_compr_cap_format_supported(format) (0)
+#define audio_extn_compr_cap_usecase_supported(usecase) (0)
+#define audio_extn_compr_cap_get_buffer_size(format) (0)
+#define audio_extn_compr_cap_read(in, buffer, bytes) (0)
+#define audio_extn_compr_cap_deinit() (0)
+#else
+void audio_extn_compr_cap_init(struct audio_device *adev,
+ struct stream_in *in);
+bool audio_extn_compr_cap_enabled();
+bool audio_extn_compr_cap_format_supported(audio_format_t format);
+bool audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase);
+size_t audio_extn_compr_cap_get_buffer_size(audio_format_t format);
+size_t audio_extn_compr_cap_read(struct stream_in *in,
+ void *buffer, size_t bytes);
+void audio_extn_compr_cap_deinit();
+#endif
+
#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/compress_capture.c b/hal/audio_extn/compress_capture.c
new file mode 100644
index 0000000..f3db419
--- /dev/null
+++ b/hal/audio_extn/compress_capture.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2013, 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_compress"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/str_parms.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+
+#include "sound/compress_params.h"
+#include "sound/compress_offload.h"
+
+#ifdef COMPRESS_CAPTURE_ENABLED
+
+#define COMPRESS_IN_CONFIG_CHANNELS 1
+#define COMPRESS_IN_CONFIG_PERIOD_SIZE 2048
+#define COMPRESS_IN_CONFIG_PERIOD_COUNT 16
+
+
+struct compress_in_module {
+ uint8_t *in_buf;
+};
+
+static struct compress_in_module c_in_mod = {
+ .in_buf = NULL,
+};
+
+
+void audio_extn_compr_cap_init(struct audio_device *adev,
+ struct stream_in *in)
+{
+ in->usecase = USECASE_AUDIO_RECORD_COMPRESS;
+ in->config.channels = COMPRESS_IN_CONFIG_CHANNELS;
+ in->config.period_size = COMPRESS_IN_CONFIG_PERIOD_SIZE;
+ in->config.period_count= COMPRESS_IN_CONFIG_PERIOD_COUNT;
+ in->config.format = AUDIO_FORMAT_AMR_WB;
+ c_in_mod.in_buf = (uint8_t*)calloc(1, in->config.period_size*2);
+}
+
+void audio_extn_compr_cap_deinit()
+{
+ if (c_in_mod.in_buf) {
+ free(c_in_mod.in_buf);
+ c_in_mod.in_buf = NULL;
+ }
+}
+
+bool audio_extn_compr_cap_enabled()
+{
+ char prop_value[PROPERTY_VALUE_MAX] = {0};
+ bool tunnel_encode = false;
+
+ property_get("tunnel.audio.encode",prop_value,"0");
+ if (!strncmp("true", prop_value, sizeof("true")))
+ return true;
+ else
+ return false;
+}
+
+bool audio_extn_compr_cap_format_supported(audio_format_t format)
+{
+ if (format == AUDIO_FORMAT_AMR_WB)
+ return true;
+ else
+ return false;
+}
+
+
+bool audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase)
+{
+ if (usecase == USECASE_AUDIO_RECORD_COMPRESS)
+ return true;
+ else
+ return false;
+}
+
+
+size_t audio_extn_compr_cap_get_buffer_size(audio_format_t format)
+{
+ if (format == AUDIO_FORMAT_AMR_WB)
+ /*One AMR WB frame is 61 bytes. Return that to the caller.
+ The buffer size is not altered, that is still period size.*/
+ return AMR_WB_FRAMESIZE;
+ else
+ return 0;
+}
+
+size_t audio_extn_compr_cap_read(struct stream_in * in,
+ void *buffer, size_t bytes)
+{
+ int ret;
+ struct snd_compr_audio_info *header;
+ uint32_t c_in_header;
+ uint32_t c_in_buf_size;
+
+ c_in_buf_size = in->config.period_size*2;
+
+ if (in->pcm) {
+ ret = pcm_read(in->pcm, c_in_mod.in_buf, c_in_buf_size);
+ if (ret < 0) {
+ ALOGE("pcm_read() returned failure: %d", ret);
+ return ret;
+ } else {
+ header = (struct snd_compr_audio_info *) c_in_mod.in_buf;
+ c_in_header = sizeof(*header) + header->reserved[0];
+ if (header->frame_size > 0) {
+ if (c_in_header + header->frame_size > c_in_buf_size) {
+ ALOGW("AMR WB read buffer overflow.");
+ header->frame_size =
+ bytes - sizeof(*header) - header->reserved[0];
+ }
+ ALOGV("c_in_buf: %p, data offset: %p, header size: %u,"
+ "reserved[0]: %u frame_size: %d", c_in_mod.in_buf,
+ c_in_mod.in_buf + c_in_header,
+ sizeof(*header), header->reserved[0],
+ header->frame_size);
+ memcpy(buffer, c_in_mod.in_buf + c_in_header, header->frame_size);
+ } else {
+ ALOGE("pcm_read() with zero frame size");
+ ret = -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif /* COMPRESS_CAPTURE_ENABLED end */
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 9b59e4a..873e5e2 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -105,6 +105,7 @@
[USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
[USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
[USECASE_AUDIO_RECORD] = "audio-record",
+ [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
[USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
[USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
[USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
@@ -741,7 +742,7 @@
struct audio_usecase *uc_info;
struct audio_device *adev = in->dev;
- in->usecase = platform_get_usecase_from_source(in->source);
+ in->usecase = platform_update_usecase_from_source(in->source,in->usecase);
ALOGV("%s: enter: usecase(%d)", __func__, in->usecase);
/* Check if source matches incall recording usecase criteria */
@@ -1126,7 +1127,8 @@
int ret = 0;
if ((format != AUDIO_FORMAT_PCM_16_BIT) &&
- !voice_extn_compress_voip_is_format_supported(format)) ret = -EINVAL;
+ !voice_extn_compress_voip_is_format_supported(format) &&
+ !audio_extn_compr_cap_format_supported(format)) ret = -EINVAL;
switch (channel_count) {
case 1:
@@ -1714,6 +1716,8 @@
if(in->usecase == USECASE_COMPRESS_VOIP_CALL)
return voice_extn_compress_voip_in_get_buffer_size(in);
+ else if(audio_extn_compr_cap_usecase_supported(in->usecase))
+ return audio_extn_compr_cap_get_buffer_size(in->config.format);
return in->config.period_size * audio_stream_frame_size(stream);
}
@@ -1865,6 +1869,8 @@
if (in->pcm) {
if (audio_extn_ssr_get_enabled() && popcount(in->channel_mask) == 6)
ret = audio_extn_ssr_read(stream, buffer, bytes);
+ else if (audio_extn_compr_cap_usecase_supported(in->usecase))
+ ret = audio_extn_compr_cap_read(in, buffer, bytes);
else
ret = pcm_read(in->pcm, buffer, bytes);
}
@@ -2383,8 +2389,7 @@
__func__, ret);
goto err_open;
}
- }
- if (channel_count == 6) {
+ } else if (channel_count == 6) {
if(audio_extn_ssr_get_enabled()) {
if(audio_extn_ssr_init(adev, in)) {
ALOGE("%s: audio_extn_ssr_init failed", __func__);
@@ -2395,6 +2400,9 @@
ret = -EINVAL;
goto err_open;
}
+ } else if (audio_extn_compr_cap_enabled() &&
+ audio_extn_compr_cap_format_supported(config->format)) {
+ audio_extn_compr_cap_init(adev, in);
} else {
in->config.channels = channel_count;
frame_size = audio_stream_frame_size((struct audio_stream *)in);
@@ -2434,6 +2442,9 @@
}
free(stream);
+ if(audio_extn_compr_cap_enabled() &&
+ audio_extn_compr_cap_format_supported(in->config.format))
+ audio_extn_compr_cap_deinit();
return;
}
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 9dca5c1..6ff6f40 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -64,6 +64,7 @@
/* Capture usecases */
USECASE_AUDIO_RECORD,
+ USECASE_AUDIO_RECORD_COMPRESS,
USECASE_AUDIO_RECORD_LOW_LATENCY,
USECASE_AUDIO_RECORD_FM_VIRTUAL,
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 089b2ec..43bef81 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -897,3 +897,9 @@
return 0;
}
}
+
+int platform_update_usecase_from_source(int source, int usecase)
+{
+ ALOGV("%s: input source :%d", __func__, source);
+ return usecase;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 4a5bbc6..352c4d8 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -103,6 +103,7 @@
[USECASE_AUDIO_PLAYBACK_OFFLOAD] =
{PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
[USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
+ [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
[USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
LOWLATENCY_PCM_DEVICE},
[USECASE_AUDIO_RECORD_FM_VIRTUAL] = {MULTIMEDIA2_PCM_DEVICE,
@@ -1381,11 +1382,10 @@
}
}
-int platform_get_usecase_from_source(int source)
+int platform_update_usecase_from_source(int source, int usecase)
{
ALOGV("%s: input source :%d", __func__, source);
if(source == AUDIO_SOURCE_FM_RX_A2DP)
- return USECASE_AUDIO_RECORD_FM_VIRTUAL;
- else
- return USECASE_AUDIO_RECORD;
+ usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
+ return usecase;
}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 9d4378d..7d80906 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -182,6 +182,7 @@
#else
#define LOWLATENCY_PCM_DEVICE 15
#endif
+#define COMPRESS_CAPTURE_DEVICE 19
#ifdef PLATFORM_MSM8x26
#define VOICE_CALL_PCM_DEVICE 2
diff --git a/hal/platform_api.h b/hal/platform_api.h
index b9919ae..dac3fd9 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -47,6 +47,6 @@
/* returns the latency for a usecase in Us */
int64_t platform_render_latency(audio_usecase_t usecase);
-int platform_get_usecase_from_source(int source);
+int platform_update_usecase_from_source(int source, audio_usecase_t usecase);
#endif // QCOM_AUDIO_PLATFORM_API_H