audioflinger: add standby() method to MmapStreamInterface

Bug: 33398120
Test: open/start/stop/close MMAP no IRQ stream for capture and playback

Change-Id: I48ec202a71565f759c441c2a835d8c8190e76334
diff --git a/include/media/MmapStreamInterface.h b/include/media/MmapStreamInterface.h
index 9f3731e..7dbc19e 100644
--- a/include/media/MmapStreamInterface.h
+++ b/include/media/MmapStreamInterface.h
@@ -75,6 +75,7 @@
 
     /**
      * Retrieve information on the mmap buffer used for audio samples transfer.
+     * Must be called before any other method after opening the stream or entering standby.
      *
      * \param[in] min_size_frames minimum buffer size requested. The actual buffer
      *        size returned in struct audio_mmap_buffer_info can be larger.
@@ -94,6 +95,7 @@
      * \param[out] position address at which the mmap read/write position should be returned.
      *
      * \return OK if the position is successfully returned.
+     *         NO_INIT in case of initialization error
      *         NOT_ENOUGH_DATA if the position cannot be retrieved
      *         INVALID_OPERATION if called before createMmapBuffer()
      */
@@ -106,6 +108,7 @@
      * \param[in] client a Client struct describing the client starting on this stream.
      * \param[out] handle unique handle for this instance. Used with stop().
      * \return OK in case of success.
+     *         NO_INIT in case of initialization error
      *         INVALID_OPERATION if called out of sequence
      */
     virtual status_t start(const Client& client, audio_port_handle_t *handle) = 0;
@@ -116,10 +119,23 @@
      *
      * \param[in] handle unique handle allocated by start().
      * \return OK in case of success.
+     *         NO_INIT in case of initialization error
      *         INVALID_OPERATION if called out of sequence
      */
     virtual status_t stop(audio_port_handle_t handle) = 0;
 
+    /**
+     * Put a stream operating in mmap mode into standby.
+     * Must be called after createMmapBuffer(). Cannot be called if any client is active.
+     * It is recommended to place a mmap stream into standby as often as possible when no client is
+     * active to save power.
+     *
+     * \return OK in case of success.
+     *         NO_INIT in case of initialization error
+     *         INVALID_OPERATION if called out of sequence
+     */
+    virtual status_t standby() = 0;
+
   protected:
     // Subclasses can not be constructed directly by clients.
     MmapStreamInterface() {}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 44fd512..4a279ea 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -563,6 +563,7 @@
         virtual status_t getMmapPosition(struct audio_mmap_position *position);
         virtual status_t start(const MmapStreamInterface::Client& client, audio_port_handle_t *handle);
         virtual status_t stop(audio_port_handle_t handle);
+        virtual status_t standby();
 
     private:
         sp<MmapThread> mThread;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index b10e42c..993e76c 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7434,7 +7434,7 @@
 {
     MmapThread *thread = mThread.get();
     // clear our strong reference before disconnecting the thread: the last strong reference
-    // will be removed when closeInput/closeOutput is executed upono call from audio policy manager
+    // will be removed when closeInput/closeOutput is executed upon call from audio policy manager
     // and the thread removed from mMMapThreads list causing the thread destruction.
     mThread.clear();
     if (thread != nullptr) {
@@ -7476,6 +7476,14 @@
     return mThread->stop(handle);
 }
 
+status_t AudioFlinger::MmapThreadHandle::standby()
+{
+    if (mThread == 0) {
+        return NO_INIT;
+    }
+    return mThread->standby();
+}
+
 
 AudioFlinger::MmapThread::MmapThread(
         const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
@@ -7484,11 +7492,13 @@
     : ThreadBase(audioFlinger, id, outDevice, inDevice, MMAP, systemReady),
       mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev)
 {
+    mStandby = true;
     readHalParameters_l();
 }
 
 AudioFlinger::MmapThread::~MmapThread()
 {
+    releaseWakeLock_l();
 }
 
 void AudioFlinger::MmapThread::onFirstRef()
@@ -7528,6 +7538,8 @@
     if (mHalStream == 0) {
         return NO_INIT;
     }
+    mStandby = true;
+    acquireWakeLock();
     return mHalStream->createMmapBuffer(minSizeFrames, info);
 }
 
