[wfd] Support a low(er) power state by triggering PAUSE/RESUME.

Change-Id: Ibe42bfa73816bbfeb7e652d435254d0171b89727
related-to-bug: 7638150
diff --git a/include/media/IRemoteDisplay.h b/include/media/IRemoteDisplay.h
index a61704e..c8baae9 100644
--- a/include/media/IRemoteDisplay.h
+++ b/include/media/IRemoteDisplay.h
@@ -39,6 +39,9 @@
 public:
     DECLARE_META_INTERFACE(RemoteDisplay);
 
+    virtual status_t pause() = 0;
+    virtual status_t resume() = 0;
+
     // Disconnects the remote display and stops listening for new connections.
     virtual status_t dispose() = 0;
 };
diff --git a/media/libmedia/IRemoteDisplay.cpp b/media/libmedia/IRemoteDisplay.cpp
index da25a15..1e15434 100644
--- a/media/libmedia/IRemoteDisplay.cpp
+++ b/media/libmedia/IRemoteDisplay.cpp
@@ -23,6 +23,8 @@
 
 enum {
     DISPOSE = IBinder::FIRST_CALL_TRANSACTION,
+    PAUSE,
+    RESUME,
 };
 
 class BpRemoteDisplay: public BpInterface<IRemoteDisplay>
@@ -33,6 +35,20 @@
     {
     }
 
+    virtual status_t pause() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IRemoteDisplay::getInterfaceDescriptor());
+        remote()->transact(PAUSE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t resume() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IRemoteDisplay::getInterfaceDescriptor());
+        remote()->transact(RESUME, data, &reply);
+        return reply.readInt32();
+    }
+
     status_t dispose()
     {
         Parcel data, reply;
@@ -55,6 +71,21 @@
             reply->writeInt32(dispose());
             return NO_ERROR;
         }
