hal: update adsp handler to handle multiple events

Update adsp handler logic to handle multiple events from ADSP

Change-Id: Icd2bf5ef7649e5781a8c3aae7aa0e3a42a43f11d
diff --git a/hal/audio_extn/adsp_hdlr.c b/hal/audio_extn/adsp_hdlr.c
index 08313a6..436da96 100644
--- a/hal/audio_extn/adsp_hdlr.c
+++ b/hal/audio_extn/adsp_hdlr.c
@@ -45,6 +45,8 @@
 #include <cutils/log.h>
 #include <cutils/sched_policy.h>
 #include <system/thread_defs.h>
+#include <sound/asound.h>
+#include <linux/msm_audio.h>
 
 #include "audio_hw.h"
 #include "audio_defs.h"
@@ -57,40 +59,29 @@
 
 #define MIXER_MAX_BYTE_LENGTH 512
 
-struct adsp_hdlr_inst {
-    bool binit;
-    struct mixer *mixer;
-};
-
-enum {
-    EVENT_CMD_EXIT,             /* event thread exit command loop*/
-    EVENT_CMD_WAIT,             /* event thread wait on mixer control */
-    EVENT_CMD_GET               /* event thread get param data from mixer */
-};
-
-struct event_cmd {
-    struct listnode list;
-    int opcode;
-};
-
-enum {
-    ADSP_HDLR_STREAM_STATE_OPENED = 0,
-    ADSP_HDLR_STREAM_STATE_EVENT_REGISTERED,
-    ADSP_HDLR_STREAM_STATE_EVENT_DEREGISTERED,
-    ADSP_HDLR_STREAM_STATE_CLOSED
-};
-
-static struct adsp_hdlr_inst *adsp_hdlr_inst = NULL;
-
-static void *event_wait_thread_loop(void *context);
-static void *event_callback_thread_loop(void *context);
-
 struct adsp_hdlr_stream_data {
     struct adsp_hdlr_stream_cfg config;
     stream_callback_t client_callback;
     void *client_cookie;
-    int state;
+};
 
+struct adsp_hdlr_event_info {
+    struct listnode list;
+    void *stream_handle;
+    char mixer_ctl_name[MIXER_PATH_MAX_LENGTH];
+    char cb_mixer_ctl_name[MIXER_PATH_MAX_LENGTH];
+    adsp_event_callback_t cb;
+    void *cookie;
+    int event_type;
+};
+
+struct adsp_hdlr_inst {
+    struct listnode event_list;
+    bool binit;
+    struct mixer *mixer;
+    pthread_mutex_t event_list_lock;
+
+    struct listnode list;
     pthread_cond_t event_wait_cond;
     pthread_t event_wait_thread;
     struct listnode event_wait_cmd_list;
@@ -104,7 +95,24 @@
     bool event_callback_thread_active;
 };
 
-static int send_cmd_event_wait_thread(struct adsp_hdlr_stream_data *stream_data, int opcode)
+enum {
+    EVENT_CMD_EXIT,             /* event thread exit command loop*/
+    EVENT_CMD_WAIT,             /* event thread wait on mixer control */
+    EVENT_CMD_GET               /* event thread get param data from mixer */
+};
+
+struct event_cmd {
+    struct listnode list;
+    int opcode;
+    char cb_mixer_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+};
+
+static struct adsp_hdlr_inst *adsp_hdlr_inst = NULL;
+
+static void *event_wait_thread_loop(void *context);
+static void *event_callback_thread_loop(void *context);
+
+static int send_cmd_event_wait_thread(struct adsp_hdlr_inst *adsp_hdlr_inst, int opcode)
 {
     struct event_cmd *cmd = calloc(1, sizeof(*cmd));
 
@@ -117,16 +125,16 @@
 
     cmd->opcode = opcode;
 
-    pthread_mutex_lock(&stream_data->event_wait_lock);
-    list_add_tail(&stream_data->event_wait_cmd_list, &cmd->list);
-    pthread_cond_signal(&stream_data->event_wait_cond);
-    pthread_mutex_unlock(&stream_data->event_wait_lock);
+    pthread_mutex_lock(&adsp_hdlr_inst->event_wait_lock);
+    list_add_tail(&adsp_hdlr_inst->event_wait_cmd_list, &cmd->list);
+    pthread_cond_signal(&adsp_hdlr_inst->event_wait_cond);
+    pthread_mutex_unlock(&adsp_hdlr_inst->event_wait_lock);
 
     return 0;
 }
 
-static int send_cmd_event_callback_thread(struct adsp_hdlr_stream_data *stream_data,
-                                          int opcode)
+static int send_cmd_event_callback_thread(struct adsp_hdlr_inst *adsp_hdlr_inst,
+                                          int opcode, char *mixer_ctl_name)
 {
     struct event_cmd *cmd = calloc(1, sizeof(*cmd));
 
@@ -135,66 +143,68 @@
         return -ENOMEM;
     }
 
-    ALOGVV("%s %d", __func__, opcode);
+    ALOGVV("%s opcode %d, name = %s", __func__, opcode, mixer_ctl_name);
 
     cmd->opcode = opcode;
