MediaPlayer: add notifyAt at native side

Test: media time is correct when playback rate is not 1.0
Bug: 65204641
Change-Id: Ie9f67e3cb37267cfd364c9a9b9f674232b68ef27
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index cda3b3a..903e503 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -58,6 +58,7 @@
     GET_CURRENT_POSITION,
     GET_DURATION,
     RESET,
+    NOTIFY_AT,
     SET_AUDIO_STREAM_TYPE,
     SET_LOOPING,
     SET_VOLUME,
@@ -328,6 +329,15 @@
         return reply.readInt32();
     }
 
+    status_t notifyAt(int64_t mediaTimeUs)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeInt64(mediaTimeUs);
+        remote()->transact(NOTIFY_AT, data, &reply);
+        return reply.readInt32();
+    }
+
     status_t setAudioStreamType(audio_stream_type_t stream)
     {
         Parcel data, reply;
@@ -746,6 +756,11 @@
             reply->writeInt32(reset());
             return NO_ERROR;
         } break;
+        case NOTIFY_AT: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(notifyAt(data.readInt64()));
+            return NO_ERROR;
+        } break;
         case SET_AUDIO_STREAM_TYPE: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             reply->writeInt32(setAudioStreamType((audio_stream_type_t) data.readInt32()));
diff --git a/media/libmedia/include/media/IMediaPlayer.h b/media/libmedia/include/media/IMediaPlayer.h
index e657716..e181338 100644
--- a/media/libmedia/include/media/IMediaPlayer.h
+++ b/media/libmedia/include/media/IMediaPlayer.h
@@ -79,6 +79,7 @@
             MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) = 0;
     virtual status_t        getCurrentPosition(int* msec) = 0;
     virtual status_t        getDuration(int* msec) = 0;
+    virtual status_t        notifyAt(int64_t mediaTimeUs) = 0;
     virtual status_t        reset() = 0;
     virtual status_t        setAudioStreamType(audio_stream_type_t type) = 0;
     virtual status_t        setLooping(int loop) = 0;
diff --git a/media/libmedia/include/media/mediaplayer.h b/media/libmedia/include/media/mediaplayer.h
index cb0a99f..25741d3 100644
--- a/media/libmedia/include/media/mediaplayer.h
+++ b/media/libmedia/include/media/mediaplayer.h
@@ -50,6 +50,7 @@
     MEDIA_PAUSED            = 7,
     MEDIA_STOPPED           = 8,
     MEDIA_SKIPPED           = 9,
+    MEDIA_NOTIFY_TIME       = 98,
     MEDIA_TIMED_TEXT        = 99,
     MEDIA_ERROR             = 100,
     MEDIA_INFO              = 200,
@@ -245,6 +246,7 @@
             status_t        seekTo(
                     int msec,
                     MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
+            status_t        notifyAt(int64_t mediaTimeUs);
             status_t        getCurrentPosition(int *msec);
             status_t        getDuration(int *msec);
             status_t        reset();
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 49101d1..00084c1 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -610,6 +610,15 @@
     return result;
 }
 
+status_t MediaPlayer::notifyAt(int64_t mediaTimeUs)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer != 0) {
+        return mPlayer->notifyAt(mediaTimeUs);
+    }
+    return INVALID_OPERATION;
+}
+
 status_t MediaPlayer::reset_l()
 {
     mLoop = false;
@@ -950,6 +959,9 @@
         mVideoWidth = ext1;
         mVideoHeight = ext2;
         break;
+    case MEDIA_NOTIFY_TIME:
+        ALOGV("Received notify time message");
+        break;
     case MEDIA_TIMED_TEXT:
         ALOGV("Received timed text message");
         break;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index ba98f18..d50e10e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1269,6 +1269,14 @@
     return p->reset();
 }
 
