MediaClock: add timer
Test: compiles
Bug: 65204641
Change-Id: Id80a41481255a8f8a9adce40cf10f629f996c6aa
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 19281cd..209caeb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -78,6 +78,8 @@
ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
mLooper->setName("NuPlayerDriver Looper");
+ mMediaClock->init();
+
// set up an analytics record
mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
mAnalyticsItem->generateSessionID();
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 3aa0061..669e09b 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -21,7 +21,7 @@
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
namespace android {
@@ -34,10 +34,41 @@
mAnchorTimeRealUs(-1),
mMaxTimeMediaUs(INT64_MAX),
mStartingTimeMediaUs(-1),
- mPlaybackRate(1.0) {
+ mPlaybackRate(1.0),
+ mGeneration(0) {
+ mLooper = new ALooper;
+ mLooper->setName("MediaClock");
+ mLooper->start(false /* runOnCallingThread */,
+ false /* canCallJava */,
+ ANDROID_PRIORITY_AUDIO);
+}
+
+void MediaClock::init() {
+ mLooper->registerHandler(this);
}
MediaClock::~MediaClock() {
+ reset();
+ if (mLooper != NULL) {
+ mLooper->unregisterHandler(id());
+ mLooper->stop();
+ }
+}
+
+void MediaClock::reset() {
+ Mutex::Autolock autoLock(mLock);
+ auto it = mTimers.begin();
+ while (it != mTimers.end()) {
+ it->second->setInt32("reason", TIMER_REASON_RESET);
+ it->second->post();
+ it = mTimers.erase(it);
+ }
+ mAnchorTimeMediaUs = -1;
+ mAnchorTimeRealUs = -1;
+ mMaxTimeMediaUs = INT64_MAX;
+ mStartingTimeMediaUs = -1;
+ mPlaybackRate = 1.0;
+ ++mGeneration;
}
void MediaClock::setStartingTimeMedia(int64_t startingTimeMediaUs) {
@@ -82,6 +113,9 @@
}
mAnchorTimeRealUs = nowUs;
mAnchorTimeMediaUs = nowMediaUs;
+
+ ++mGeneration;
+ processTimers_l();
}
void MediaClock::updateMaxTimeMedia(int64_t maxTimeMediaUs) {
@@ -105,6 +139,11 @@
}
mAnchorTimeRealUs = nowUs;
mPlaybackRate = rate;
+
+ if (rate > 0.0) {
+ ++mGeneration;
+ processTimers_l();
+ }
}
float MediaClock::getPlaybackRate() const {
@@ -165,4 +204,64 @@
return OK;
}
+void MediaClock::addTimer(const sp<AMessage> ¬ify, int64_t mediaTimeUs) {
+ Mutex::Autolock autoLock(mLock);
+ int64_t nextMediaTimeUs = INT64_MAX;
+ if (!mTimers.empty()) {
+ nextMediaTimeUs = mTimers.begin()->first;
+ }
+
+ mTimers.emplace(mediaTimeUs, notify);
+ if (mediaTimeUs < nextMediaTimeUs) {
+ ++mGeneration;
+ processTimers_l();
+ }
+}
+
+void MediaClock::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatTimeIsUp:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ Mutex::Autolock autoLock(mLock);
+ if (generation != mGeneration) {
+ break;
+ }
+ processTimers_l();
+ break;
+ }
+
+ default:
+ TRESPASS();
+ break;
+ }
+}
+
+void MediaClock::processTimers_l() {
+ int64_t nowMediaTimeUs;
+ status_t status = getMediaTime_l(
+ ALooper::GetNowUs(), &nowMediaTimeUs, false /* allowPastMaxTime */);
+
+ if (status != OK) {
+ return;
+ }
+
+ auto it = mTimers.begin();
+ while (it != mTimers.end() && it->first <= nowMediaTimeUs) {
+ it->second->setInt32("reason", TIMER_REASON_REACHED);
+ it->second->post();
+ it = mTimers.erase(it);
+ }
+
+ if (it == mTimers.end() || mPlaybackRate == 0.0 || mAnchorTimeMediaUs < 0) {
+ return;
+ }
+
+ sp<AMessage> msg = new AMessage(kWhatTimeIsUp, this);
+ msg->setInt32("generation", mGeneration);
+ msg->post((it->first - nowMediaTimeUs) / (double)mPlaybackRate);
+}
+
} // namespace android
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 9278381..ba14e5d 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -61,6 +61,7 @@
mNextBufferItemMediaUs(-1),
mPlaybackRate(0.0) {
mMediaClock = new MediaClock;
+ mMediaClock->init();
// initialize settings
mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT;
diff --git a/media/libstagefright/include/media/stagefright/MediaClock.h b/media/libstagefright/include/media/stagefright/MediaClock.h
index dd1a809..59f700a 100644
--- a/media/libstagefright/include/media/stagefright/MediaClock.h
+++ b/media/libstagefright/include/media/stagefright/MediaClock.h
@@ -18,7 +18,8 @@
#define MEDIA_CLOCK_H_
-#include <media/stagefright/foundation/ABase.h>
+#include <map>
+#include <media/stagefright/foundation/AHandler.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
@@ -26,8 +27,15 @@
struct AMessage;
-struct MediaClock : public RefBase {
+struct MediaClock : public AHandler {
+ enum {
+ TIMER_REASON_REACHED = 0,
+ TIMER_REASON_NO_CLOCK = 1,
+ TIMER_REASON_RESET = 2,
+ };
+
MediaClock();
+ void init();
void setStartingTimeMedia(int64_t startingTimeMediaUs);
@@ -54,15 +62,28 @@
// The result is saved in |outRealUs|.
status_t getRealTimeFor(int64_t targetMediaUs, int64_t *outRealUs) const;
+ void addTimer(const sp<AMessage> ¬ify, int64_t mediaTimeUs);
+
+ void reset();
+
protected:
virtual ~MediaClock();
+ virtual void onMessageReceived(const sp<AMessage> &msg);
+
private:
+ enum {
+ kWhatTimeIsUp = 'tIsU',
+ };
+
status_t getMediaTime_l(
int64_t realUs,
int64_t *outMediaUs,
bool allowPastMaxTime) const;
+ void processTimers_l();
+
+ sp<ALooper> mLooper;
mutable Mutex mLock;
int64_t mAnchorTimeMediaUs;
@@ -72,6 +93,9 @@
float mPlaybackRate;
+ int32_t mGeneration;
+ std::multimap<int64_t, sp<AMessage> > mTimers;
+
DISALLOW_EVIL_CONSTRUCTORS(MediaClock);
};