+    if (mixer_ctl_name)
+        strlcpy(cmd->cb_mixer_ctl_name, mixer_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
 
-    pthread_mutex_lock(&stream_data->event_callback_lock);
-    list_add_tail(&stream_data->event_callback_cmd_list, &cmd->list);
-    pthread_cond_signal(&stream_data->event_callback_cond);
-    pthread_mutex_unlock(&stream_data->event_callback_lock);
+    pthread_mutex_lock(&adsp_hdlr_inst->event_callback_lock);
+    list_add_tail(&adsp_hdlr_inst->event_callback_cmd_list, &cmd->list);
+    pthread_cond_signal(&adsp_hdlr_inst->event_callback_cond);
+    pthread_mutex_unlock(&adsp_hdlr_inst->event_callback_lock);
 
     return 0;
 }
 
-static void create_event_wait_thread(struct adsp_hdlr_stream_data *stream_data)
+static void create_event_wait_thread(struct adsp_hdlr_inst *adsp_hdlr_inst)
 {
-    pthread_cond_init(&stream_data->event_wait_cond,
+    pthread_cond_init(&adsp_hdlr_inst->event_wait_cond,
                         (const pthread_condattr_t *) NULL);
-    list_init(&stream_data->event_wait_cmd_list);
-    pthread_create(&stream_data->event_wait_thread, (const pthread_attr_t *) NULL,
-                    event_wait_thread_loop, stream_data);
-    stream_data->event_wait_thread_active = true;
+    list_init(&adsp_hdlr_inst->event_wait_cmd_list);
+    pthread_create(&adsp_hdlr_inst->event_wait_thread, (const pthread_attr_t *) NULL,
+                    event_wait_thread_loop, adsp_hdlr_inst);
+    adsp_hdlr_inst->event_wait_thread_active = true;
 }
 
-static void create_event_callback_thread(struct adsp_hdlr_stream_data *stream_data)
+static void create_event_callback_thread(struct adsp_hdlr_inst *adsp_hdlr_inst)
 {
-    pthread_cond_init(&stream_data->event_callback_cond,
+    pthread_cond_init(&adsp_hdlr_inst->event_callback_cond,
                       (const pthread_condattr_t *) NULL);
-    list_init(&stream_data->event_callback_cmd_list);
-    pthread_create(&stream_data->event_callback_thread, (const pthread_attr_t *) NULL,
-                   event_callback_thread_loop, stream_data);
-    stream_data->event_callback_thread_active = true;
+    list_init(&adsp_hdlr_inst->event_callback_cmd_list);
+    pthread_create(&adsp_hdlr_inst->event_callback_thread, (const pthread_attr_t *) NULL,
+                   event_callback_thread_loop, adsp_hdlr_inst);
+    adsp_hdlr_inst->event_callback_thread_active = true;
 }
 
-static void destroy_event_wait_thread(struct adsp_hdlr_stream_data *stream_data)
+static void destroy_event_wait_thread(struct adsp_hdlr_inst *adsp_hdlr_inst)
 {
-    send_cmd_event_wait_thread(stream_data, EVENT_CMD_EXIT);
-    pthread_join(stream_data->event_wait_thread, (void **) NULL);
+    send_cmd_event_wait_thread(adsp_hdlr_inst, EVENT_CMD_EXIT);
+    pthread_join(adsp_hdlr_inst->event_wait_thread, (void **) NULL);
 
-    pthread_mutex_lock(&stream_data->event_wait_lock);
-    pthread_cond_destroy(&stream_data->event_wait_cond);
-    stream_data->event_wait_thread_active = false;
-    pthread_mutex_unlock(&stream_data->event_wait_lock);
+    pthread_mutex_lock(&adsp_hdlr_inst->event_wait_lock);
+    pthread_cond_destroy(&adsp_hdlr_inst->event_wait_cond);
+    adsp_hdlr_inst->event_wait_thread_active = false;
+    pthread_mutex_unlock(&adsp_hdlr_inst->event_wait_lock);
 }
 
-static void destroy_event_callback_thread(struct adsp_hdlr_stream_data *stream_data)
+static void destroy_event_callback_thread(struct adsp_hdlr_inst *adsp_hdlr_inst)
 {
-    send_cmd_event_callback_thread(stream_data, EVENT_CMD_EXIT);
-    pthread_join(stream_data->event_callback_thread, (void **) NULL);
+    send_cmd_event_callback_thread(adsp_hdlr_inst, EVENT_CMD_EXIT, NULL);
+    pthread_join(adsp_hdlr_inst->event_callback_thread, (void **) NULL);
 
-    pthread_mutex_lock(&stream_data->event_callback_lock);
-    pthread_cond_destroy(&stream_data->event_callback_cond);
-    stream_data->event_callback_thread_active = false;
-    pthread_mutex_unlock(&stream_data->event_callback_lock);
+    pthread_mutex_lock(&adsp_hdlr_inst->event_callback_lock);
+    pthread_cond_destroy(&adsp_hdlr_inst->event_callback_cond);
+    adsp_hdlr_inst->event_callback_thread_active = false;
+    pthread_mutex_unlock(&adsp_hdlr_inst->event_callback_lock);
 }
 
-static void destroy_event_threads(struct adsp_hdlr_stream_data *stream_data)
+static void destroy_event_threads(struct adsp_hdlr_inst *adsp_hdlr_inst)
 {
-    if (stream_data->event_wait_thread_active)
-        destroy_event_wait_thread(stream_data);
-    if (stream_data->event_callback_thread_active)
-        destroy_event_callback_thread(stream_data);
+    if (adsp_hdlr_inst->event_wait_thread_active)
+        destroy_event_wait_thread(adsp_hdlr_inst);
+    if (adsp_hdlr_inst->event_callback_thread_active)
+        destroy_event_callback_thread(adsp_hdlr_inst);
 }
 
 static void *event_wait_thread_loop(void *context)
@@ -202,53 +212,35 @@
     int ret = 0;
     int opcode = 0;
     bool wait = false;
-    struct adsp_hdlr_stream_data *stream_data =
-                        (struct adsp_hdlr_stream_data *) context;
-    struct adsp_hdlr_stream_cfg *config = &stream_data->config;
-    char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
-    struct mixer_ctl *ctl = NULL;
+    struct adsp_hdlr_inst *adsp_hdlr_inst =
+                        (struct adsp_hdlr_inst *) context;
     struct event_cmd *cmd;
-    struct listnode *node;
+    struct listnode *node, *tempnode;
+    struct snd_ctl_event mixer_event = {0};
 
     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
     set_sched_policy(0, SP_BACKGROUND);
     prctl(PR_SET_NAME, (unsigned long)"Event Wait", 0, 0, 0);
 
-    ret = snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
-            "ADSP Stream Callback Event %d", config->pcm_device_id);
-    if (ret < 0) {
-        ALOGE("%s: snprintf failed",__func__);
-        ret = -EINVAL;
-        goto done;
-    }
-
-    ctl = mixer_get_ctl_by_name(adsp_hdlr_inst->mixer, mixer_ctl_name);
-    if (!ctl) {
-        ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
-              mixer_ctl_name);
-        ret = -EINVAL;
-        goto done;
-    }
-
     ret = mixer_subscribe_events(adsp_hdlr_inst->mixer, 1);
     if (ret < 0) {
-        ALOGE("%s: Could not subscribe for mixer cmd - %s, ret %d",
-              __func__, mixer_ctl_name, ret);
+        ALOGE("%s: Could not subscribe for mixer events, ret %d",
+              __func__, ret);
         goto done;
     }
 
