hal: add audio ip handler support to loopback extension
Add support to call audio ip handler APIs from loopback extension
for secure dolby playback.
Change-Id: I24686aaae84dbaf4f5a304404bc0009e153ded26
diff --git a/hal/audio_extn/hw_loopback.c b/hal/audio_extn/hw_loopback.c
index ddca6b8..8e577c2 100644
--- a/hal/audio_extn/hw_loopback.c
+++ b/hal/audio_extn/hw_loopback.c
@@ -215,6 +215,9 @@
int32_t ret = 0;
struct audio_usecase *uc_info;
struct audio_device *adev = audio_loopback_mod->adev;
+ struct stream_inout *inout = &active_loopback_patch->patch_stream;
+ struct audio_port_config *source_patch_config = &active_loopback_patch->
+ loopback_source;
/* 1. Close the PCM devices */
if (active_loopback_patch->source_stream) {
@@ -251,10 +254,41 @@
list_remove(&uc_info->list);
free(uc_info);
+ if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format) && inout->ip_hdlr_handle) {
+ ret = audio_extn_ip_hdlr_intf_close(inout->ip_hdlr_handle, true, inout);
+ if (ret < 0)
+ ALOGE("%s: audio_extn_ip_hdlr_intf_close failed %d",__func__, ret);
+ }
+
+ /* close adsp hdrl session before standby */
+ if (inout->adsp_hdlr_stream_handle) {
+ ret = audio_extn_adsp_hdlr_stream_close(inout->adsp_hdlr_stream_handle);
+ if (ret)
+ ALOGE("%s: adsp_hdlr_stream_close failed %d",__func__, ret);
+ inout->adsp_hdlr_stream_handle = NULL;
+ }
+
+ if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format) &&
+ inout->ip_hdlr_handle) {
+ audio_extn_ip_hdlr_intf_deinit(inout->ip_hdlr_handle);
+ inout->ip_hdlr_handle = NULL;
+ }
+
ALOGD("%s: Release loopback session exit: status(%d)", __func__, ret);
return ret;
}
+/* Callback funtion called in the case of failures */
+int loopback_stream_cb(stream_callback_event_t event, void *param, void *cookie)
+{
+ if (event == AUDIO_EXTN_STREAM_CBK_EVENT_ERROR) {
+ pthread_mutex_lock(&audio_loopback_mod->lock);
+ release_loopback_session(cookie);
+ pthread_mutex_unlock(&audio_loopback_mod->lock);
+ }
+ return 0;
+}
+
/* Create a loopback session based on active loopback patch selected */
int create_loopback_session(loopback_patch_t *active_loopback_patch)
{
@@ -269,6 +303,8 @@
loopback_source;
struct audio_port_config *sink_patch_config = &active_loopback_patch->
loopback_sink;
+ struct stream_inout *inout = &active_loopback_patch->patch_stream;
+ struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
ALOGD("%s: Create loopback session begin", __func__);
@@ -303,6 +339,29 @@
ALOGD("%s: LOOPBACK PCM devices (rx: %d tx: %d) usecase(%d)",
__func__, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id, uc_info->id);
+ /* setup a channel for client <--> adsp communication for stream events */
+ inout->dev = adev;
+ inout->client_callback = loopback_stream_cb;
+ inout->client_cookie = active_loopback_patch;
+ hdlr_stream_cfg.pcm_device_id = pcm_dev_asm_rx_id;
+ hdlr_stream_cfg.flags = 0;
+ hdlr_stream_cfg.type = PCM_PLAYBACK;
+ ret = audio_extn_adsp_hdlr_stream_open(&inout->adsp_hdlr_stream_handle,
+ &hdlr_stream_cfg);
+ if (ret) {
+ ALOGE("%s: adsp_hdlr_stream_open failed %d", __func__, ret);
+ inout->adsp_hdlr_stream_handle = NULL;
+ goto exit;
+ }
+ if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format)) {
+ ret = audio_extn_ip_hdlr_intf_init(&inout->ip_hdlr_handle, NULL, NULL);
+ if (ret < 0) {
+ ALOGE("%s: audio_extn_ip_hdlr_intf_init failed %d", __func__, ret);
+ inout->ip_hdlr_handle = NULL;
+ goto exit;
+ }
+ }
+
if (source_patch_config->format == AUDIO_FORMAT_IEC61937) {
// This is needed to set a known format to DSP and handle
// any format change via ADSP event
@@ -378,6 +437,14 @@
ret = -EINVAL;
goto exit;
}
+ if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format) && inout->ip_hdlr_handle) {
+ ret = audio_extn_ip_hdlr_intf_open(inout->ip_hdlr_handle, true, inout,
+ USECASE_AUDIO_TRANSCODE_LOOPBACK);
+ if (ret < 0) {
+ ALOGE("%s: audio_extn_ip_hdlr_intf_open failed %d",__func__, ret);
+ goto exit;
+ }
+ }
/* Move patch state to running, now that session is set up */
active_loopback_patch->patch_state = PATCH_RUNNING;
@@ -411,6 +478,7 @@
int status = 0;
patch_handle_type_t loopback_patch_type=0x0;
loopback_patch_t loopback_patch, *active_loopback_patch = NULL;
+
ALOGV("%s : Create audio patch begin", __func__);
if ((audio_loopback_mod == NULL) || (dev == NULL)) {
diff --git a/hal/audio_extn/ip_hdlr_intf.c b/hal/audio_extn/ip_hdlr_intf.c
index 411b16f..4242d68 100644
--- a/hal/audio_extn/ip_hdlr_intf.c
+++ b/hal/audio_extn/ip_hdlr_intf.c
@@ -42,6 +42,7 @@
#define LIB_PATH "/system/vendor/lib/libaudio_ip_handler.so"
#endif
+#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include <dlfcn.h>
@@ -57,6 +58,12 @@
#define ADSP_EVENT_ID_RTIC 0x00013239
#define ADSP_EVENT_ID_RTIC_FAIL 0x0001323A
+struct ip_hdlr_stream {
+ struct listnode list;
+ void *stream;
+ audio_usecase_t usecase;
+};
+
struct ip_hdlr_intf {
void *lib_hdl;
int (*init)(void **handle, char *lib_path, void **lib_handle);
@@ -67,6 +74,8 @@
int (*event)(void *handle, void *payload);
int (*reg_cb)(void *handle, void *ack_cb, void *fail_cb);
+ struct listnode stream_list;
+ pthread_mutex_t stream_list_lock;
int ref_cnt;
};
static struct ip_hdlr_intf *ip_hdlr = NULL;
@@ -109,9 +118,7 @@
bool audio_extn_ip_hdlr_intf_supported(audio_format_t format)
{
- if ((format & AUDIO_FORMAT_MAIN_MASK == AUDIO_FORMAT_AC3) ||
- (format & AUDIO_FORMAT_MAIN_MASK == AUDIO_FORMAT_E_AC3) ||
- (format & AUDIO_FORMAT_MAIN_MASK == AUDIO_FORMAT_DOLBY_TRUEHD))
+ if ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_DOLBY_TRUEHD)
return true;
else
return false;
@@ -132,8 +139,37 @@
struct mixer_ctl *ctl = NULL;
struct stream_out *out = (struct stream_out *)aud_sess_handle;
struct rtic_ack_param param;
+ struct listnode *node, *tempnode;
+ struct ip_hdlr_stream *stream_info;
+ struct audio_device *adev = NULL;
+ audio_usecase_t usecase = 0;
- pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
+ pthread_mutex_lock(&ip_hdlr->stream_list_lock);
+ list_for_each_safe(node, tempnode, &ip_hdlr->stream_list) {
+ stream_info = node_to_item(node, struct ip_hdlr_stream, list);
+ /* send the error if rtic failure notifcation is received */
+ if ((stream_info->stream == aud_sess_handle) &&
+ (stream_info->usecase == USECASE_AUDIO_TRANSCODE_LOOPBACK)) {
+ struct stream_inout *inout = (struct stream_inout *)aud_sess_handle;
+ usecase = stream_info->usecase;
+ adev = inout->dev;
+ break;
+ } else if (stream_info->stream == aud_sess_handle) {
+ struct stream_out *out = (struct stream_out *)aud_sess_handle;
+ usecase = stream_info->usecase;
+ adev = out->dev;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&ip_hdlr->stream_list_lock);
+
+ if (adev == NULL) {
+ ALOGE("%s:[%d] Invalid adev", __func__, ip_hdlr->ref_cnt);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pcm_device_id = platform_get_pcm_device_id(usecase, PCM_PLAYBACK);
ALOGVV("%s:[%d] token = %d, info->status = %d, pcm_id = %d",__func__,
ip_hdlr->ref_cnt, info->token, info->status, pcm_device_id);
@@ -146,7 +182,7 @@
ret = -EINVAL;
goto done;
}
- ctl = mixer_get_ctl_by_name(out->dev->mixer, mixer_ctl_name);
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
if (!ctl) {
ALOGE("%s:[%d] Could not get ctl for mixer cmd - %s", __func__,
ip_hdlr->ref_cnt, mixer_ctl_name);
@@ -167,37 +203,56 @@
return ret;
}
-/* Acquire Mutex lock on output stream */
-static void lock_output_stream(struct stream_out *out)
-{
- pthread_mutex_lock(&out->pre_lock);
- pthread_mutex_lock(&out->lock);
- pthread_mutex_unlock(&out->pre_lock);
-}
-
int audio_extn_ip_hdlr_intf_rtic_fail(void *aud_sess_handle)
{
- struct stream_out *out = (struct stream_out *)aud_sess_handle;
+ struct listnode *node, *tempnode;
+ struct ip_hdlr_stream *stream_info;
ALOGD("%s:[%d] sess_handle = %p",__func__, ip_hdlr->ref_cnt, aud_sess_handle);
- /* send the error if rtic fail notifcation is received */
- lock_output_stream(out);
- if (out && out->client_callback)
- out->client_callback(AUDIO_EXTN_STREAM_CBK_EVENT_ERROR, NULL, out->client_cookie);
- pthread_mutex_unlock(&out->lock);
+ pthread_mutex_lock(&ip_hdlr->stream_list_lock);
+ list_for_each_safe(node, tempnode, &ip_hdlr->stream_list) {
+ stream_info = node_to_item(node, struct ip_hdlr_stream, list);
+ /* send the error if rtic failure notifcation is received */
+ if ((stream_info->stream == aud_sess_handle) &&
+ (stream_info->usecase == USECASE_AUDIO_TRANSCODE_LOOPBACK)) {
+ struct stream_inout *inout = (struct stream_inout *)aud_sess_handle;
+ pthread_mutex_lock(&inout->pre_lock);
+ pthread_mutex_lock(&inout->lock);
+ pthread_mutex_unlock(&inout->pre_lock);
+ ALOGVV("%s:[%d] calling client callback", __func__, ip_hdlr->ref_cnt);
+ if (inout && inout->client_callback)
+ inout->client_callback(AUDIO_EXTN_STREAM_CBK_EVENT_ERROR, NULL, inout->client_cookie);
+ pthread_mutex_unlock(&inout->lock);
+ break;
+ } else if (stream_info->stream == aud_sess_handle) {
+ struct stream_out *out = (struct stream_out *)aud_sess_handle;
+ pthread_mutex_lock(&out->pre_lock);
+ pthread_mutex_lock(&out->lock);
+ pthread_mutex_unlock(&out->pre_lock);
+ ALOGVV("%s:[%d] calling client callback", __func__, ip_hdlr->ref_cnt);
+ if (out && out->client_callback)
+ out->client_callback(AUDIO_EXTN_STREAM_CBK_EVENT_ERROR, NULL, out->client_cookie);
+ pthread_mutex_unlock(&out->lock);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&ip_hdlr->stream_list_lock);
return 0;
}
-static int audio_extn_ip_hdlr_intf_open_dsp(void *handle, void *stream_handle)
+static int audio_extn_ip_hdlr_intf_open_dsp(void *handle, void *stream_handle, audio_usecase_t usecase)
{
int ret = 0, fd = 0, pcm_device_id = 0;
struct audio_adsp_event *param;
struct reg_event *reg_ev;
size_t shm_size;
void *shm_buf;;
- struct stream_out *out = (struct stream_out *)stream_handle;
+ struct stream_out *out;
+ struct stream_inout *inout;
+ void *adsp_hdlr_stream_handle;
+ struct audio_device *dev = NULL;
struct mixer_ctl *ctl = NULL;
char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
@@ -220,8 +275,18 @@
param->payload_length = sizeof(struct reg_event);
param->payload = reg_ev;
+ if (usecase == USECASE_AUDIO_TRANSCODE_LOOPBACK) {
+ inout = (struct stream_inout *)stream_handle;
+ adsp_hdlr_stream_handle = inout->adsp_hdlr_stream_handle;
+ dev = inout->dev;
+ } else {
+ out = (struct stream_out *)stream_handle;
+ adsp_hdlr_stream_handle = out->adsp_hdlr_stream_handle;
+ dev = out->dev;
+ }
+
/* Register for event and its callback */
- ret = audio_extn_adsp_hdlr_stream_register_event(out->adsp_hdlr_stream_handle, param,
+ ret = audio_extn_adsp_hdlr_stream_register_event(adsp_hdlr_stream_handle, param,
audio_extn_ip_hdlr_intf_event,
handle);
if (ret < 0) {
@@ -231,16 +296,17 @@
ip_hdlr->reg_cb(handle, &audio_extn_ip_hdlr_intf_rtic_ack, &audio_extn_ip_hdlr_intf_rtic_fail);
ip_hdlr->shm_info(handle, &fd);
- ALOGV("%s: fd = %d", __func__, fd);
- pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
+ pcm_device_id = platform_get_pcm_device_id(usecase, PCM_PLAYBACK);
ret = snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
"Playback ION FD %d", pcm_device_id);
if (ret < 0) {
ALOGE("%s:[%d] snprintf failed",__func__, ip_hdlr->ref_cnt, ret);
goto done;
}
- ctl = mixer_get_ctl_by_name(out->dev->mixer, mixer_ctl_name);
+ ALOGV("%s: fd = %d pcm_id = %d", __func__, fd, pcm_device_id);
+
+ ctl = mixer_get_ctl_by_name(dev->mixer, mixer_ctl_name);
if (!ctl) {
ALOGE("%s:[%d] Could not get ctl for mixer cmd - %s", __func__,
ip_hdlr->ref_cnt, mixer_ctl_name);
@@ -260,28 +326,39 @@
return ret;
}
-int audio_extn_ip_hdlr_intf_open(void *handle, bool is_dsp_decode, void *aud_sess_handle)
+int audio_extn_ip_hdlr_intf_open(void *handle, bool is_dsp_decode,
+ void *aud_sess_handle, audio_usecase_t usecase)
{
int ret = 0;
+ struct ip_hdlr_stream *stream_info;
if (!handle || !aud_sess_handle) {
ALOGE("%s:[%d] Invalid arguments, handle %p", __func__, ip_hdlr->ref_cnt, handle);
return -EINVAL;
}
+ stream_info = (struct ip_hdlr_stream *)calloc(1, sizeof(struct ip_hdlr_stream));
+ if (!stream_info)
+ return -ENOMEM;
+ stream_info->stream = aud_sess_handle;
+ stream_info->usecase = usecase;
+
ret = ip_hdlr->open(handle, is_dsp_decode, aud_sess_handle);
if (ret < 0) {
ALOGE("%s:[%d] open failed", __func__, ip_hdlr->ref_cnt);
return -EINVAL;
}
- ALOGD("%s:[%d] handle = %p, sess_handle = %p, is_dsp_decode = %d",__func__,
- ip_hdlr->ref_cnt, handle, aud_sess_handle, is_dsp_decode);
+ ALOGD("%s:[%d] handle = %p, sess_handle = %p, is_dsp_decode = %d, usecase = %d",
+ __func__, ip_hdlr->ref_cnt, handle, aud_sess_handle, is_dsp_decode, usecase);
if (is_dsp_decode) {
- ret = audio_extn_ip_hdlr_intf_open_dsp(handle, aud_sess_handle);
+ ret = audio_extn_ip_hdlr_intf_open_dsp(handle, aud_sess_handle, usecase);
if (ret < 0)
ip_hdlr->close(handle);
}
+ pthread_mutex_lock(&ip_hdlr->stream_list_lock);
+ list_add_tail(&ip_hdlr->stream_list, &stream_info->list);
+ pthread_mutex_unlock(&ip_hdlr->stream_list_lock);
done:
return ret;
}
@@ -289,24 +366,46 @@
int audio_extn_ip_hdlr_intf_close(void *handle, bool is_dsp_decode, void *aud_sess_handle)
{
struct audio_adsp_event param;
+ void *adsp_hdlr_stream_handle;
+ struct listnode *node, *tempnode;
+ struct ip_hdlr_stream *stream_info;
+ audio_usecase_t usecase = 0;
int ret = 0;
if (!handle) {
ALOGE("%s:[%d] handle is NULL", __func__, ip_hdlr->ref_cnt);
return -EINVAL;
}
- ALOGD("%s:[%d] handle = %p",__func__, ip_hdlr->ref_cnt, handle);
ret = ip_hdlr->close(handle);
if (ret < 0)
ALOGE("%s:[%d] close failed", __func__, ip_hdlr->ref_cnt);
+ pthread_mutex_lock(&ip_hdlr->stream_list_lock);
+ list_for_each_safe(node, tempnode, &ip_hdlr->stream_list) {
+ stream_info = node_to_item(node, struct ip_hdlr_stream, list);
+ if (stream_info->stream == aud_sess_handle) {
+ usecase = stream_info->usecase;
+ list_remove(node);
+ free(stream_info);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&ip_hdlr->stream_list_lock);
+ ALOGD("%s:[%d] handle = %p, usecase = %d",__func__, ip_hdlr->ref_cnt, handle, usecase);
+
if (is_dsp_decode) {
- struct stream_out *out = (struct stream_out *)aud_sess_handle;
+ if (usecase == USECASE_AUDIO_TRANSCODE_LOOPBACK) {
+ struct stream_inout *inout = (struct stream_inout *)aud_sess_handle;
+ adsp_hdlr_stream_handle = inout->adsp_hdlr_stream_handle;
+ } else {
+ struct stream_out *out = (struct stream_out *)aud_sess_handle;
+ adsp_hdlr_stream_handle = out->adsp_hdlr_stream_handle;
+ }
param.event_type = AUDIO_STREAM_ENCDEC_EVENT;
param.payload_length = 0;
/* Deregister the event */
- ret = audio_extn_adsp_hdlr_stream_deregister_event(out->adsp_hdlr_stream_handle, ¶m);
+ ret = audio_extn_adsp_hdlr_stream_deregister_event(adsp_hdlr_stream_handle, ¶m);
if (ret < 0)
ALOGE("%s:[%d] event deregister failed", __func__, ip_hdlr->ref_cnt);
}
@@ -323,6 +422,9 @@
if (!ip_hdlr)
return -ENOMEM;
+ list_init(&ip_hdlr->stream_list);
+ pthread_mutex_init(&ip_hdlr->stream_list_lock, (const pthread_mutexattr_t *) NULL);
+
ip_hdlr->lib_hdl = dlopen(LIB_PATH, RTLD_NOW);
if (ip_hdlr->lib_hdl == NULL) {
ALOGE("%s: DLOPEN failed, %s", __func__, dlerror());
@@ -365,6 +467,7 @@
dlclose:
dlclose(ip_hdlr->lib_hdl);
err:
+ pthread_mutex_destroy(&ip_hdlr->stream_list_lock);
free(ip_hdlr);
ip_hdlr = NULL;
return ret;
@@ -387,6 +490,7 @@
if (ip_hdlr->lib_hdl)
dlclose(ip_hdlr->lib_hdl);
+ pthread_mutex_destroy(&ip_hdlr->stream_list_lock);
free(ip_hdlr);
ip_hdlr == NULL;
}
diff --git a/hal/audio_extn/ip_hdlr_intf.h b/hal/audio_extn/ip_hdlr_intf.h
index 01d0b7b..e8a9166 100644
--- a/hal/audio_extn/ip_hdlr_intf.h
+++ b/hal/audio_extn/ip_hdlr_intf.h
@@ -32,7 +32,8 @@
#ifdef AUDIO_EXTN_IP_HDLR_ENABLED
-int audio_extn_ip_hdlr_intf_open(void *handle, bool is_dsp_decode, void *aud_sess_handle);
+int audio_extn_ip_hdlr_intf_open(void *handle, bool is_dsp_decode, void *aud_sess_handle,
+ audio_usecase_t usecase);
int audio_extn_ip_hdlr_intf_close(void *handle, bool is_dsp_decode, void *aud_sess_handle);
int audio_extn_ip_hdlr_intf_init(void **handle, char *lib_path, void **lib_handle);
int audio_extn_ip_hdlr_intf_deinit(void *handle);
@@ -40,7 +41,7 @@
#else
-#define audio_extn_ip_hdlr_intf_open(handle, is_dsp_decode, aud_sess_handle) (0)
+#define audio_extn_ip_hdlr_intf_open(handle, is_dsp_decode, aud_sess_handle, usecase) (0)
#define audio_extn_ip_hdlr_intf_close(handle, is_dsp_decode, aud_sess_handle) (0)
#define audio_extn_ip_hdlr_intf_init(handle, lib_path, lib_handle) (0)
#define audio_extn_ip_hdlr_intf_deinit(handle) (0)
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 6375ec5..2228106 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2543,7 +2543,7 @@
ALOGD("%s: exit", __func__);
if (audio_extn_ip_hdlr_intf_supported(out->format) && out->ip_hdlr_handle) {
- ret = audio_extn_ip_hdlr_intf_open(out->ip_hdlr_handle, true, out);
+ ret = audio_extn_ip_hdlr_intf_open(out->ip_hdlr_handle, true, out, out->usecase);
if (ret < 0)
ALOGE("%s: audio_extn_ip_hdlr_intf_open failed %d",__func__, ret);
}
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 20edc99..80b11b8 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -224,6 +224,11 @@
pthread_cond_t cond;
struct stream_config in_config;
struct stream_config out_config;
+ struct audio_device *dev;
+ void *adsp_hdlr_stream_handle;
+ void *ip_hdlr_handle;
+ stream_callback_t client_callback;
+ void *client_cookie;
};
struct stream_out {
struct audio_stream_out stream;