audio: add injection and capture for roku [1/1]
PD#SWPL-187494
Problem:
new feature
Solution:
add capture output and package into a module
Verify:
yocto
Change-Id: I7eaa3cdc394b5c77495d69d04f5bfd2e09fb0311
Signed-off-by: wei.du <wei.du@amlogic.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a63acc9..09839b1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -201,6 +201,7 @@
audio_hal/hal_clipmeta.c
audio_hal/aml_audio_scaletempo.c
audio_hal/karaoke_manager.c
+ audio_hal/aml_capture_output.c
utils/cJSON/cJSON.c
utils/aml_hw_mixer.c
utils/alsa_device_parser.c
diff --git a/audio_hal/amlAudioMixer.c b/audio_hal/amlAudioMixer.c
index e67d71f..2d8831d 100644
--- a/audio_hal/amlAudioMixer.c
+++ b/audio_hal/amlAudioMixer.c
@@ -484,59 +484,13 @@
int count = 3;
while (out_port->bytes_avail > 0) {
- // out_write_callbacks();
- if (adev->active_outport == OUTPORT_A2DP) {
- if (out_port->cfg.channelCnt == 1) {
- in_data_config.channel_mask = AUDIO_CHANNEL_OUT_MONO;
- } else if (out_port->cfg.channelCnt == 2) {
- in_data_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
- } else {
- AM_LOGW("not supported channel:%d", out_port->cfg.channelCnt);
- release_cur_outport_lock(audio_mixer, port_index);
- return out_port->bytes_avail;
- }
- in_data_config.sample_rate = out_port->cfg.sampleRate;
- in_data_config.format = out_port->cfg.format;
-#if 0
- if (is_TV(adev)) {
- float volume = aml_audio_get_s_gain_by_src(adev, get_dev_patch_src(adev));
-
- volume *= adev->sink_gain[OUTPORT_A2DP];
- apply_volume(volume, out_port->data_buf, sizeof(uint16_t),
- out_port->bytes_avail);
- }
-
- int ret = a2dp_out_write(adev, &in_data_config, out_port->data_buf, out_port->bytes_avail);
- if (ret == 0 && count-- > 0) {
- continue;
- }
-#endif
- } else if (is_sco_port(adev->active_outport)) {
- if (out_port->cfg.channelCnt == 1) {
- in_data_config.channel_mask = AUDIO_CHANNEL_OUT_MONO;
- } else if (out_port->cfg.channelCnt == 2) {
- in_data_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
- } else {
- AM_LOGW("not supported channel:%d", out_port->cfg.channelCnt);
- release_cur_outport_lock(audio_mixer, port_index);
- return out_port->bytes_avail;
- }
- in_data_config.sample_rate = out_port->cfg.sampleRate;
- in_data_config.format = out_port->cfg.format;
- if (is_TV(adev))
- apply_volume(adev->sink_gain[OUTPORT_BT_SCO], out_port->data_buf, sizeof(uint16_t),
- out_port->bytes_avail);
-
- write_to_sco(adev, &in_data_config, out_port->data_buf, out_port->bytes_avail);
- } else {
- if (audio_mixer->submix_standby) {
- pthread_mutex_unlock(&audio_mixer->outport_locks[port_index]);
- mixer_output_startup(audio_mixer);
- pthread_mutex_lock(&audio_mixer->outport_locks[port_index]);
- }
-
- out_port->write(out_port, out_port->data_buf, out_port->bytes_avail);
+ if (audio_mixer->submix_standby) {
+ pthread_mutex_unlock(&audio_mixer->outport_locks[port_index]);
+ mixer_output_startup(audio_mixer);
+ pthread_mutex_lock(&audio_mixer->outport_locks[port_index]);
}
+
+ out_port->write(out_port, out_port->data_buf, out_port->bytes_avail);
set_outport_data_avail(out_port, 0);
};
release_cur_outport_lock(audio_mixer, port_index);
diff --git a/audio_hal/aml_audio_output.c b/audio_hal/aml_audio_output.c
index 705a28b..b5e022f 100644
--- a/audio_hal/aml_audio_output.c
+++ b/audio_hal/aml_audio_output.c
@@ -32,9 +32,7 @@
#include "audio_hw_resource_mgr.h"
#include "audio_hw_ms12_v2.h"
#include "aml_audio_timer.h"
-#ifndef NO_AUDIO_CAP
- #include <IpcBuffer/IpcBuffer_c.h>
-#endif
+#include "aml_capture_output.h"
#include "a2dp_hal.h"
#include "audio_bt_sco.h"
#include "dolby_lib_api.h"
@@ -178,11 +176,13 @@
pthread_mutex_lock(&adev->alsa_lock[I2S_DEVICE]);
alsa_handle = adev->alsa_handle[I2S_DEVICE];
- if (NULL == alsa_handle || NULL == alsa_status) {
- AM_LOGE("alsa_handle[I2S_DEVICE] or alsa_status is NULL!");
- goto error;
- } else {
- ret = aml_alsa_output_get_alsa_status(alsa_handle, alsa_status);
+ if (!adev->injection_enable) {
+ if (NULL == alsa_handle || NULL == alsa_status) {
+ AM_LOGE("alsa_handle[I2S_DEVICE] or alsa_status is NULL!");
+ goto error;
+ } else {
+ ret = aml_alsa_output_get_alsa_status(alsa_handle, alsa_status);
+ }
}
error:
pthread_mutex_unlock(&adev->alsa_lock[I2S_DEVICE]);
@@ -217,14 +217,16 @@
pthread_mutex_lock(&adev->alsa_lock[I2S_DEVICE]);
alsa_handle = adev->alsa_handle[I2S_DEVICE];
- if (NULL == alsa_handle) {
- AM_LOGE("alsa_handle[I2S_DEVICE] is NULL!");
- struct pcm_config config;
- get_hardware_config_parameters(&config, AUDIO_FORMAT_PCM, adev->default_alsa_ch, 48000, false,
- false, is_low_latency_mode(adev));
- delay_frames = config.start_threshold;
- } else {
- delay_frames = aml_alsa_output_get_delay_frame(alsa_handle, ignore_default);
+ if (!adev->injection_enable) {
+ if (NULL == alsa_handle) {
+ AM_LOGE("alsa_handle[I2S_DEVICE] is NULL!");
+ struct pcm_config config;
+ get_hardware_config_parameters(&config, AUDIO_FORMAT_PCM, adev->default_alsa_ch, 48000, false,
+ false, is_low_latency_mode(adev));
+ delay_frames = config.start_threshold;
+ } else {
+ delay_frames = aml_alsa_output_get_delay_frame(alsa_handle, ignore_default);
+ }
}
error:
pthread_mutex_unlock(&adev->alsa_lock[I2S_DEVICE]);
@@ -396,11 +398,11 @@
#ifndef NO_AUDIO_CAP
/* 2ch downmix capture for nonetv platform*/
- pthread_mutex_lock(&adev->cap_buffer_lock);
- if (adev->cap_buffer) {
- IpcBuffer_write(adev->cap_buffer, (const unsigned char *)buffer, (int) bytes);
+ pthread_mutex_lock(&adev->cap_handle_lock);
+ if (adev->capture_handle) {
+ aml_audio_capture_out_write(adev->capture_handle, buffer, bytes);
}
- pthread_mutex_unlock(&adev->cap_buffer_lock);
+ pthread_mutex_unlock(&adev->cap_handle_lock);
#endif
if (is_TV(adev)) {
@@ -616,29 +618,35 @@
buffer, bytes, output_format);
}
- if (!adev->alsa_handle[I2S_DEVICE] && !adev->injection_enable) {
- AM_LOGI("pcm is null, open device");
- if (-1 == aml_audio_pcm_out_open(adev)) {
- AM_LOGE("aml_audio_pcm_out_open fail, hw write fail");
- return -1;
+ if (!adev->injection_enable) {
+ if (!adev->alsa_handle[I2S_DEVICE]) {
+ AM_LOGI("pcm is null, open device");
+ if (-1 == aml_audio_pcm_out_open(adev)) {
+ AM_LOGE("aml_audio_pcm_out_open fail, hw write fail");
+ return -1;
+ }
+ }
+
+ if (adev->alsa_handle[I2S_DEVICE] || adev->a2dp_hal || is_sco_port(adev->active_outport)) {
+//#ifdef ENABLE_BT_A2DP
+#ifndef BUILD_LINUX
+ if (adev->active_outport == OUTPORT_A2DP) {
+ ret = a2dp_out_write(adev, &in_data_config, buffer, bytes);
+ } else
+#endif
+ if (is_sco_port(adev->active_outport)) {
+ ret = write_to_sco(adev, &in_data_config, buffer, bytes);
+ } else {
+ ret = aml_audio_pcm_out_write(adev, buffer, bytes);
+ }
+ if (ret < 0) {
+ AM_LOGE("ALSA out write fail");
+ }
}
}
-
- if (adev->alsa_handle[I2S_DEVICE] || adev->a2dp_hal || is_sco_port(adev->active_outport)) {
- //#ifdef ENABLE_BT_A2DP
- #ifndef BUILD_LINUX
- if (adev->active_outport == OUTPORT_A2DP) {
- ret = a2dp_out_write(adev, &in_data_config, buffer, bytes);
- } else
- #endif
- if (is_sco_port(adev->active_outport)) {
- ret = write_to_sco(adev, &in_data_config, buffer, bytes);
- } else {
- ret = aml_audio_pcm_out_write(adev, buffer, bytes);
- }
- if (ret < 0) {
- AM_LOGE("ALSA out write fail");
- }
+ else if (!adev->capture_handle){
+ AM_LOGE("injection should enable together with capture, if not, sleep 5ms to avoid ms12 overrun!!");
+ aml_audio_sleep(5*1000);
}
if (adev->debug_flag > 1) {
diff --git a/audio_hal/aml_capture_output.c b/audio_hal/aml_capture_output.c
new file mode 100644
index 0000000..ae79015
--- /dev/null
+++ b/audio_hal/aml_capture_output.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 224 Amlogic Corporation.
+ *
+ * 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_capture_output"
+//#define LOG_NDEBUG 0
+
+
+#include <system/audio.h>
+#include <hardware/audio.h>
+#include <sys/timerfd.h>
+#ifndef NO_AUDIO_CAP
+#include <IpcBuffer/IpcBuffer_c.h>
+#endif
+#include "aml_audio_log.h"
+#include "audio_hw.h"
+#include "aml_capture_output.h"
+#include "aml_malloc_debug.h"
+#include "audio_hw_utils.h"
+#include "aml_dump_debug.h"
+#include "aml_audio_timer.h"
+
+#define IPC_BUFFER_CREATE_MAX_RETRY_ATTEMPTS (10)
+#define IPC_BUFFER_CREATE_RETRY_SLEEP_MS (5)
+#define CAPTURE_TIMER_INTERVAL_MS (10)
+#define CAPTURE_BUFFER_MIN_SIZE (4*48*32)
+
+typedef enum capture_location {
+ CAP_MIXER_OUTPUT = 0,
+ CAP_MIXER_INPUT,
+ CAP_LOCATION_MAX
+} capture_location_e;
+
+typedef struct aml_capture_handle {
+ void *cap_buffer;
+ enum capture_location cap_location;
+ int timer_fd;
+ pthread_t cap_process_threadID;
+ pthread_mutex_t cap_lock;
+ bool cap_process_exit;
+ bool is_cap_init;
+ bool cap_mute;
+ bool cap_start_detect;
+ ring_buffer_t cap_ringbuffer;
+ void *cap_ipcbuffer;
+ int cap_mm_delay;
+ int cap_dtv_delay;
+ int buffer_size;
+ void *cap_interleave_buffer;
+ void *cap_stereo_buffer;
+} aml_capture_handle_t;
+
+static int aml_start_timer_fd(int fd, uint32_t interval_ms)
+{
+ struct itimerspec i_timer_spec;
+ uint64_t interval_ns = (uint64_t)interval_ms*(uint64_t)1000000;
+
+ i_timer_spec.it_value.tv_sec = interval_ns/1000000000;
+ i_timer_spec.it_value.tv_nsec = interval_ns%1000000000;
+ i_timer_spec.it_interval.tv_sec = i_timer_spec.it_value.tv_sec;
+ i_timer_spec.it_interval.tv_nsec = i_timer_spec.it_value.tv_nsec;
+
+ return timerfd_settime(fd, 0, &i_timer_spec, NULL);
+}
+
+void *aml_audio_capture_process_threadloop(void *data)
+{
+ aml_capture_handle_t * p_capture = (aml_capture_handle_t *)data;
+ struct timespec ts;
+ int avail_bytes = 0;
+ size_t read_bytes = 0;
+ char *read_buffer = NULL;
+ int expect_read_bytes = CAPTURE_TIMER_INTERVAL_MS * 48 * 4;
+ bool is_start_play = false;
+ unsigned int count = 0;
+ uint64_t events = 0;
+ ssize_t read_ret = 0;
+
+ AM_LOGI("in");
+ read_buffer = aml_audio_calloc(1, expect_read_bytes);
+ if (!read_buffer) {
+ AM_LOGE("buffer calloc failed");
+ return NULL;
+ }
+
+ aml_set_thread_priority("audio capture thread", p_capture->cap_process_threadID, 30);
+
+ while (!p_capture->cap_process_exit) {
+ read_ret = read(p_capture->timer_fd, &events, sizeof(events));
+ while (events > 0) {
+ if (p_capture->is_cap_init) {
+ avail_bytes = get_buffer_read_space(&p_capture->cap_ringbuffer);
+ if (avail_bytes >= expect_read_bytes * 3 && !is_start_play) {
+ count = 0;
+ is_start_play = true;
+ AM_LOGI("Cap start play, threshold:%d ms", CAPTURE_TIMER_INTERVAL_MS * 3);
+ }
+
+ if (is_start_play) {
+ if (avail_bytes > expect_read_bytes) {
+ count = 0;
+ read_bytes = ring_buffer_read(&p_capture->cap_ringbuffer, read_buffer, expect_read_bytes);
+ } else {
+ if (++count >= 3) {
+ is_start_play = false;
+ }
+ read_bytes = expect_read_bytes;
+ memset(read_buffer, 0, read_bytes);
+ AM_LOGI("Cap ringbuffer underrun, conut:%d", count);
+ }
+ } else {
+ read_bytes = expect_read_bytes;
+ memset(read_buffer, 0, read_bytes);
+ }
+
+ if (aml_audio_property_get_bool("vendor.media.audiohal.mixer.capture", 0)) {
+ aml_dump_audio_bitstreams("capture.pcm", read_buffer, read_bytes);
+ }
+
+ pthread_mutex_lock(&p_capture->cap_lock);
+ IpcBuffer_write(p_capture->cap_ipcbuffer, (const unsigned char *)read_buffer, (int)read_bytes);
+ pthread_mutex_unlock(&p_capture->cap_lock);
+ }
+ --events;
+ }
+ }
+
+ aml_audio_free(read_buffer);
+ AM_LOGI("exit");
+ return NULL;
+}
+
+
+int aml_audio_capture_out_open(void ** phandle, char *name, int size)
+{
+ int ret = 0;
+ int signal_timer_id = -1;
+ int retry_count = 0;
+ aml_capture_handle_t * p_capture = (aml_capture_handle_t *)aml_audio_calloc(1, sizeof(aml_capture_handle_t));
+ if (p_capture == NULL) {
+ AM_LOGE("malloc aml_capture_handle_t failed\n");
+ return -1;
+ }
+ p_capture->buffer_size = size;
+ if (p_capture->buffer_size < CAPTURE_BUFFER_MIN_SIZE) {
+ AM_LOGI("capture buffer size(%d) is too small!!!", size);
+ }
+ if (!strcmp(name, "cap_mix_output")) {
+ p_capture->cap_location = CAP_MIXER_OUTPUT;
+ } else if (!strcmp(name, "cap_mix_input")) {
+ //to do
+ p_capture->cap_location = CAP_MIXER_INPUT;
+ p_capture->cap_interleave_buffer = (char *)aml_audio_calloc(1, size);
+ if (!p_capture->cap_interleave_buffer) {
+ AM_LOGE("Interleave buffer calloc size %d failed", size);
+ goto calloc_interleave_buffer_error;
+ }
+
+ p_capture->cap_stereo_buffer = (char *)aml_audio_calloc(1, size);
+ if (!p_capture->cap_stereo_buffer) {
+ AM_LOGE("Stereo buffer calloc size %d failed", size);
+ goto calloc_stereo_buffer_error;
+ }
+ } else {
+ AM_LOGE("Unsupported capture location:%s", name);
+ goto capture_location_error;
+ }
+
+ pthread_mutex_lock(&p_capture->cap_lock);
+ while (retry_count < IPC_BUFFER_CREATE_MAX_RETRY_ATTEMPTS) {
+ p_capture->cap_ipcbuffer = IpcBuffer_create(name, size);
+ if (!p_capture->cap_ipcbuffer) {
+ AM_LOGE("Create IPC buffer failed (attempt %d)", retry_count +1);
+ retry_count++;
+ usleep(IPC_BUFFER_CREATE_RETRY_SLEEP_MS * 1000); // Sleep for 5 milliseconds
+ } else {
+ AM_LOGI("Create IPC buffer succeeded, point[%p]:(%s, %d)", p_capture->cap_ipcbuffer, name, size);
+ break; // Successfully created IPC buffer, exit loop
+ }
+ }
+ pthread_mutex_unlock(&p_capture->cap_lock);
+
+ if (retry_count == IPC_BUFFER_CREATE_MAX_RETRY_ATTEMPTS) {
+ AM_LOGE("Create IPC buffer failed after %d attempts", IPC_BUFFER_CREATE_MAX_RETRY_ATTEMPTS);
+ goto calloc_stereo_buffer_error;
+ }
+
+ ret = ring_buffer_init(&p_capture->cap_ringbuffer, size);
+ if (ret != 0) {
+ AM_LOGE("Init ring buffer failed");
+ goto init_ring_buffer_error;
+ }
+
+ p_capture->timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (p_capture->timer_fd < 0) {
+ AM_LOGE("Create timerfd failed");
+ goto create_timer_fd_error;
+ }
+
+ ret = aml_start_timer_fd(p_capture->timer_fd, CAPTURE_TIMER_INTERVAL_MS);
+ if (ret < 0) {
+ AM_LOGE("Start timerfd failed");
+ goto start_timer_fd_error;
+ }
+ p_capture->cap_process_exit = false;
+ ret = pthread_create(&p_capture->cap_process_threadID, NULL, &aml_audio_capture_process_threadloop, p_capture);
+ if (ret != 0) {
+ AM_LOGE("Can't create thread: %s", strerror(ret));
+ goto create_pthread_error;
+ }
+
+ p_capture->is_cap_init = true;
+ *phandle = (void *)p_capture;
+
+ return 0;
+
+create_pthread_error:
+start_timer_fd_error:
+ close(p_capture->timer_fd);
+create_timer_fd_error:
+ ring_buffer_release(&p_capture->cap_ringbuffer);
+init_ring_buffer_error:
+ pthread_mutex_lock(&p_capture->cap_lock);
+ if (p_capture->cap_ipcbuffer) {
+ IpcBuffer_destroy(p_capture->cap_ipcbuffer);
+ p_capture->cap_ipcbuffer = NULL;
+ }
+ pthread_mutex_unlock(&p_capture->cap_lock);
+calloc_stereo_buffer_error:
+ if (p_capture->cap_interleave_buffer) {
+ aml_audio_free(p_capture->cap_interleave_buffer);
+ p_capture->cap_interleave_buffer = NULL;
+ }
+calloc_interleave_buffer_error:
+capture_location_error:
+ aml_audio_free(p_capture);
+ return -1;
+
+}
+int aml_audio_capture_out_close(void * handle)
+{
+ aml_capture_handle_t * p_capture = (aml_capture_handle_t *)handle;
+ int ret = 0;
+
+ p_capture->is_cap_init = false;
+ if (p_capture->cap_location == CAP_MIXER_INPUT) {
+ //to do
+ }
+
+ if (p_capture->cap_interleave_buffer) {
+ aml_audio_free(p_capture->cap_interleave_buffer);
+ p_capture->cap_interleave_buffer = NULL;
+ }
+
+ if (p_capture->cap_stereo_buffer) {
+ aml_audio_free(p_capture->cap_stereo_buffer);
+ p_capture->cap_stereo_buffer = NULL;
+ }
+
+ p_capture->cap_process_exit = true;
+ ret = pthread_join(p_capture->cap_process_threadID, NULL);
+ if (ret != 0) {
+ AM_LOGE("pthread join failed");
+ }
+ close(p_capture->timer_fd);
+
+ pthread_mutex_lock(&p_capture->cap_lock);
+ if (p_capture->cap_ipcbuffer) {
+ IpcBuffer_destroy(p_capture->cap_ipcbuffer);
+ p_capture->cap_ipcbuffer = NULL;
+ }
+ pthread_mutex_unlock(&p_capture->cap_lock);
+
+ ring_buffer_release(&p_capture->cap_ringbuffer);
+
+ aml_audio_free(handle);
+}
+int aml_audio_capture_out_write(void * handle, const void *buffer, size_t bytes)
+{
+ aml_capture_handle_t * p_capture = (aml_capture_handle_t *)handle;
+ int ret = 0;
+ int retry = false;
+ int avail_bytes = 0;
+ void *audio_cap_buf = (void *)buffer;
+ size_t audio_cap_used_size = bytes;
+
+ if (p_capture->is_cap_init && p_capture->cap_location == CAP_MIXER_OUTPUT) {
+ do {
+ avail_bytes = get_buffer_write_space(&p_capture->cap_ringbuffer);
+ if (avail_bytes >= audio_cap_used_size) {
+ retry = false;
+ ret = ring_buffer_write(&p_capture->cap_ringbuffer, audio_cap_buf, audio_cap_used_size, UNCOVER_WRITE);
+ if (ret != audio_cap_used_size) {
+ AM_LOGE("Write buffer fails!");
+ }
+ } else if (avail_bytes > 0) {
+ retry = true;
+ ret = ring_buffer_write(&p_capture->cap_ringbuffer, audio_cap_buf, avail_bytes, UNCOVER_WRITE);
+ if (ret != avail_bytes) {
+ AM_LOGE("Write buffer fails!");
+ }
+ audio_cap_used_size = audio_cap_used_size - avail_bytes;
+ memmove(audio_cap_buf, audio_cap_buf + avail_bytes, audio_cap_used_size);
+ } else {
+ retry = true;
+ aml_audio_sleep(CAPTURE_TIMER_INTERVAL_MS * 1000);
+ }
+ } while (retry && p_capture->is_cap_init);
+ }
+
+ return ret;
+}
+int aml_audio_capture_out_reset(void * handle)
+{
+ aml_capture_handle_t * p_capture = (aml_capture_handle_t *)handle;
+ if (p_capture->is_cap_init) {
+ AM_LOGI("reset capture buffer");
+ ring_buffer_reset(&p_capture->cap_ringbuffer);
+ }
+}
+
+int aml_audio_capture_out_dump(void * handle, int fd) {
+ aml_capture_handle_t * p_capture = (aml_capture_handle_t *)handle;
+ if (p_capture->is_cap_init) {
+ dprintf(fd, "[AML_HAL] cap_location : %d, timer fd: %d\n", p_capture->cap_location, p_capture->timer_fd);
+ dprintf(fd, "[AML_HAL] mute : %d\n", p_capture->cap_mute);
+ dprintf(fd, "[AML_HAL] buffer size : %d, avail size : %d\n", p_capture->buffer_size, get_buffer_read_space(&p_capture->cap_ringbuffer));
+ }
+}
diff --git a/audio_hal/aml_capture_output.h b/audio_hal/aml_capture_output.h
new file mode 100644
index 0000000..854d671
--- /dev/null
+++ b/audio_hal/aml_capture_output.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 Amlogic Corporation.
+ *
+ * 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.
+ */
+
+#ifndef _AML_CAPTURE_OUTPUT_H_
+#define _AML_CAPTURE_OUTPUT_H_
+
+int aml_audio_capture_out_open(void ** phandle, char *name, int size);
+int aml_audio_capture_out_close(void * handle);
+int aml_audio_capture_out_write(void * handle, const void *buffer, size_t bytes);
+int aml_audio_capture_out_reset(void * handle);
+int aml_audio_capture_out_dump(void * handle, int fd);
+#endif // _AML_CAPTURE_OUTPUT_H_
diff --git a/audio_hal/audio_hw.c b/audio_hal/audio_hw.c
index d6b6a3c..536f6f6 100644
--- a/audio_hal/audio_hw.c
+++ b/audio_hal/audio_hw.c
@@ -58,9 +58,9 @@
#include <aml_android_utils.h>
#include <aml_alsa_mixer.h>
#ifndef NO_AUDIO_CAP
- #include <IpcBuffer/IpcBuffer_c.h>
+#include <IpcBuffer/IpcBuffer_c.h>
#endif
-
+#include "aml_capture_output.h"
#include "tv_patch_format_parser.h"
#include "SPDIFEncoderAD.h"
#include "aml_volume_utils.h"
@@ -4762,22 +4762,23 @@
if (name) {
size = atoi(name + strlen(name) + 1);
if (size > 0) {
- pthread_mutex_lock(&adev->cap_buffer_lock);
- if (adev->cap_buffer) {
- IpcBuffer_destroy(adev->cap_buffer);
+ pthread_mutex_lock(&adev->cap_handle_lock);
+ if (adev->capture_handle) {
+ aml_audio_capture_out_close(adev->capture_handle);
+ adev->capture_handle = NULL;
}
- adev->cap_buffer = IpcBuffer_create(name, size);
- AM_LOGI("IpcBuffer_created %p (%s, %d)", adev->cap_buffer, name, size);
- pthread_mutex_unlock(&adev->cap_buffer_lock);
+ aml_audio_capture_out_open(&adev->capture_handle, name, size);
+ AM_LOGI("IpcBuffer_created %p (%s, %d)", adev->capture_handle, name, size);
+ pthread_mutex_unlock(&adev->cap_handle_lock);
ret = 0;
goto exit;
} else if (size == 0) {
- pthread_mutex_lock(&adev->cap_buffer_lock);
- if (adev->cap_buffer) {
- IpcBuffer_destroy(adev->cap_buffer);
- adev->cap_buffer = NULL;
+ pthread_mutex_lock(&adev->cap_handle_lock);
+ if (adev->capture_handle) {
+ aml_audio_capture_out_close(adev->capture_handle);
+ adev->capture_handle = NULL;
}
- pthread_mutex_unlock(&adev->cap_buffer_lock);
+ pthread_mutex_unlock(&adev->cap_handle_lock);
ret = 0;
goto exit;
}
@@ -4785,10 +4786,18 @@
ret = -EINVAL;
goto exit;
}
- ret = str_parms_get_str(parms, "cap_delay", value, sizeof(value));
+
+ ret = str_parms_get_str(parms, "cap_mm_delay", value, sizeof(value));
if (ret >= 0) {
- adev->cap_delay = atoi(value);
- ret = 0;
+ adev->cap_mm_delay = atoi(value);
+ AM_LOGI("cap_delay=%d",adev->cap_mm_delay);
+ goto exit;
+ }
+
+ ret = str_parms_get_str(parms, "cap_dtv_delay", value, sizeof(value));
+ if (ret >= 0) {
+ adev->cap_dtv_delay = atoi(value);
+ AM_LOGI("cap_dtv_delay=%d",adev->cap_dtv_delay);
goto exit;
}
#endif
@@ -5050,10 +5059,23 @@
ret = str_parms_get_int(parms, "audioinject", &val);
if (ret >= 0) {
if (val == 1) {
+ adev->injection_enable = 1;
+ // injection must be used with capture together
+ pthread_mutex_lock(&adev->cap_handle_lock);
+ if (!adev->capture_handle) {
+ AM_LOGE("injection must be used with capture together!!! please check !!!");
+ }
+ pthread_mutex_unlock(&adev->cap_handle_lock);
+ //set PCM output to close spdif handle
+ set_hdmi_format(adev, PCM);
AM_LOGI("close pcm out");
aml_audio_pcm_out_close(adev);
- adev->injection_enable = 1;
} else {
+ pthread_mutex_lock(&adev->cap_handle_lock);
+ if (adev->capture_handle) {
+ aml_audio_capture_out_reset(adev->capture_handle);
+ }
+ pthread_mutex_unlock(&adev->cap_handle_lock);
adev->injection_enable = 0;
}
goto exit;
@@ -7741,6 +7763,14 @@
dprintf(fd, "\n");
dprintf(fd, "[AML_HAL] hdmi_format : %10d | active_outport : %s | active_inport: %s\n",
aml_dev->hdmi_format, outputPort2Str(aml_dev->active_outport), inputPort2Str(get_active_inport(aml_dev)));
+ dprintf(fd, "[AML_HAL] injection : %d\n", aml_dev->injection_enable);
+ pthread_mutex_lock(&aml_dev->cap_handle_lock);
+ dprintf(fd, "[AML_HAL] capture enable : %d\n", aml_dev->capture_handle ? 1 :0);
+ if (aml_dev->capture_handle) {
+ aml_audio_capture_out_dump(aml_dev->capture_handle, fd);
+ }
+ pthread_mutex_unlock(&aml_dev->cap_handle_lock);
+
dprintf(fd, "[AML_HAL] audio_effect_enable : %10d | stream_write_data : %d\n",
aml_dev->last_audio_effect_enable, aml_dev->stream_write_data);
dprintf(fd, "[AML_HAL] A2DP gain : %10f \n",
@@ -8586,7 +8616,7 @@
aml_audio_debug_open(aml_get_jason_string_value("DUMP_DEFAULT_PATH"));
#ifndef NO_AUDIO_CAP
- pthread_mutex_init(&adev->cap_buffer_lock, NULL);
+ pthread_mutex_init(&adev->cap_handle_lock, NULL);
#endif
//set DRC default as RF
diff --git a/audio_hal/audio_hw.h b/audio_hal/audio_hw.h
index 68eda67..52a5cef 100644
--- a/audio_hal/audio_hw.h
+++ b/audio_hal/audio_hw.h
@@ -563,9 +563,10 @@
float record_volume_before_mute;//Record the master volume before mute
#ifndef NO_AUDIO_CAP
/* CapTure IpcBuffer */
- pthread_mutex_t cap_buffer_lock;
- void *cap_buffer;
- int cap_delay;
+ void * capture_handle;
+ pthread_mutex_t cap_handle_lock;
+ int cap_mm_delay;
+ int cap_dtv_delay;
#endif
int synctype; //tsplayer TS mode input set
int injection_enable;
diff --git a/input/dtv_patch_hal_avsync.c b/input/dtv_patch_hal_avsync.c
index d88d03c..2e8c8d9 100644
--- a/input/dtv_patch_hal_avsync.c
+++ b/input/dtv_patch_hal_avsync.c
@@ -773,8 +773,8 @@
}
#ifndef NO_AUDIO_CAP
/*coverity[missing_lock]: aml_dev->cap_buffer does not need to be lock*/
- if (aml_dev->cap_buffer) {
- tuning_ms += aml_dev->cap_delay;
+ if (aml_dev->capture_handle) {
+ tuning_ms += aml_dev->cap_dtv_delay;
} else {
tuning_ms += aml_audio_property_get_int(PROPERTY_LOCAL_PASSTHROUGH_LATENCY, 0);
}