-    pthread_mutex_lock(&stream_data->event_wait_lock);
+    pthread_mutex_lock(&adsp_hdlr_inst->event_wait_lock);
     while (1) {
-        if (list_empty(&stream_data->event_wait_cmd_list) && !wait) {
+        if (list_empty(&adsp_hdlr_inst->event_wait_cmd_list) && !wait) {
             ALOGVV("%s SLEEPING", __func__);
-            pthread_cond_wait(&stream_data->event_wait_cond, &stream_data->event_wait_lock);
+            pthread_cond_wait(&adsp_hdlr_inst->event_wait_cond, &adsp_hdlr_inst->event_wait_lock);
             ALOGVV("%s RUNNING", __func__);
         }
         /* execute command if available */
-        if (!list_empty(&stream_data->event_wait_cmd_list)) {
-            node = list_head(&stream_data->event_wait_cmd_list);
+        if (!list_empty(&adsp_hdlr_inst->event_wait_cmd_list)) {
+            node = list_head(&adsp_hdlr_inst->event_wait_cmd_list);
             list_remove(node);
-            pthread_mutex_unlock(&stream_data->event_wait_lock);
+            pthread_mutex_unlock(&adsp_hdlr_inst->event_wait_lock);
             cmd = node_to_item(node, struct event_cmd, list);
             opcode = cmd->opcode;
        /* wait if no command avialable */
@@ -265,30 +257,20 @@
             goto thread_exit;
         case EVENT_CMD_WAIT:
             ret = mixer_wait_event(adsp_hdlr_inst->mixer, WAIT_EVENT_POLL_TIMEOUT);
-            if (ret < 0)
-                ALOGE("%s: mixer_wait_event err! mixer %s, ret = %d",
-                      __func__, mixer_ctl_name, ret);
-            else if (ret > 0) {
-                send_cmd_event_callback_thread(stream_data, EVENT_CMD_GET);
-
-                /* Resubscribe to clear flag checked by mixer_wait_event */
-                ret = mixer_subscribe_events(adsp_hdlr_inst->mixer, 0);
-                if (ret < 0) {
-                    ALOGE("%s: Could not unsubscribe for mixer cmd - %s, ret %d",
-                          __func__, mixer_ctl_name, ret);
-                    goto done;
-                }
-                ret = mixer_subscribe_events(adsp_hdlr_inst->mixer, 1);
-                if (ret < 0) {
-                     ALOGE("%s: Could not unsubscribe for mixer cmd - %s, ret %d",
-                          __func__, mixer_ctl_name, ret);
-                    goto done;
-                }
+            ALOGVV("%s: mixer_wait_event unblocked!, ret = %d", __func__, ret);
+            if (ret < 0) {
+                ALOGE("%s: mixer_wait_event err!, ret = %d", __func__, ret);
+            } else if (ret > 0) {
+                ret = mixer_read(adsp_hdlr_inst->mixer, &mixer_event);
+                if (ret >= 0)
+                    send_cmd_event_callback_thread(adsp_hdlr_inst, EVENT_CMD_GET, mixer_event.data.elem.id.name);
+                else
+                    ALOGE("%s: mixer_read failed, ret = %d", __func__, ret);
             }
             /* Once wait command has been sent continue to wait for
                events unless something else is in the command que */
             wait = true;
-        break;
+            break;
         default:
             ALOGE("%s unknown command received: %d", __func__, opcode);
             break;
@@ -300,12 +282,18 @@
         }
     }
 thread_exit:
-    pthread_mutex_lock(&stream_data->event_wait_lock);
-    list_for_each(node, &stream_data->event_wait_cmd_list) {
+    ret = mixer_subscribe_events(adsp_hdlr_inst->mixer, 0);
+    if (ret < 0) {
+        ALOGE("%s: Could not un-subscribe for mixer events, ret %d",
+              __func__, ret);
+        goto done;
+    }
+    pthread_mutex_lock(&adsp_hdlr_inst->event_wait_lock);
+    list_for_each_safe(node, tempnode, &adsp_hdlr_inst->event_wait_cmd_list) {
         list_remove(node);
         free(node);
     }
-    pthread_mutex_unlock(&stream_data->event_wait_lock);
+    pthread_mutex_unlock(&adsp_hdlr_inst->event_wait_lock);
 done:
     return NULL;
 }
@@ -314,47 +302,32 @@
 {
     int ret = 0;
     size_t count = 0;
-    struct adsp_hdlr_stream_data *stream_data =
-                            (struct adsp_hdlr_stream_data *)context;
-    struct adsp_hdlr_stream_cfg *config = &stream_data->config;
-    char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+    struct adsp_hdlr_inst *adsp_hdlr_inst =
+                            (struct adsp_hdlr_inst *)context;
     struct mixer_ctl *ctl = NULL;
     uint8_t param[MAX_EVENT_PAYLOAD] = {0};
     struct event_cmd *cmd;
-    struct listnode *node;
+    struct listnode *node, *tempnode;
+    struct adsp_hdlr_event_info *event_info;
+    bool param_avail = false;
+    struct msm_adsp_event_data *received_evt;
 
     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
     set_sched_policy(0, SP_BACKGROUND);
     prctl(PR_SET_NAME, (unsigned long)"Event Callback", 0, 0, 0);
 
-    ret = snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
-            "ADSP Stream Callback Event %d", config->pcm_device_id);
-    if (ret < 0) {
-        ALOGE("%s: snprintf failed",__func__);
-        ret = -EINVAL;
-        goto done;
-    }
-
-    ctl = mixer_get_ctl_by_name(adsp_hdlr_inst->mixer, mixer_ctl_name);
-    if (!ctl) {
-        ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
-              mixer_ctl_name);
-        ret = -EINVAL;
-        goto done;
-    }
-
-    pthread_mutex_lock(&stream_data->event_callback_lock);
+    pthread_mutex_lock(&adsp_hdlr_inst->event_callback_lock);
     while (1) {
-        if (list_empty(&stream_data->event_callback_cmd_list)) {
+        if (list_empty(&adsp_hdlr_inst->event_callback_cmd_list)) {
             ALOGVV("%s SLEEPING", __func__);
-            pthread_cond_wait(&stream_data->event_callback_cond,
-                              &stream_data->event_callback_lock);
+            pthread_cond_wait(&adsp_hdlr_inst->event_callback_cond,
+                              &adsp_hdlr_inst->event_callback_lock);
             ALOGVV("%s RUNNING", __func__);
             continue;
         }
-        node = list_head(&stream_data->event_callback_cmd_list);
+        node = list_head(&adsp_hdlr_inst->event_callback_cmd_list);
         list_remove(node);
-        pthread_mutex_unlock(&stream_data->event_callback_lock);
+        pthread_mutex_unlock(&adsp_hdlr_inst->event_callback_lock);
         cmd = node_to_item(node, struct event_cmd, list);
 
         ALOGVV("%s command received: %d", __func__, cmd->opcode);
@@ -363,30 +336,60 @@
             free(cmd);
             goto thread_exit;
         case EVENT_CMD_GET:
-            mixer_ctl_update(ctl);
-
-            count = mixer_ctl_get_num_values(ctl);
-            if ((count > MAX_EVENT_PAYLOAD) || (count <= 0)) {
-                ALOGE("%s mixer - %s, count is %d",
-                      __func__, mixer_ctl_name, count);
-                break;
+            param_avail = false;
+            pthread_mutex_lock(&adsp_hdlr_inst->event_list_lock);
+            /* Find the mixer control for which event is triggered */
+            list_for_each(node, &adsp_hdlr_inst->event_list) {
+                event_info = node_to_item(node, struct adsp_hdlr_event_info, list);
+                ALOGVV("%s: cmd mixer name: %s, event list mixer name: %s", __func__,
+                       cmd->cb_mixer_ctl_name, event_info->cb_mixer_ctl_name);
+                if (!strcmp(cmd->cb_mixer_ctl_name, event_info->cb_mixer_ctl_name)) {
+                    if (!param_avail) {
+                        ctl = mixer_get_ctl_by_name(adsp_hdlr_inst->mixer, cmd->cb_mixer_ctl_name);
+                        if (!ctl) {
+                            ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
+                                  cmd->cb_mixer_ctl_name);
+                            break;
+                        }
+                        mixer_ctl_update(ctl);
+                        count = mixer_ctl_get_num_values(ctl);
+                        if ((count > MAX_EVENT_PAYLOAD) || (count <= 0)) {
+                            ALOGE("%s: count is %d greater than allowed for %s mixer cmd",
+                                  __func__, count, cmd->cb_mixer_ctl_name);
+                            break;
+                        }
+                        ret = mixer_ctl_get_array(ctl, param, count);
+                        if (ret < 0) {
+                            ALOGE("%s: mixer_ctl_get_array failed! mixer - %s, ret = %d",
+                                  __func__, cmd->cb_mixer_ctl_name, ret);
+                            break;
+                        }
+                        param_avail = true;
+                        received_evt = (struct msm_adsp_event_data *)param;
+                        ALOGD("%s: event type = %d", __func__, received_evt->event_type);
+                    }
+                    /* Call appropriate event type client callback */
+                    if (param_avail && event_info->event_type == received_evt->event_type) {
+                        struct adsp_hdlr_stream_data *stream_data = event_info->stream_handle;
+                        if (event_info->cb != NULL) {
+                            ALOGVV("%s: calling event callback function", __func__);
+                            event_info->cb(event_info->stream_handle,
+                                           received_evt->payload,
+                                           event_info->cookie);
+                        } else if (stream_data->client_callback != NULL) {
+                            ALOGVV("%s: sending client callback event %d", __func__,
+                                   AUDIO_EXTN_STREAM_CBK_EVENT_ADSP);
+                            stream_data->client_callback((stream_callback_event_t)
+                                                         AUDIO_EXTN_STREAM_CBK_EVENT_ADSP,
+                                                         received_evt,
+                                                         stream_data->client_cookie);
+                        }
+                        break;
+                    }
+                }
             }
+            pthread_mutex_unlock(&adsp_hdlr_inst->event_list_lock);
 
-            ret = mixer_ctl_get_array(ctl, param, count);
-            if (ret < 0) {
-                ALOGE("%s: mixer_ctl_get_array failed! mixer - %s, ret = %d",
-                      __func__, mixer_ctl_name, ret);
-                break;
-            }
-
-            if (stream_data->client_callback != NULL) {
-                ALOGVV("%s: sending client callback event %d", __func__,
-                       AUDIO_EXTN_STREAM_CBK_EVENT_ADSP);
-                stream_data->client_callback((stream_callback_event_t)
-                                             AUDIO_EXTN_STREAM_CBK_EVENT_ADSP,
-                                             param,
-                                             stream_data->client_cookie);
-            }
         break;
         default:
             ALOGE("%s unknown command received: %d", __func__, cmd->opcode);
@@ -395,39 +398,101 @@
         free(cmd);
     }
 thread_exit:
-    pthread_mutex_lock(&stream_data->event_callback_lock);
-    list_for_each(node, &stream_data->event_callback_cmd_list) {
+    pthread_mutex_lock(&adsp_hdlr_inst->event_callback_lock);
+    list_for_each_safe(node, tempnode, &adsp_hdlr_inst->event_callback_cmd_list) {
         list_remove(node);
         free(node);
     }
-    pthread_mutex_unlock(&stream_data->event_callback_lock);
+    pthread_mutex_unlock(&adsp_hdlr_inst->event_callback_lock);
 done:
     return NULL;
 }
 
-static int adsp_hdlr_stream_deregister_event(
-                struct adsp_hdlr_stream_data *stream_data)
+int audio_extn_adsp_hdlr_stream_deregister_event(void *handle, void *data)
 {
-    destroy_event_threads((struct adsp_hdlr_stream_data *)stream_data);
-    stream_data->state = ADSP_HDLR_STREAM_STATE_EVENT_DEREGISTERED;
+    struct listnode *node, *tempnode;
+    struct adsp_hdlr_stream_data *stream_data = (struct adsp_hdlr_stream_data *)handle;
+    struct adsp_hdlr_event_info *event_info;
+    struct audio_adsp_event *param = (struct audio_adsp_event *)data;
+
+    if (!handle) {
+        ALOGE("%s: Invalid handle", __func__);
+        return -EINVAL;
+    }
+
+    pthread_mutex_lock(&adsp_hdlr_inst->event_list_lock);
+    if (list_empty(&adsp_hdlr_inst->event_list)) {
+        ALOGD("%s: event list is empty", __func__);
+        return 0;
+    }
+    list_for_each_safe(node, tempnode, &adsp_hdlr_inst->event_list) {
+        event_info = node_to_item(node, struct adsp_hdlr_event_info, list);
+        if (param && event_info->stream_handle == stream_data) {
+            /* if the type of event is avaliable to dereg then dereg only that event */
+            if (event_info->event_type == param->event_type) {
+                ALOGD("%s: Deregister event type = %d", __func__, event_info->event_type);
+                list_remove(node);
+                free(event_info);
+            }
+        } else if (event_info->stream_handle == stream_data) {
+            /* Dereg all the events related to that stream */
+            ALOGD("%s: Deregister all stream events", __func__);
+            list_remove(node);
+            free(event_info);
+        }
+    }
+    pthread_mutex_unlock(&adsp_hdlr_inst->event_list_lock);
+
+    if (list_empty(&adsp_hdlr_inst->event_list)) {
+        ALOGD("%s: Closing event threads", __func__);
+        destroy_event_threads(adsp_hdlr_inst);
+        pthread_mutex_destroy(&adsp_hdlr_inst->event_wait_lock);
+        pthread_mutex_destroy(&adsp_hdlr_inst->event_callback_lock);
+        pthread_mutex_destroy(&adsp_hdlr_inst->event_list_lock);
+    }
+
     return 0;
 }
 
-static int adsp_hdlr_stream_register_event(
-                struct adsp_hdlr_stream_data *stream_data,
-                struct audio_adsp_event *param)
+int audio_extn_adsp_hdlr_stream_register_event(void *handle, void *data,
+                                               adsp_event_callback_t cb,
+                                               void *cookie)
 {
     int ret = 0;
     char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+    char cb_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
     struct mixer_ctl *ctl = NULL;
     uint8_t payload[AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN] = {0};
+    struct adsp_hdlr_stream_data *stream_data = (struct adsp_hdlr_stream_data *)handle;
     struct adsp_hdlr_stream_cfg *config = &stream_data->config;
+    struct adsp_hdlr_event_info *event_info;
+    struct audio_adsp_event *param = (struct audio_adsp_event *)data;
+
+    if (!param || !handle) {
+        ret = -EINVAL;
+        ALOGE("%s: Invalid input arguments", __func__);
+        goto done;
+    }
 
     /* check if param size exceeds max size supported by mixer */
     if (param->payload_length > AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN) {
         ALOGE("%s: Invalid payload_length %d",__func__, param->payload_length);
         return -EINVAL;
     }
+    ret = snprintf(cb_mixer_ctl_name, sizeof(cb_mixer_ctl_name),
+            "ADSP Stream Callback Event %d", config->pcm_device_id);
+    if (ret < 0) {
+        ALOGE("%s: snprintf failed",__func__);
+        ret = -EINVAL;
+        goto done;
+    }
+    ctl = mixer_get_ctl_by_name(adsp_hdlr_inst->mixer, cb_mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
+              cb_mixer_ctl_name);
+        ret = -EINVAL;
+        goto done;
+    }
 
     ret = snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
             "ADSP Stream Cmd %d", config->pcm_device_id);
@@ -444,36 +509,63 @@
         ret = -EINVAL;
         goto done;
     }
+    ALOGD("%s: event = %d, payload_length %d", __func__, param->event_type, param->payload_length);
 
-    ALOGD("%s: payload_length %d",__func__, param->payload_length);
-
-    /*copy payload size and param */
-    memcpy(payload, &param->payload_length,
+    /* copy event_type, payload size and payload */
+    memcpy(payload, &param->event_type,
+                    sizeof(param->event_type));
+    memcpy(payload + sizeof(param->event_type), &param->payload_length,
                     sizeof(param->payload_length));
-    memcpy(payload + sizeof(param->payload_length),
+    memcpy(payload + sizeof(param->event_type) + sizeof(param->payload_length),
            param->payload, param->payload_length);
-    ret = mixer_ctl_set_array(ctl, payload,
-                 sizeof(param->payload_length) + param->payload_length);
+    ret = mixer_ctl_set_array(ctl, payload, (sizeof(param->event_type) +
+                               sizeof(param->payload_length) + param->payload_length));
     if (ret < 0) {
         ALOGE("%s: Could not set ctl for mixer cmd - %s, ret %d", __func__,
               mixer_ctl_name, ret);
         goto done;
     }
 
-    pthread_mutex_lock(&stream_data->event_wait_lock);
-    if (!stream_data->event_wait_thread_active)
-        create_event_wait_thread(stream_data);
-    pthread_mutex_unlock(&stream_data->event_wait_lock);
+    if (list_empty(&adsp_hdlr_inst->event_list)) {
+        pthread_mutex_init(&adsp_hdlr_inst->event_wait_lock,
+                           (const pthread_mutexattr_t *) NULL);
+        pthread_mutex_init(&adsp_hdlr_inst->event_callback_lock,
+                           (const pthread_mutexattr_t *) NULL);
+        pthread_mutex_init(&adsp_hdlr_inst->event_list_lock,
+                           (const pthread_mutexattr_t *) NULL);
 
-    pthread_mutex_lock(&stream_data->event_callback_lock);
-    if (!stream_data->event_callback_thread_active)
-        create_event_callback_thread(stream_data);
-    pthread_mutex_unlock(&stream_data->event_callback_lock);
+        /* create event threads during first event registration */
+        pthread_mutex_lock(&adsp_hdlr_inst->event_wait_lock);
+        if (!adsp_hdlr_inst->event_wait_thread_active)
+            create_event_wait_thread(adsp_hdlr_inst);
+        pthread_mutex_unlock(&adsp_hdlr_inst->event_wait_lock);
 
-    send_cmd_event_wait_thread(stream_data, EVENT_CMD_WAIT);
-    stream_data->state = ADSP_HDLR_STREAM_STATE_EVENT_REGISTERED;
+        pthread_mutex_lock(&adsp_hdlr_inst->event_callback_lock);
+        if (!adsp_hdlr_inst->event_callback_thread_active)
+            create_event_callback_thread(adsp_hdlr_inst);
+        pthread_mutex_unlock(&adsp_hdlr_inst->event_callback_lock);
+
+        send_cmd_event_wait_thread(adsp_hdlr_inst, EVENT_CMD_WAIT);
+    }
+    event_info = (struct adsp_hdlr_event_info *) calloc(1,
+                                   sizeof(struct adsp_hdlr_event_info));
+    if (event_info == NULL) {
+        ret = -ENOMEM;
+        goto done;
+    }
+    event_info->event_type = param->event_type;
+    event_info->cb = cb;
+    event_info->cookie = cookie;
+    event_info->stream_handle = stream_data;
+    strlcpy(event_info->mixer_ctl_name, mixer_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+    strlcpy(event_info->cb_mixer_ctl_name, cb_mixer_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+    pthread_mutex_lock(&adsp_hdlr_inst->event_list_lock);
+    list_add_tail(&adsp_hdlr_inst->event_list, &event_info->list);
+    ALOGD("%s: event_info type %d added from the list", __func__, event_info->event_type);
+    pthread_mutex_unlock(&adsp_hdlr_inst->event_list_lock);
+
 done:
-        return ret;
+    return ret;
 }
 
 int audio_extn_adsp_hdlr_stream_set_param(void *handle,
@@ -481,28 +573,21 @@
                     void *param)
 {
     int ret = 0;
-    struct adsp_hdlr_stream_data *stream_data;
 
     if (handle == NULL) {
         ALOGE("%s: Invalid handle",__func__);
         return -EINVAL;
     }
 
-    stream_data = (struct adsp_hdlr_stream_data *)handle;
     switch (cmd) {
         case ADSP_HDLR_STREAM_CMD_REGISTER_EVENT :
-            if (!param) {
-                ret = -EINVAL;
-                ALOGE("%s: Invalid handle",__func__);
-                break;
-            }
-            ret = adsp_hdlr_stream_register_event(stream_data, param);
+            ret = audio_extn_adsp_hdlr_stream_register_event(handle, param, NULL, NULL);
             if (ret)
                 ALOGE("%s:adsp_hdlr_stream_register_event failed error %d",
                        __func__, ret);
             break;
         case ADSP_HDLR_STREAM_CMD_DEREGISTER_EVENT:
-            ret = adsp_hdlr_stream_deregister_event(stream_data);
+            ret = audio_extn_adsp_hdlr_stream_deregister_event(handle, param);
             if (ret)
                 ALOGE("%s:adsp_hdlr_stream_deregister_event failed error %d",
                        __func__, ret);
@@ -546,15 +631,10 @@
         ret = -EINVAL;
     } else {
         stream_data = (struct adsp_hdlr_stream_data *)handle;
-        if (stream_data->state == ADSP_HDLR_STREAM_STATE_EVENT_REGISTERED) {
-            ret = adsp_hdlr_stream_deregister_event(stream_data);
-            if (ret)
-                ALOGE("%s:adsp_hdlr_stream_deregister_event failed error %d",
-                        __func__, ret);
-        }
-        stream_data->state = ADSP_HDLR_STREAM_STATE_CLOSED;
-        pthread_mutex_destroy(&stream_data->event_wait_lock);
-        pthread_mutex_destroy(&stream_data->event_wait_lock);
+        ret = audio_extn_adsp_hdlr_stream_deregister_event(stream_data, NULL);
+        if (ret)
+            ALOGE("%s:adsp_hdlr_stream_deregister_event failed error %d",
+                  __func__, ret);
         free(stream_data);
         stream_data = NULL;
     }
@@ -588,15 +668,9 @@
     if (stream_data == NULL) {
         ret = -ENOMEM;
     }
-
     stream_data->config = *config;
-    pthread_mutex_init(&stream_data->event_wait_lock,
-                       (const pthread_mutexattr_t *) NULL);
-    pthread_mutex_init(&stream_data->event_callback_lock,
-                       (const pthread_mutexattr_t *) NULL);
-    stream_data->state = ADSP_HDLR_STREAM_STATE_OPENED;
-
     *handle = (void **)stream_data;
+
     return ret;
 }
 
@@ -614,14 +688,15 @@
         return 0;
     }
     adsp_hdlr_inst = (struct adsp_hdlr_inst *)calloc(1,
-                                  sizeof(struct adsp_hdlr_inst *));
+                                  sizeof(struct adsp_hdlr_inst));
     if (!adsp_hdlr_inst) {
         ALOGE("%s: calloc failed for adsp_hdlr_inst", __func__);
         return -EINVAL;
     }
     adsp_hdlr_inst->mixer = mixer;
+    list_init(&adsp_hdlr_inst->event_list);
 
-   return 0;
+    return 0;
 }
 
 int audio_extn_adsp_hdlr_deinit(void)
diff --git a/hal/audio_extn/adsp_hdlr.h b/hal/audio_extn/adsp_hdlr.h
index 7499917..b265e42 100644
--- a/hal/audio_extn/adsp_hdlr.h
+++ b/hal/audio_extn/adsp_hdlr.h
@@ -42,6 +42,9 @@
 };
 
 #ifdef AUDIO_EXTN_ADSP_HDLR_ENABLED
