Defer audio disable to the next AP wakeup

Bug: 110796813
Test: ./load_chre.sh, reboot, disconnect USB, connect USB after 2 mins,
    adb logcat -s CHRE, see audio defer disabled, 30s later, audio
    disabled

Change-Id: I6b2d0fde574130682ee6fd875de826ae8361b975
diff --git a/core/include/chre/core/audio_request_manager.h b/core/include/chre/core/audio_request_manager.h
index 8f5ec49..11caf20 100644
--- a/core/include/chre/core/audio_request_manager.h
+++ b/core/include/chre/core/audio_request_manager.h
@@ -147,6 +147,14 @@
         / kOneSecondInNanoseconds);
   }
 
+  /**
+   * @return the instance of platform audio to allow platform-specific
+   * funtionality to call it. Example: handling host awake events.
+   */
+  PlatformAudio& getPlatformAudio() {
+    return mPlatformAudio;
+  }
+
  private:
   /**
    * One instance of an audio request from a nanoapp.
diff --git a/core/include/chre/core/event_loop_manager.h b/core/include/chre/core/event_loop_manager.h
index c1991ff..50d9dec 100644
--- a/core/include/chre/core/event_loop_manager.h
+++ b/core/include/chre/core/event_loop_manager.h
@@ -59,6 +59,7 @@
   WifiHandleFailedRanging,
   WifiHandleRangingEvent,
   AudioAvailabilityChange,
+  AudioHandleHostAwake,
 };
 
 //! The function signature of a system callback mirrors the CHRE event free
diff --git a/platform/slpi/include/chre/target_platform/platform_audio_base.h b/platform/slpi/include/chre/target_platform/platform_audio_base.h
index 3b84c3c..8bdeae9 100644
--- a/platform/slpi/include/chre/target_platform/platform_audio_base.h
+++ b/platform/slpi/include/chre/target_platform/platform_audio_base.h
@@ -24,10 +24,24 @@
  * functionality from.
  */
 class PlatformAudioBase {
+ public:
+  /**
+   * Invoked whenever the host goes awake. This is used to implement the
+   * deferred audio disable operation. This is called on the CHRE thread.
+   */
+  void onHostAwake();
+
  protected:
   //! The number of open audio clients. This is incremented/decremented by the
   //! setHandleEnabled platform API.
   uint32_t mNumAudioClients = 0;
+
+  //! The current state of the audio feature enabled on the host.
+  bool currentAudioEnabled = false;
+
+  //! The target state of the audio feature enabled on the host. This is used to
+  //! support deferred disabling when the next AP wake occurs.
+  bool targetAudioEnabled = false;
 };
 
 }  // namespace chre
diff --git a/platform/slpi/platform_audio.cc b/platform/slpi/platform_audio.cc
index 8b4d924..ebf9c80 100644
--- a/platform/slpi/platform_audio.cc
+++ b/platform/slpi/platform_audio.cc
@@ -106,11 +106,21 @@
   }
 
   if (lastNumAudioClients == 0 && mNumAudioClients > 0) {
+    // When enabling, request audio immediately.
     LOGD("Enabling WCD SLPI");
-    sendAudioRequest();
+    targetAudioEnabled = true;
+    if (!currentAudioEnabled) {
+      currentAudioEnabled = true;
+      sendAudioRequest();
+    }
   } else if (lastNumAudioClients > 0 && mNumAudioClients == 0) {
-    LOGD("Disabling WCD SLPI");
-    sendAudioRelease();
+    targetAudioEnabled = false;
+    if (EventLoopManagerSingleton::get()->getEventLoop()
+            .getPowerControlManager().hostIsAwake()) {
+      onHostAwake();
+    } else {
+      LOGD("Deferring disable WCD SLPI");
+    }
   }
 }
 
@@ -151,4 +161,12 @@
   return result;
 }
 
+void PlatformAudioBase::onHostAwake() {
+  if (currentAudioEnabled && !targetAudioEnabled) {
+    LOGD("Disabling WCD SPI");
+    currentAudioEnabled = targetAudioEnabled;
+    sendAudioRelease();
+  }
+}
+
 }  // namespace chre
diff --git a/platform/slpi/see/power_control_manager.cc b/platform/slpi/see/power_control_manager.cc
index b0fd3b8..e98c495 100644
--- a/platform/slpi/see/power_control_manager.cc
+++ b/platform/slpi/see/power_control_manager.cc
@@ -34,6 +34,20 @@
     EventLoopManagerSingleton::get()->getEventLoop().postEvent(
         mHostIsAwake ? CHRE_EVENT_HOST_AWAKE : CHRE_EVENT_HOST_ASLEEP,
         nullptr /* eventData */, nullptr /* freeCallback */);
+
+#ifdef CHRE_AUDIO_SUPPORT_ENABLED
+    if (awake) {
+      auto callback = [](uint16_t /* eventType */, void * /* eventData*/) {
+        auto platformAudioBase = static_cast<PlatformAudioBase&>(
+            EventLoopManagerSingleton::get()->getAudioRequestManager()
+                .getPlatformAudio());
+        platformAudioBase.onHostAwake();
+      };
+
+      EventLoopManagerSingleton::get()->deferCallback(
+          SystemCallbackType::AudioHandleHostAwake, nullptr, callback);
+    }
+#endif  // CHRE_AUDIO_SUPPORT_ENABLED
   }
 }