@@ -7542,7 +7554,7 @@
 status_t AudioFlinger::MmapThread::start(const MmapStreamInterface::Client& client,
                                          audio_port_handle_t *handle)
 {
-    ALOGV("%s clientUid %d", __FUNCTION__, client.clientUid);
+    ALOGV("%s clientUid %d mStandby %d", __FUNCTION__, client.clientUid, mStandby);
     if (mHalStream == 0) {
         return NO_INIT;
     }
@@ -7556,6 +7568,7 @@
         mHalStream->start();
         portId = mPortId;
         sessionId = mSessionId;
+        mStandby = false;
     } else {
         // for other tracks than first one, get a new port ID from APM.
         sessionId = (audio_session_t)mAudioFlinger->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
@@ -7613,6 +7626,8 @@
             } else {
                 AudioSystem::releaseInput(mId, sessionId);
             }
+        } else {
+            mHalStream->stop();
         }
         return PERMISSION_DENIED;
     }
@@ -7632,14 +7647,13 @@
 
     broadcast_l();
 
-    ALOGV("%s DONE handle %d", __FUNCTION__, portId);
+    ALOGV("%s DONE handle %d stream %p", __FUNCTION__, portId, mHalStream.get());
 
     return NO_ERROR;
 }
 
 status_t AudioFlinger::MmapThread::stop(audio_port_handle_t handle)
 {
-
     ALOGV("%s handle %d", __FUNCTION__, handle);
 
     if (mHalStream == 0) {
@@ -7685,6 +7699,22 @@
     return NO_ERROR;
 }
 
+status_t AudioFlinger::MmapThread::standby()
+{
+    ALOGV("%s", __FUNCTION__);
+
+    if (mHalStream == 0) {
+        return NO_INIT;
+    }
+    if (mActiveTracks.size() != 0) {
+        return INVALID_OPERATION;
+    }
+    mHalStream->standby();
+    mStandby = true;
+    releaseWakeLock();
+    return NO_ERROR;
+}
+
 
 void AudioFlinger::MmapThread::readHalParameters_l()
 {
@@ -7701,8 +7731,6 @@
 
 bool AudioFlinger::MmapThread::threadLoop()
 {
-    acquireWakeLock();
-
     checkSilentMode_l();
 
     const String8 myName(String8::format("thread %p type %d TID %d", this, mType, gettid()));
@@ -7724,18 +7752,10 @@
                     break;
                 }
 
-                bool wakelockReleased = false;
-                if (mActiveTracks.size() == 0) {
-                    releaseWakeLock_l();
-                    wakelockReleased = true;
-                }
                 // wait until we have something to do...
                 ALOGV("%s going to sleep", myName.string());
                 mWaitWorkCV.wait(mLock);
                 ALOGV("%s waking up", myName.string());
-                if (wakelockReleased) {
-                    acquireWakeLock_l();
-                }
 
                 checkSilentMode_l();
 
@@ -7768,8 +7788,6 @@
         mStandby = true;
     }
 
-    releaseWakeLock();
-
     ALOGV("Thread %p type %d exiting", this, mType);
     return false;
 }
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 0a17a8e..422eeb5 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1540,6 +1540,7 @@
     status_t getMmapPosition(struct audio_mmap_position *position);
     status_t start(const MmapStreamInterface::Client& client, audio_port_handle_t *handle);
     status_t stop(audio_port_handle_t handle);
+    status_t standby();
 
     // RefBase
     virtual     void        onFirstRef();
@@ -1549,6 +1550,7 @@
 
     virtual     void        threadLoop_exit();
     virtual     void        threadLoop_standby();
+    virtual     bool        shouldStandby_l() { return false; }
 
     virtual     status_t    initCheck() const { return (mHalStream == 0) ? NO_INIT : NO_ERROR; }
     virtual     size_t      frameCount() const { return mFrameCount; }