+
+typedef int (*adsp_event_callback_t)(void *handle, void *payload, void *cookie);
+
 int audio_extn_adsp_hdlr_init(struct mixer *mixer);
 int audio_extn_adsp_hdlr_deinit(void);
 int audio_extn_adsp_hdlr_stream_open(void **handle,
@@ -53,6 +56,9 @@
 int audio_extn_adsp_hdlr_stream_set_param(void *handle,
                     adsp_hdlr_cmd_t cmd,
                     void *param);
+int audio_extn_adsp_hdlr_stream_register_event(void *handle,
+                void *param, adsp_event_callback_t cb, void *cookie);
+int audio_extn_adsp_hdlr_stream_deregister_event(void *handle, void *param);
 #else
 #define audio_extn_adsp_hdlr_init(mixer)                                     (0)
 #define audio_extn_adsp_hdlr_deinit()                                        (0)
@@ -60,6 +66,8 @@
 #define audio_extn_adsp_hdlr_stream_close(handle)                            (0)
 #define audio_extn_adsp_hdlr_stream_set_callback(handle, callback, cookie)   (0)
 #define audio_extn_adsp_hdlr_stream_set_param(handle, cmd, param)            (0)
+#define audio_extn_adsp_hdlr_stream_register_event(stream_data, param, cb)   (0)
+#define audio_extn_adsp_hdlr_stream_deregister_event(handle, param)          (0)
 #endif
 
 #endif
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index ea84b75..c3201b4 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -199,12 +199,18 @@
                                                  */
 } audio_extn_callback_id;
 