+
+        case PAUSE:
+        {
+            CHECK_INTERFACE(IRemoteDisplay, data, reply);
+            reply->writeInt32(pause());
+            return OK;
+        }
+
+        case RESUME:
+        {
+            CHECK_INTERFACE(IRemoteDisplay, data, reply);
+            reply->writeInt32(resume());
+            return OK;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmediaplayerservice/RemoteDisplay.cpp b/media/libmediaplayerservice/RemoteDisplay.cpp
index 5baa3ad..20e6513 100644
--- a/media/libmediaplayerservice/RemoteDisplay.cpp
+++ b/media/libmediaplayerservice/RemoteDisplay.cpp
@@ -40,6 +40,14 @@
 RemoteDisplay::~RemoteDisplay() {
 }
 
+status_t RemoteDisplay::pause() {
+    return mSource->pause();
+}
+
+status_t RemoteDisplay::resume() {
+    return mSource->resume();
+}
+
 status_t RemoteDisplay::dispose() {
     mSource->stop();
 
diff --git a/media/libmediaplayerservice/RemoteDisplay.h b/media/libmediaplayerservice/RemoteDisplay.h
index 0d87250..bd8b684 100644
--- a/media/libmediaplayerservice/RemoteDisplay.h
+++ b/media/libmediaplayerservice/RemoteDisplay.h
@@ -33,6 +33,8 @@
 struct RemoteDisplay : public BnRemoteDisplay {
     RemoteDisplay(const sp<IRemoteDisplayClient> &client, const char *iface);
 
+    virtual status_t pause();
+    virtual status_t resume();
     virtual status_t dispose();
 
 protected:
diff --git a/media/libstagefright/wifi-display/source/MediaPuller.cpp b/media/libstagefright/wifi-display/source/MediaPuller.cpp
index ab69c4a..189bea3 100644
--- a/media/libstagefright/wifi-display/source/MediaPuller.cpp
+++ b/media/libstagefright/wifi-display/source/MediaPuller.cpp
@@ -34,7 +34,8 @@
     : mSource(source),
       mNotify(notify),
       mPullGeneration(0),
-      mIsAudio(false) {
+      mIsAudio(false),
+      mPaused(false) {
     sp<MetaData> meta = source->getFormat();
     const char *mime;
     CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -71,6 +72,14 @@
     msg->post();
 }
 
+void MediaPuller::pause() {
+    (new AMessage(kWhatPause, id()))->post();
+}
+
+void MediaPuller::resume() {
+    (new AMessage(kWhatResume, id()))->post();
+}
+
 void MediaPuller::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatStart:
@@ -95,7 +104,6 @@
 
             uint32_t replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
-
             response->postReply(replyID);
             break;
         }
@@ -130,6 +138,16 @@
             MediaBuffer *mbuf;
             status_t err = mSource->read(&mbuf);
 
+            if (mPaused) {
+                if (err == OK) {
+                    mbuf->release();
+                    mbuf = NULL;
+                }
+
+                schedulePull();
+                break;
+            }
+
             if (err != OK) {
                 if (err == ERROR_END_OF_STREAM) {
                     ALOGI("stream ended.");
@@ -176,6 +194,18 @@
             break;
         }
 
+        case kWhatPause:
+        {
+            mPaused = true;
+            break;
+        }
+
+        case kWhatResume:
+        {
+            mPaused = false;
+            break;
+        }
+
         default:
             TRESPASS();
     }
diff --git a/media/libstagefright/wifi-display/source/MediaPuller.h b/media/libstagefright/wifi-display/source/MediaPuller.h
index 728da7b..1291bb3 100644
--- a/media/libstagefright/wifi-display/source/MediaPuller.h
+++ b/media/libstagefright/wifi-display/source/MediaPuller.h
@@ -35,6 +35,9 @@
     status_t start();
     void stopAsync(const sp<AMessage> &notify);
 
+    void pause();
+    void resume();
+
 protected:
     virtual void onMessageReceived(const sp<AMessage> &msg);
     virtual ~MediaPuller();
@@ -44,12 +47,15 @@
         kWhatStart,
         kWhatStop,
         kWhatPull,
+        kWhatPause,
+        kWhatResume,
     };
 
     sp<MediaSource> mSource;
     sp<AMessage> mNotify;
     int32_t mPullGeneration;
     bool mIsAudio;
+    bool mPaused;
 
     status_t postSynchronouslyAndReturnError(const sp<AMessage> &msg);
     void schedulePull();
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 4e5eb52..916f797 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -76,6 +76,9 @@
     status_t start();
     void stopAsync();
 
+    void pause();
+    void resume();
+
     void queueAccessUnit(const sp<ABuffer> &accessUnit);
     sp<ABuffer> dequeueAccessUnit();
 
@@ -208,6 +211,14 @@
     }
 }
 
+void WifiDisplaySource::PlaybackSession::Track::pause() {
+    mMediaPuller->pause();
+}
+
+void WifiDisplaySource::PlaybackSession::Track::resume() {
+    mMediaPuller->resume();
+}
+
 void WifiDisplaySource::PlaybackSession::Track::onMessageReceived(
         const sp<AMessage> &msg) {
     switch (msg->what()) {
@@ -325,6 +336,7 @@
       mInterfaceAddr(interfaceAddr),
       mHDCP(hdcp),
       mWeAreDead(false),
+      mPaused(false),
       mLastLifesignUs(),
       mVideoTrackIndex(-1),
       mPrevTimeUs(-1ll),
@@ -383,6 +395,8 @@
 status_t WifiDisplaySource::PlaybackSession::play() {
     updateLiveness();
 
+    (new AMessage(kWhatResume, id()))->post();
+
     return OK;
 }
 
@@ -413,6 +427,8 @@
 status_t WifiDisplaySource::PlaybackSession::pause() {
     updateLiveness();
 
+    (new AMessage(kWhatPause, id()))->post();
+
     return OK;
 }
 
@@ -590,6 +606,34 @@
             break;
         }
 
+        case kWhatPause:
+        {
+            if (mPaused) {
+                break;
+            }
+
+            for (size_t i = 0; i < mTracks.size(); ++i) {
+                mTracks.editValueAt(i)->pause();
+            }
+
+            mPaused = true;
+            break;
+        }
+
+        case kWhatResume:
+        {
+            if (!mPaused) {
+                break;
+            }
+
+            for (size_t i = 0; i < mTracks.size(); ++i) {
+                mTracks.editValueAt(i)->resume();
+            }
+
+            mPaused = false;
+            break;
+        }
+
         default:
             TRESPASS();
     }
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h
index dabc1c4..b9d193b 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.h
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.h
@@ -84,6 +84,8 @@
         kWhatUpdateSurface,
         kWhatFinishPlay,
         kWhatPacketize,
