From 5131d127a042ee88f903370be88845dc8c9f8578 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Fri, 16 Nov 2012 10:38:11 -0800 Subject: [wfd] Support a low(er) power state by triggering PAUSE/RESUME. Change-Id: Ibe42bfa73816bbfeb7e652d435254d0171b89727 related-to-bug: 7638150 --- include/media/IRemoteDisplay.h | 3 + media/libmedia/IRemoteDisplay.cpp | 31 +++++ media/libmediaplayerservice/RemoteDisplay.cpp | 8 ++ media/libmediaplayerservice/RemoteDisplay.h | 2 + .../wifi-display/source/MediaPuller.cpp | 34 ++++- .../wifi-display/source/MediaPuller.h | 6 + .../wifi-display/source/PlaybackSession.cpp | 44 +++++++ .../wifi-display/source/PlaybackSession.h | 3 + .../wifi-display/source/WifiDisplaySource.cpp | 146 +++++++++++++++++---- .../wifi-display/source/WifiDisplaySource.h | 20 ++- 10 files changed, 267 insertions(+), 30 deletions(-) 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 @@ class IRemoteDisplay : public IInterface 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 @@ namespace android { enum { DISPOSE = IBinder::FIRST_CALL_TRANSACTION, + PAUSE, + RESUME, }; class BpRemoteDisplay: public BpInterface @@ -33,6 +35,20 @@ public: { } + 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 @@ status_t BnRemoteDisplay::onTransact( 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( 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 WifiDisplaySource; struct RemoteDisplay : public BnRemoteDisplay { RemoteDisplay(const sp &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 @@ MediaPuller::MediaPuller( : mSource(source), mNotify(notify), mPullGeneration(0), - mIsAudio(false) { + mIsAudio(false), + mPaused(false) { sp meta = source->getFormat(); const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); @@ -71,6 +72,14 @@ void MediaPuller::stopAsync(const sp ¬ify) { msg->post(); } +void MediaPuller::pause() { + (new AMessage(kWhatPause, id()))->post(); +} + +void MediaPuller::resume() { + (new AMessage(kWhatResume, id()))->post(); +} + void MediaPuller::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatStart: @@ -95,7 +104,6 @@ void MediaPuller::onMessageReceived(const sp &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - response->postReply(replyID); break; } @@ -130,6 +138,16 @@ void MediaPuller::onMessageReceived(const sp &msg) { 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 @@ void MediaPuller::onMessageReceived(const sp &msg) { 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 @@ struct MediaPuller : public AHandler { status_t start(); void stopAsync(const sp ¬ify); + void pause(); + void resume(); + protected: virtual void onMessageReceived(const sp &msg); virtual ~MediaPuller(); @@ -44,12 +47,15 @@ private: kWhatStart, kWhatStop, kWhatPull, + kWhatPause, + kWhatResume, }; sp mSource; sp mNotify; int32_t mPullGeneration; bool mIsAudio; + bool mPaused; status_t postSynchronouslyAndReturnError(const sp &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 @@ struct WifiDisplaySource::PlaybackSession::Track : public AHandler { status_t start(); void stopAsync(); + void pause(); + void resume(); + void queueAccessUnit(const sp &accessUnit); sp dequeueAccessUnit(); @@ -208,6 +211,14 @@ void WifiDisplaySource::PlaybackSession::Track::stopAsync() { } } +void WifiDisplaySource::PlaybackSession::Track::pause() { + mMediaPuller->pause(); +} + +void WifiDisplaySource::PlaybackSession::Track::resume() { + mMediaPuller->resume(); +} + void WifiDisplaySource::PlaybackSession::Track::onMessageReceived( const sp &msg) { switch (msg->what()) { @@ -325,6 +336,7 @@ WifiDisplaySource::PlaybackSession::PlaybackSession( mInterfaceAddr(interfaceAddr), mHDCP(hdcp), mWeAreDead(false), + mPaused(false), mLastLifesignUs(), mVideoTrackIndex(-1), mPrevTimeUs(-1ll), @@ -383,6 +395,8 @@ void WifiDisplaySource::PlaybackSession::updateLiveness() { status_t WifiDisplaySource::PlaybackSession::play() { updateLiveness(); + (new AMessage(kWhatResume, id()))->post(); + return OK; } @@ -413,6 +427,8 @@ status_t WifiDisplaySource::PlaybackSession::onFinishPlay2() { status_t WifiDisplaySource::PlaybackSession::pause() { updateLiveness(); + (new AMessage(kWhatPause, id()))->post(); + return OK; } @@ -590,6 +606,34 @@ void WifiDisplaySource::PlaybackSession::onMessageReceived( 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 @@ private: kWhatUpdateSurface, kWhatFinishPlay, kWhatPacketize, + kWhatPause, + kWhatResume, }; sp mNetSession; @@ -93,6 +95,7 @@ private: in_addr mInterfaceAddr; sp 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,41 +65,50 @@ WifiDisplaySource::WifiDisplaySource( WifiDisplaySource::~WifiDisplaySource() { } -status_t WifiDisplaySource::start(const char *iface) { - CHECK_EQ(mState, INITIALIZED); - - sp msg = new AMessage(kWhatStart, id()); - msg->setString("iface", iface); - - sp response; - status_t err = msg->postAndAwaitResponse(&response); +static status_t PostAndAwaitResponse( + const sp &msg, sp *response) { + status_t err = msg->postAndAwaitResponse(response); if (err != OK) { return err; } - if (!response->findInt32("err", &err)) { + if (response == NULL || !(*response)->findInt32("err", &err)) { err = OK; } return err; } +status_t WifiDisplaySource::start(const char *iface) { + CHECK_EQ(mState, INITIALIZED); + + sp msg = new AMessage(kWhatStart, id()); + msg->setString("iface", iface); + + sp response; + return PostAndAwaitResponse(msg, &response); +} + status_t WifiDisplaySource::stop() { sp msg = new AMessage(kWhatStop, id()); sp response; - status_t err = msg->postAndAwaitResponse(&response); + return PostAndAwaitResponse(msg, &response); +} - if (err != OK) { - return err; - } +status_t WifiDisplaySource::pause() { + sp msg = new AMessage(kWhatPause, id()); - if (!response->findInt32("err", &err)) { - err = OK; - } + sp response; + return PostAndAwaitResponse(msg, &response); +} - return err; +status_t WifiDisplaySource::resume() { + sp msg = new AMessage(kWhatResume, id()); + + sp response; + return PostAndAwaitResponse(msg, &response); } void WifiDisplaySource::onMessageReceived(const sp &msg) { @@ -236,6 +245,20 @@ void WifiDisplaySource::onMessageReceived(const sp &msg) { 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 @@ void WifiDisplaySource::onMessageReceived(const sp &msg) { 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 @@ void WifiDisplaySource::onMessageReceived(const sp &msg) { 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 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 response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + case kWhatReapDeadClients: { mReaperPending = false; @@ -400,7 +463,7 @@ void WifiDisplaySource::onMessageReceived(const sp &msg) { if (mSetupTriggerDeferred) { mSetupTriggerDeferred = false; - sendM5(mClientSessionID, false /* requestShutdown */); + sendTrigger(mClientSessionID, TRIGGER_SETUP); } break; } @@ -574,13 +637,25 @@ status_t WifiDisplaySource::sendM4(int32_t sessionID) { 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 @@ status_t WifiDisplaySource::onReceiveM4Response( return OK; } - return sendM5(sessionID, false /* requestShutdown */); + return sendTrigger(sessionID, TRIGGER_SETUP); } status_t WifiDisplaySource::onReceiveM5Response( @@ -1184,6 +1259,11 @@ status_t WifiDisplaySource::onPlayRequest( return err; } + if (mState == PAUSED_TO_PLAYING) { + mState = PLAYING; + return OK; + } + playbackSession->finishPlay(); CHECK_EQ(mState, AWAITING_CLIENT_PLAY); @@ -1205,6 +1285,12 @@ status_t WifiDisplaySource::onPauseRequest( 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 @@ status_t WifiDisplaySource::onPauseRequest( 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 @@ struct WifiDisplaySource : public AHandler { status_t start(const char *iface); status_t stop(); + status_t pause(); + status_t resume(); + protected: virtual ~WifiDisplaySource(); virtual void onMessageReceived(const sp &msg); @@ -59,6 +62,9 @@ private: AWAITING_CLIENT_PLAY, ABOUT_TO_PLAY, PLAYING, + PLAYING_TO_PAUSED, + PAUSED, + PAUSED_TO_PLAYING, AWAITING_CLIENT_TEARDOWN, STOPPING, STOPPED, @@ -68,6 +74,8 @@ private: kWhatStart, kWhatRTSPNotify, kWhatStop, + kWhatPause, + kWhatResume, kWhatReapDeadClients, kWhatPlaybackSessionNotify, kWhatKeepAlive, @@ -147,7 +155,17 @@ private: 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( -- cgit v1.1