-#define AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN 508
+#define AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN 504
+
+typedef enum {
+    AUDIO_STREAM_PP_EVENT = 0,
+    AUDIO_STREAM_ENCDEC_EVENT = 1,
+} audio_event_id;
 
 /* payload format for HAL parameter
  * AUDIO_EXTN_PARAM_ADSP_STREAM_CMD
  */
 struct audio_adsp_event {
+ audio_event_id event_type;                  /* type of the event */
  uint32_t payload_length;                    /* length in bytes of the payload */
  void    *payload;                           /* the actual payload */
 };
diff --git a/qahw_api/inc/qahw_defs.h b/qahw_api/inc/qahw_defs.h
index 3900676..8438d6e 100644
--- a/qahw_api/inc/qahw_defs.h
+++ b/qahw_api/inc/qahw_defs.h
@@ -293,10 +293,16 @@
 
 #define QAHW_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN 512
 
+typedef enum {
+    QAHW_STREAM_PP_EVENT = 0,
+    QAHW_STREAM_ENCDEC_EVENT = 1,
+} qahw_event_id;
+
 /* payload format for HAL parameter
  * QAHW_PARAM_ADSP_STREAM_CMD
  */
 struct qahw_adsp_event {
+    qahw_event_id event_type;      /* type of the event */
     uint32_t payload_length;       /* length in bytes of the payload */
     void *payload;                 /* the actual payload */
 };
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index 96f0c5f..2c7864a 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -422,8 +422,9 @@
     case QAHW_STREAM_CBK_EVENT_ADSP:
         fprintf(log_file, "stream %d: received event - QAHW_STREAM_CBK_EVENT_ADSP\n", params->stream_index);
         if (payload != NULL) {
-            fprintf(log_file, "param_length %d\n", payload[0]);
-            for (i=1; i* sizeof(uint32_t) <= payload[0]; i++)
+            fprintf(log_file, "event_type %d\n", payload[0]);
+            fprintf(log_file, "param_length %d\n", payload[1]);
+            for (i=2; i* sizeof(uint32_t) <= payload[1]; i++)
                 fprintf(log_file, "param[%d] = 0x%x\n", i, payload[i]);
         }
         break;
@@ -1239,6 +1240,7 @@
     event_payload.module_id = 0x10940;
     event_payload.config_mask = 1;
 
+    payload.adsp_event_params.event_type = QAHW_STREAM_PP_EVENT;
     payload.adsp_event_params.payload_length = sizeof(event_payload);
     payload.adsp_event_params.payload = &event_payload;