+status_t MediaPlayerService::Client::notifyAt(int64_t mediaTimeUs)
+{
+    ALOGV("[%d] notifyAt(%lld)", mConnId, (long long)mediaTimeUs);
+    sp<MediaPlayerBase> p = getPlayer();
+    if (p == 0) return UNKNOWN_ERROR;
+    return p->notifyAt(mediaTimeUs);
+}
+
 status_t MediaPlayerService::Client::setAudioStreamType(audio_stream_type_t type)
 {
     ALOGV("[%d] setAudioStreamType(%d)", mConnId, type);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 25691f9..2ae0f86 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -327,6 +327,7 @@
         virtual status_t        getCurrentPosition(int* msec);
         virtual status_t        getDuration(int* msec);
         virtual status_t        reset();
+        virtual status_t        notifyAt(int64_t mediaTimeUs);
         virtual status_t        setAudioStreamType(audio_stream_type_t type);
         virtual status_t        setLooping(int loop);
         virtual status_t        setVolume(float leftVolume, float rightVolume);
diff --git a/media/libmediaplayerservice/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
index bcdca37..764df70 100644
--- a/media/libmediaplayerservice/include/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -225,6 +225,9 @@
     virtual status_t    getCurrentPosition(int *msec) = 0;
     virtual status_t    getDuration(int *msec) = 0;
     virtual status_t    reset() = 0;
+    virtual status_t    notifyAt(int64_t /* mediaTimeUs */) {
+        return INVALID_OPERATION;
+    }
     virtual status_t    setLooping(int loop) = 0;
     virtual player_type playerType() = 0;
     virtual status_t    setParameter(int key, const Parcel &request) = 0;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 274f613..75bdccc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -473,6 +473,13 @@
     (new AMessage(kWhatReset, this))->post();
 }
 
+status_t NuPlayer::notifyAt(int64_t mediaTimeUs) {
+    sp<AMessage> notify = new AMessage(kWhatNotifyTime, this);
+    notify->setInt64("timerUs", mediaTimeUs);
+    mMediaClock->addTimer(notify, mediaTimeUs);
+    return OK;
+}
+
 void NuPlayer::seekToAsync(int64_t seekTimeUs, MediaPlayerSeekMode mode, bool needNotify) {
     sp<AMessage> msg = new AMessage(kWhatSeek, this);
     msg->setInt64("seekTimeUs", seekTimeUs);
@@ -1315,6 +1322,16 @@
             break;
         }
 
+        case kWhatNotifyTime:
+        {
+            ALOGV("kWhatNotifyTime");
+            int64_t timerUs;
+            CHECK(msg->findInt64("timerUs", &timerUs));
+
+            notifyListener(MEDIA_NOTIFY_TIME, timerUs, 0);
+            break;
+        }
+
         case kWhatSeek:
         {
             int64_t seekTimeUs;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 5e3c48b..eefc2a6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -73,6 +73,9 @@
     // Will notify the driver through "notifyResetComplete" once finished.
     void resetAsync();
 
+    // Request a notification when specified media time is reached.
+    status_t notifyAt(int64_t mediaTimeUs);
+
     // Will notify the driver through "notifySeekComplete" once finished
     // and needNotify is true.
     void seekToAsync(
@@ -140,6 +143,7 @@
         kWhatClosedCaptionNotify        = 'capN',
         kWhatRendererNotify             = 'renN',
         kWhatReset                      = 'rset',
+        kWhatNotifyTime                 = 'nfyT',
         kWhatSeek                       = 'seek',
         kWhatPause                      = 'paus',
         kWhatResume                     = 'rsme',
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 209caeb..4005be8 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -664,6 +664,11 @@
     return OK;
 }
 
+status_t NuPlayerDriver::notifyAt(int64_t mediaTimeUs) {
+    ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs);
+    return mPlayer->notifyAt(mediaTimeUs);
+}
+
 status_t NuPlayerDriver::setLooping(int loop) {
     mLooping = loop != 0;
     return OK;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index b797ca1..666359a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -65,6 +65,7 @@
     virtual status_t getCurrentPosition(int *msec);
     virtual status_t getDuration(int *msec);
     virtual status_t reset();
+    virtual status_t notifyAt(int64_t mediaTimeUs) override;
     virtual status_t setLooping(int loop);
     virtual player_type playerType();
     virtual status_t invoke(const Parcel &request, Parcel *reply);