+        kWhatPause,
+        kWhatResume,
     };
 
     sp<ANetworkSession> mNetSession;
@@ -93,6 +95,7 @@
     in_addr mInterfaceAddr;
     sp<IHDCP> mHDCP;
     bool mWeAreDead;
+    bool mPaused;
 
     int64_t mLastLifesignUs;
 
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 78d6e62..08f67f9 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -65,6 +65,21 @@
 WifiDisplaySource::~WifiDisplaySource() {
 }
 
+static status_t PostAndAwaitResponse(
+        const sp<AMessage> &msg, sp<AMessage> *response) {
+    status_t err = msg->postAndAwaitResponse(response);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (response == NULL || !(*response)->findInt32("err", &err)) {
+        err = OK;
+    }
+
+    return err;
+}
+
 status_t WifiDisplaySource::start(const char *iface) {
     CHECK_EQ(mState, INITIALIZED);
 
@@ -72,34 +87,28 @@
     msg->setString("iface", iface);
 
     sp<AMessage> response;
-    status_t err = msg->postAndAwaitResponse(&response);
-
-    if (err != OK) {
-        return err;
-    }
-
-    if (!response->findInt32("err", &err)) {
-        err = OK;
-    }
-
-    return err;
+    return PostAndAwaitResponse(msg, &response);
 }
 
 status_t WifiDisplaySource::stop() {
     sp<AMessage> msg = new AMessage(kWhatStop, id());
 
     sp<AMessage> response;
-    status_t err = msg->postAndAwaitResponse(&response);
+    return PostAndAwaitResponse(msg, &response);
+}
 
-    if (err != OK) {
-        return err;
-    }
+status_t WifiDisplaySource::pause() {
+    sp<AMessage> msg = new AMessage(kWhatPause, id());
 
-    if (!response->findInt32("err", &err)) {
-        err = OK;
-    }
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
 
-    return err;
+status_t WifiDisplaySource::resume() {
+    sp<AMessage> msg = new AMessage(kWhatResume, id());
+
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
 }
 
 void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) {
@@ -236,6 +245,20 @@
                         mClient->onDisplayError(
                                 IRemoteDisplayClient::kDisplayErrorUnknown);
                     }
+
+#if 0
+                    // testing only.
+                    char val[PROPERTY_VALUE_MAX];
+                    if (property_get("media.wfd.trigger", val, NULL)) {
+                        if (!strcasecmp(val, "pause") && mState == PLAYING) {
+                            mState = PLAYING_TO_PAUSED;
+                            sendTrigger(mClientSessionID, TRIGGER_PAUSE);
+                        } else if (!strcasecmp(val, "play") && mState == PAUSED) {
+                            mState = PAUSED_TO_PLAYING;
+                            sendTrigger(mClientSessionID, TRIGGER_PLAY);
+                        }
+                    }
+#endif
                     break;
                 }
 
