hal: Add support to close streams on power policy callback

* Close existing streams during power policy disable callback

* Stop new streams from starting if current policy is in disabled state

Signed-off-by: Shubhasini Sugumaran <quic_c_shubsu@quicinc.com>
Change-Id: I4960e336f03086d1322708e155a4a4f02098b3fb
diff --git a/hal/audio_extn/PowerPolicyClient.cpp b/hal/audio_extn/PowerPolicyClient.cpp
index e3a9e22..62dcf39 100644
--- a/hal/audio_extn/PowerPolicyClient.cpp
+++ b/hal/audio_extn/PowerPolicyClient.cpp
@@ -51,7 +51,11 @@
 
 }  // namespace
 
-PowerPolicyClient::PowerPolicyClient() {
+PowerPolicyClient::PowerPolicyClient(power_policy_init_config_t init_config) {
+
+    fp_in_set_power_policy = init_config.fp_in_set_power_policy;
+    fp_out_set_power_policy = init_config.fp_out_set_power_policy;
+
     plugin_handle = dlopen(LIB_AUDIO_HAL_PLUGIN, RTLD_NOW);
     if (plugin_handle == NULL) {
         LOG(ERROR) << "Failed to open plugin library";
@@ -89,12 +93,16 @@
     if (hasComponent(powerPolicy.enabledComponents, kAudioComponent)) {
         LOG(ERROR) << "Power policy: Audio component is enabled";
         disable = 0;
+
+        fp_out_set_power_policy(!disable);
         if (hal_plugin_send_msg != NULL)
             hal_plugin_send_msg(AUDIO_HAL_PLUGIN_MSG_SILENT_MODE,
                                 &disable, sizeof(disable));
     } else if (hasComponent(powerPolicy.disabledComponents, kAudioComponent)) {
         LOG(ERROR) << "Power policy: Audio component is disabled";
         disable = 1;
+
+        fp_out_set_power_policy(!disable);
         if (hal_plugin_send_msg != NULL)
             hal_plugin_send_msg(AUDIO_HAL_PLUGIN_MSG_SILENT_MODE,
                                 &disable, sizeof(disable));
@@ -103,11 +111,15 @@
     if (hasComponent(powerPolicy.enabledComponents, kMicComponent)) {
         LOG(ERROR) << "Power policy: Microphone component is enabled";
         disable = 0;
+
+        fp_in_set_power_policy(!disable);
         if (hal_plugin_send_msg != NULL)
             hal_plugin_send_msg(AUDIO_HAL_PLUGIN_MSG_MIC_STATE,
                                 &disable, sizeof(disable));
     } else if (hasComponent(powerPolicy.disabledComponents, kMicComponent)) {
         disable = 1;
+
+        fp_in_set_power_policy(!disable);
         if (hal_plugin_send_msg != NULL)
             hal_plugin_send_msg(AUDIO_HAL_PLUGIN_MSG_MIC_STATE,
                                 &disable, sizeof(disable));
diff --git a/hal/audio_extn/PowerPolicyClient.h b/hal/audio_extn/PowerPolicyClient.h
index da0b434..c5308e3 100644
--- a/hal/audio_extn/PowerPolicyClient.h
+++ b/hal/audio_extn/PowerPolicyClient.h
@@ -32,11 +32,19 @@
 #include "audio_hal_plugin.h"
 
 typedef int32_t (*hal_plugin_send_msg_t) (audio_hal_plugin_msg_type_t, void*, uint32_t);
+typedef void (*fp_in_set_power_policy_t) (uint8_t);
+typedef void (*fp_out_set_power_policy_t) (uint8_t);
+
+typedef struct power_policy_init_config {
+    fp_in_set_power_policy_t                      fp_in_set_power_policy;
+    fp_out_set_power_policy_t                     fp_out_set_power_policy;
+} power_policy_init_config_t;
+
 
 class PowerPolicyClient
     : public ::android::frameworks::automotive::powerpolicy::PowerPolicyClientBase {
   public:
-    explicit PowerPolicyClient();
+    explicit PowerPolicyClient(power_policy_init_config init_config);
     ~PowerPolicyClient();
 
     void onInitFailed();
@@ -48,6 +56,8 @@
   private:
         void* plugin_handle;
         hal_plugin_send_msg_t hal_plugin_send_msg;
+        fp_out_set_power_policy_t fp_out_set_power_policy;
+        fp_in_set_power_policy_t fp_in_set_power_policy;
 };
 
 #endif  // QTI_AUDIO_POWERPOLICYCLIENT_H_
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
old mode 100755
new mode 100644
index 2848649..b094cbd
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -6526,10 +6526,13 @@
         goto exit;
     }
     ALOGD("%s: Launching Power Policy Client", __func__);
-    launch_power_policy();
+    power_policy_init_config_t init_config;
+    init_config.fp_in_set_power_policy = in_set_power_policy;
+    init_config.fp_out_set_power_policy = out_set_power_policy;
+    launch_power_policy(init_config);
 
 exit:
-    pthread_exit(NULL);
+    return NULL;
 }
 
 static int power_policy_feature_init(bool is_feature_enabled)
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
old mode 100755
new mode 100644
index 4344bad..f2038d8
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -1428,6 +1428,17 @@
 } synth_init_config_t;
 // END: SYNTH_HAL FEATURE ==================================================
 
+// START: POWER_POLICY FEATURE ==================================================
+
+typedef void (*fp_in_set_power_policy_t) (uint8_t);
+typedef void (*fp_out_set_power_policy_t) (uint8_t);
+
+typedef struct power_policy_init_config {
+    fp_in_set_power_policy_t                      fp_in_set_power_policy;
+    fp_out_set_power_policy_t                     fp_out_set_power_policy;
+} power_policy_init_config_t;
+// END: POWER_POLICY FEATURE ==================================================
+
 bool audio_extn_edid_is_supported_sr(edid_audio_info* info, int sr);
 bool audio_extn_edid_is_supported_bps(edid_audio_info* info, int bps);
 int audio_extn_edid_get_highest_supported_sr(edid_audio_info* info);
diff --git a/hal/audio_extn/power_policy_launcher.cpp b/hal/audio_extn/power_policy_launcher.cpp
index a85f30c..ac846cd 100644
--- a/hal/audio_extn/power_policy_launcher.cpp
+++ b/hal/audio_extn/power_policy_launcher.cpp
@@ -34,11 +34,11 @@
 
 extern "C" {
 
-    int launchPowerPolicyClient() {
+    int launchPowerPolicyClient(power_policy_init_config_t init_config) {
         ALOGD("%s: power policy launcher called", __func__);
         ABinderProcess_setThreadPoolMaxThreadCount(0);
         std::shared_ptr<PowerPolicyClient> powerPolicyClient =
-                ::ndk::SharedRefBase::make<PowerPolicyClient>();
+                ::ndk::SharedRefBase::make<PowerPolicyClient>(init_config);
         ALOGD("%s:Instantiating power policy client from launcher", __func__);
         powerPolicyClient->init();
         ALOGD("%s: Power Policy class inited, joining threadpool", __func__);
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 8546c97..1798d27 100755
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -3445,8 +3445,9 @@
           __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
 
     if (CARD_STATUS_OFFLINE == in->card_status||
-        CARD_STATUS_OFFLINE == adev->card_status) {
-        ALOGW("in->card_status or adev->card_status offline, try again");
+        CARD_STATUS_OFFLINE == adev->card_status ||
+        POWER_POLICY_STATUS_OFFLINE == adev->in_power_policy) {
+        ALOGW("in->card_status or adev->card_status or adev->input_power offline, try again");
         ret = -EIO;
         goto error_config;
     }
@@ -3865,7 +3866,8 @@
             else
                 ALOGE("%s: Next track returned error %d",__func__, ret);
             if (-ENETRESET != ret && !(-EINTR == ret &&
-                        CARD_STATUS_OFFLINE == out->card_status)) {
+                (CARD_STATUS_OFFLINE == out->card_status ||
+                POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy))) {
                 send_callback = true;
                 pthread_mutex_lock(&out->lock);
                 out->send_new_metadata = 1;
@@ -3882,7 +3884,8 @@
             ALOGD("copl(%p):out of compress_drain", out);
             // EINTR check avoids drain interruption due to SSR
             if (-ENETRESET != ret && !(-EINTR == ret &&
-                        CARD_STATUS_OFFLINE == out->card_status)) {
+               (CARD_STATUS_OFFLINE == out->card_status ||
+                POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy))) {
                 send_callback = true;
                 event = STREAM_CBK_EVENT_DRAIN_READY;
             } else
@@ -4121,7 +4124,8 @@
                                                       AUDIO_DEVICE_OUT_SPEAKER_SAFE);
 
     if (CARD_STATUS_OFFLINE == out->card_status ||
-        CARD_STATUS_OFFLINE == adev->card_status) {
+        CARD_STATUS_OFFLINE == adev->card_status ||
+        POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
         ALOGW("out->card_status or adev->card_status offline, try again");
         ret = -EIO;
         goto error_fatal;
@@ -6139,7 +6143,8 @@
     ATRACE_BEGIN("out_write");
     lock_output_stream(out);
 
-    if (CARD_STATUS_OFFLINE == out->card_status) {
+    if (CARD_STATUS_OFFLINE == out->card_status ||
+        POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
 
         if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
             /*during SSR for compress usecase we should return error to flinger*/
@@ -6599,7 +6604,8 @@
         } else if(ret < 0) {
             ALOGE(" ERROR: Unable to get time stamp from compress driver");
             ret = -EINVAL;
-        } else if (out->card_status == CARD_STATUS_OFFLINE) {
+        } else if (out->card_status == CARD_STATUS_OFFLINE ||
+                   adev->out_power_policy == POWER_POLICY_STATUS_OFFLINE) {
             /*
              * Handle corner case where compress session is closed during SSR
              * and timestamp is queried
@@ -6728,6 +6734,7 @@
                 ret = 0;
             }
         } else if (out->card_status == CARD_STATUS_OFFLINE ||
+                   adev->out_power_policy == POWER_POLICY_STATUS_OFFLINE ||
             // audioflinger still needs position updates when A2DP is suspended
             (is_a2dp_out_device_type(&out->device_list) && audio_extn_a2dp_source_is_suspended())) {
             *frames = out->written;
@@ -6949,7 +6956,8 @@
     pthread_mutex_lock(&adev->lock);
 
     if (CARD_STATUS_OFFLINE == out->card_status ||
-        CARD_STATUS_OFFLINE == adev->card_status) {
+        CARD_STATUS_OFFLINE == adev->card_status ||
+        POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
         ALOGW("out->card_status or adev->card_status offline, try again");
         ret = -EIO;
         goto exit;
@@ -7828,7 +7836,8 @@
     ALOGV("%s in %p", __func__, in);
 
     if (CARD_STATUS_OFFLINE == in->card_status||
-        CARD_STATUS_OFFLINE == adev->card_status) {
+        CARD_STATUS_OFFLINE == adev->card_status ||
+        POWER_POLICY_STATUS_OFFLINE == adev->in_power_policy) {
         ALOGW("in->card_status or adev->card_status offline, try again");
         ret = -EIO;
         goto exit;
@@ -9029,6 +9038,51 @@
     ALOGV("%s: exit", __func__);
 }
 
+void in_set_power_policy(uint8_t enable)
+{
+    struct listnode *node;
+
+    ALOGD("%s: Enter, state %d", __func__, enable);
+
+    pthread_mutex_lock(&adev->lock);
+    adev->in_power_policy = enable ? POWER_POLICY_STATUS_ONLINE : POWER_POLICY_STATUS_OFFLINE;
+    pthread_mutex_unlock(&adev->lock);
+
+    if (!enable) {
+        list_for_each(node, &adev->active_inputs_list) {
+            streams_input_ctxt_t *in_ctxt = node_to_item(node,
+                                                         streams_input_ctxt_t,
+                                                         list);
+            struct stream_in *in = in_ctxt->input;
+            in_standby(&in->stream.common);
+        }
+    }
+
+    ALOGD("%s: Exit", __func__);
+}
+
+void out_set_power_policy(uint8_t enable)
+{
+    struct listnode *node;
+
+    ALOGD("%s: Enter, state %d", __func__, enable);
+
+    pthread_mutex_lock(&adev->lock);
+    adev->out_power_policy = enable ? POWER_POLICY_STATUS_ONLINE : POWER_POLICY_STATUS_ONLINE;
+    pthread_mutex_unlock(&adev->lock);
+
+    if (!enable) {
+        list_for_each(node, &adev->active_outputs_list) {
+            streams_output_ctxt_t *out_ctxt = node_to_item(node,
+                                                           streams_output_ctxt_t,
+                                                           list);
+            struct stream_out *out = out_ctxt->output;
+            out_on_error(&out->stream.common);
+        }
+    }
+
+    ALOGD("%s: Exit", __func__);
+}
 static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
 {
     struct audio_device *adev = (struct audio_device *)dev;
@@ -11180,6 +11234,8 @@
     pthread_mutex_lock(&adev->lock);
     audio_extn_snd_mon_register_listener(adev, adev_snd_mon_cb);
     adev->card_status = CARD_STATUS_ONLINE;
+    adev->out_power_policy = POWER_POLICY_STATUS_ONLINE;
+    adev->in_power_policy = POWER_POLICY_STATUS_ONLINE;
     audio_extn_battery_properties_listener_init(adev_on_battery_status_changed);
     /*
      * if the battery state callback happens before charging can be queried,
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
old mode 100755
new mode 100644
index 4169926..ecffc06
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -193,6 +193,10 @@
     CARD_STATUS_ONLINE
 } card_status_t;
 
+typedef enum power_policy_status_t {
+    POWER_POLICY_STATUS_OFFLINE,
+    POWER_POLICY_STATUS_ONLINE
+} power_policy_status_t;
 /* These are the supported use cases by the hardware.
  * Each usecase is mapped to a specific PCM device.
  * Refer to pcm_device_table[].
@@ -751,6 +755,8 @@
 
     int snd_card;
     card_status_t card_status;
+    power_policy_status_t out_power_policy;
+    power_policy_status_t in_power_policy;
     unsigned int cur_codec_backend_samplerate;
     unsigned int cur_codec_backend_bit_width;
     bool is_channel_status_set;
@@ -845,6 +851,8 @@
     int curve;
 };
 #endif
+void out_set_power_policy(uint8_t enable);
+void in_set_power_policy(uint8_t enable);
 
 int select_devices(struct audio_device *adev,
                           audio_usecase_t uc_id);