@@ -254,8 +277,8 @@
             if (mState >= AWAITING_CLIENT_PLAY) {
                 // We have a session, i.e. a previous SETUP succeeded.
 
-                status_t err = sendM5(
-                        mClientSessionID, true /* requestShutdown */);
+                status_t err = sendTrigger(
+                        mClientSessionID, TRIGGER_TEARDOWN);
 
                 if (err == OK) {
                     mState = AWAITING_CLIENT_TEARDOWN;
@@ -273,6 +296,46 @@
             break;
         }
 
+        case kWhatPause:
+        {
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            status_t err = OK;
+
+            if (mState != PLAYING) {
+                err = INVALID_OPERATION;
+            } else {
+                mState = PLAYING_TO_PAUSED;
+                sendTrigger(mClientSessionID, TRIGGER_PAUSE);
+            }
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatResume:
+        {
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            status_t err = OK;
+
+            if (mState != PAUSED) {
+                err = INVALID_OPERATION;
+            } else {
+                mState = PAUSED_TO_PLAYING;
+                sendTrigger(mClientSessionID, TRIGGER_PLAY);
+            }
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
         case kWhatReapDeadClients:
         {
             mReaperPending = false;
@@ -400,7 +463,7 @@
                     if (mSetupTriggerDeferred) {
                         mSetupTriggerDeferred = false;
 
-                        sendM5(mClientSessionID, false /* requestShutdown */);
+                        sendTrigger(mClientSessionID, TRIGGER_SETUP);
                     }
                     break;
                 }
@@ -574,13 +637,25 @@
     return OK;
 }
 
-status_t WifiDisplaySource::sendM5(int32_t sessionID, bool requestShutdown) {
+status_t WifiDisplaySource::sendTrigger(
+        int32_t sessionID, TriggerType triggerType) {
     AString body = "wfd_trigger_method: ";
-    if (requestShutdown) {
-        ALOGI("Sending TEARDOWN trigger.");
-        body.append("TEARDOWN");
-    } else {
-        body.append("SETUP");
+    switch (triggerType) {
+        case TRIGGER_SETUP:
+            body.append("SETUP");
+            break;
+        case TRIGGER_TEARDOWN:
+            ALOGI("Sending TEARDOWN trigger.");
+            body.append("TEARDOWN");
+            break;
+        case TRIGGER_PAUSE:
+            body.append("PAUSE");
+            break;
+        case TRIGGER_PLAY:
+            body.append("PLAY");
+            break;
+        default:
+            TRESPASS();
     }
 
     body.append("\r\n");
@@ -807,7 +882,7 @@
         return OK;
     }
 
-    return sendM5(sessionID, false /* requestShutdown */);
+    return sendTrigger(sessionID, TRIGGER_SETUP);
 }
 
 status_t WifiDisplaySource::onReceiveM5Response(
@@ -1184,6 +1259,11 @@
         return err;
     }
 
+    if (mState == PAUSED_TO_PLAYING) {
+        mState = PLAYING;
+        return OK;
+    }
+
     playbackSession->finishPlay();
 
     CHECK_EQ(mState, AWAITING_CLIENT_PLAY);
@@ -1205,6 +1285,12 @@
         return ERROR_MALFORMED;
     }
 
+    ALOGI("Received PAUSE request.");
+
+    if (mState != PLAYING_TO_PAUSED) {
+        return INVALID_OPERATION;
+    }
+
     status_t err = playbackSession->pause();
     CHECK_EQ(err, (status_t)OK);
 
@@ -1214,6 +1300,12 @@
 
     err = mNetSession->sendRequest(sessionID, response.c_str());
 
+    if (err != OK) {
+        return err;
+    }
+
+    mState = PAUSED;
+
     return err;
 }
 
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
index 1e855e7..974e070 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
@@ -44,6 +44,9 @@
     status_t start(const char *iface);
     status_t stop();
 
+    status_t pause();
+    status_t resume();
+
 protected:
     virtual ~WifiDisplaySource();
     virtual void onMessageReceived(const sp<AMessage> &msg);
@@ -59,6 +62,9 @@
         AWAITING_CLIENT_PLAY,
         ABOUT_TO_PLAY,
         PLAYING,
+        PLAYING_TO_PAUSED,
+        PAUSED,
+        PAUSED_TO_PLAYING,
         AWAITING_CLIENT_TEARDOWN,
         STOPPING,
         STOPPED,
@@ -68,6 +74,8 @@
         kWhatStart,
         kWhatRTSPNotify,
         kWhatStop,
+        kWhatPause,
+        kWhatResume,
         kWhatReapDeadClients,
         kWhatPlaybackSessionNotify,
         kWhatKeepAlive,
@@ -147,7 +155,17 @@
     status_t sendM1(int32_t sessionID);
     status_t sendM3(int32_t sessionID);
     status_t sendM4(int32_t sessionID);
-    status_t sendM5(int32_t sessionID, bool requestShutdown);
+
+    enum TriggerType {
+        TRIGGER_SETUP,
+        TRIGGER_TEARDOWN,
+        TRIGGER_PAUSE,
+        TRIGGER_PLAY,
+    };
+
+    // M5
+    status_t sendTrigger(int32_t sessionID, TriggerType triggerType);
+
     status_t sendM16(int32_t sessionID);
 
     status_t onReceiveM1Response(