1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "NuPlayerDriver"
19 #include <inttypes.h>
20 #include <android-base/macros.h>
21 #include <utils/Log.h>
22 #include <cutils/properties.h>
23 
24 #include "NuPlayerDriver.h"
25 
26 #include "NuPlayer.h"
27 #include "NuPlayerSource.h"
28 
29 #include <media/stagefright/foundation/ADebug.h>
30 #include <media/stagefright/foundation/ALooper.h>
31 #include <media/stagefright/foundation/AUtils.h>
32 #include <media/stagefright/foundation/ByteUtils.h>
33 #include <media/stagefright/MediaClock.h>
34 #include <media/stagefright/MetaData.h>
35 #include <media/stagefright/Utils.h>
36 
37 #include <media/IMediaAnalyticsService.h>
38 
39 static const int kDumpLockRetries = 50;
40 static const int kDumpLockSleepUs = 20000;
41 
42 namespace android {
43 
44 // key for media statistics
45 static const char *kKeyPlayer = "nuplayer";
46 // attrs for media statistics
47     // NB: these are matched with public Java API constants defined
48     // in frameworks/base/media/java/android/media/MediaPlayer.java
49     // These must be kept synchronized with the constants there.
50 static const char *kPlayerVMime = "android.media.mediaplayer.video.mime";
51 static const char *kPlayerVCodec = "android.media.mediaplayer.video.codec";
52 static const char *kPlayerWidth = "android.media.mediaplayer.width";
53 static const char *kPlayerHeight = "android.media.mediaplayer.height";
54 static const char *kPlayerFrames = "android.media.mediaplayer.frames";
55 static const char *kPlayerFramesDropped = "android.media.mediaplayer.dropped";
56 static const char *kPlayerFrameRate = "android.media.mediaplayer.fps";
57 static const char *kPlayerAMime = "android.media.mediaplayer.audio.mime";
58 static const char *kPlayerACodec = "android.media.mediaplayer.audio.codec";
59 static const char *kPlayerDuration = "android.media.mediaplayer.durationMs";
60 static const char *kPlayerPlaying = "android.media.mediaplayer.playingMs";
61 static const char *kPlayerError = "android.media.mediaplayer.err";
62 static const char *kPlayerErrorCode = "android.media.mediaplayer.errcode";
63 
64     // NB: These are not yet exposed as public Java API constants.
65 static const char *kPlayerErrorState = "android.media.mediaplayer.errstate";
66 static const char *kPlayerDataSourceType = "android.media.mediaplayer.dataSource";
67 //
68 static const char *kPlayerRebuffering = "android.media.mediaplayer.rebufferingMs";
69 static const char *kPlayerRebufferingCount = "android.media.mediaplayer.rebuffers";
70 static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
71 
72 
NuPlayerDriver(pid_t pid)73 NuPlayerDriver::NuPlayerDriver(pid_t pid)
74     : mState(STATE_IDLE),
75       mIsAsyncPrepare(false),
76       mAsyncResult(UNKNOWN_ERROR),
77       mSetSurfaceInProgress(false),
78       mDurationUs(-1),
79       mPositionUs(-1),
80       mSeekInProgress(false),
81       mPlayingTimeUs(0),
82       mRebufferingTimeUs(0),
83       mRebufferingEvents(0),
84       mRebufferingAtExit(false),
85       mLooper(new ALooper),
86       mMediaClock(new MediaClock),
87       mPlayer(new NuPlayer(pid, mMediaClock)),
88       mPlayerFlags(0),
89       mAnalyticsItem(NULL),
90       mClientUid(-1),
91       mAtEOS(false),
92       mLooping(false),
93       mAutoLoop(false) {
94     ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
95     mLooper->setName("NuPlayerDriver Looper");
96 
97     mMediaClock->init();
98 
99     // set up an analytics record
100     mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer);
101 
102     mLooper->start(
103             false, /* runOnCallingThread */
104             true,  /* canCallJava */
105             PRIORITY_AUDIO);
106 
107     mLooper->registerHandler(mPlayer);
108 
109     mPlayer->init(this);
110 }
111 
~NuPlayerDriver()112 NuPlayerDriver::~NuPlayerDriver() {
113     ALOGV("~NuPlayerDriver(%p)", this);
114     mLooper->stop();
115 
116     // finalize any pending metrics, usually a no-op.
117     updateMetrics("destructor");
118     logMetrics("destructor");
119 
120     if (mAnalyticsItem != NULL) {
121         delete mAnalyticsItem;
122         mAnalyticsItem = NULL;
123     }
124 }
125 
initCheck()126 status_t NuPlayerDriver::initCheck() {
127     return OK;
128 }
129 
setUID(uid_t uid)130 status_t NuPlayerDriver::setUID(uid_t uid) {
131     mPlayer->setUID(uid);
132     mClientUid = uid;
133     if (mAnalyticsItem) {
134         mAnalyticsItem->setUid(mClientUid);
135     }
136 
137     return OK;
138 }
139 
setDataSource(const sp<IMediaHTTPService> & httpService,const char * url,const KeyedVector<String8,String8> * headers)140 status_t NuPlayerDriver::setDataSource(
141         const sp<IMediaHTTPService> &httpService,
142         const char *url,
143         const KeyedVector<String8, String8> *headers) {
144     ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str());
145     Mutex::Autolock autoLock(mLock);
146 
147     if (mState != STATE_IDLE) {
148         return INVALID_OPERATION;
149     }
150 
151     mState = STATE_SET_DATASOURCE_PENDING;
152 
153     mPlayer->setDataSourceAsync(httpService, url, headers);
154 
155     while (mState == STATE_SET_DATASOURCE_PENDING) {
156         mCondition.wait(mLock);
157     }
158 
159     return mAsyncResult;
160 }
161 
setDataSource(int fd,int64_t offset,int64_t length)162 status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
163     ALOGV("setDataSource(%p) file(%d)", this, fd);
164     Mutex::Autolock autoLock(mLock);
165 
166     if (mState != STATE_IDLE) {
167         return INVALID_OPERATION;
168     }
169 
170     mState = STATE_SET_DATASOURCE_PENDING;
171 
172     mPlayer->setDataSourceAsync(fd, offset, length);
173 
174     while (mState == STATE_SET_DATASOURCE_PENDING) {
175         mCondition.wait(mLock);
176     }
177 
178     return mAsyncResult;
179 }
180 
setDataSource(const sp<IStreamSource> & source)181 status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
182     ALOGV("setDataSource(%p) stream source", this);
183     Mutex::Autolock autoLock(mLock);
184 
185     if (mState != STATE_IDLE) {
186         return INVALID_OPERATION;
187     }
188 
189     mState = STATE_SET_DATASOURCE_PENDING;
190 
191     mPlayer->setDataSourceAsync(source);
192 
193     while (mState == STATE_SET_DATASOURCE_PENDING) {
194         mCondition.wait(mLock);
195     }
196 
197     return mAsyncResult;
198 }
199 
setDataSource(const sp<DataSource> & source)200 status_t NuPlayerDriver::setDataSource(const sp<DataSource> &source) {
201     ALOGV("setDataSource(%p) callback source", this);
202     Mutex::Autolock autoLock(mLock);
203 
204     if (mState != STATE_IDLE) {
205         return INVALID_OPERATION;
206     }
207 
208     mState = STATE_SET_DATASOURCE_PENDING;
209 
210     mPlayer->setDataSourceAsync(source);
211 
212     while (mState == STATE_SET_DATASOURCE_PENDING) {
213         mCondition.wait(mLock);
214     }
215 
216     return mAsyncResult;
217 }
218 
setVideoSurfaceTexture(const sp<IGraphicBufferProducer> & bufferProducer)219 status_t NuPlayerDriver::setVideoSurfaceTexture(
220         const sp<IGraphicBufferProducer> &bufferProducer) {
221     ALOGV("setVideoSurfaceTexture(%p)", this);
222     Mutex::Autolock autoLock(mLock);
223 
224     if (mSetSurfaceInProgress) {
225         return INVALID_OPERATION;
226     }
227 
228     switch (mState) {
229         case STATE_SET_DATASOURCE_PENDING:
230         case STATE_RESET_IN_PROGRESS:
231             return INVALID_OPERATION;
232 
233         default:
234             break;
235     }
236 
237     mSetSurfaceInProgress = true;
238 
239     mPlayer->setVideoSurfaceTextureAsync(bufferProducer);
240 
241     while (mSetSurfaceInProgress) {
242         mCondition.wait(mLock);
243     }
244 
245     return OK;
246 }
247 
getBufferingSettings(BufferingSettings * buffering)248 status_t NuPlayerDriver::getBufferingSettings(BufferingSettings* buffering) {
249     ALOGV("getBufferingSettings(%p)", this);
250     {
251         Mutex::Autolock autoLock(mLock);
252         if (mState == STATE_IDLE) {
253             return INVALID_OPERATION;
254         }
255     }
256 
257     return mPlayer->getBufferingSettings(buffering);
258 }
259 
setBufferingSettings(const BufferingSettings & buffering)260 status_t NuPlayerDriver::setBufferingSettings(const BufferingSettings& buffering) {
261     ALOGV("setBufferingSettings(%p)", this);
262     {
263         Mutex::Autolock autoLock(mLock);
264         if (mState == STATE_IDLE) {
265             return INVALID_OPERATION;
266         }
267     }
268 
269     return mPlayer->setBufferingSettings(buffering);
270 }
271 
prepare()272 status_t NuPlayerDriver::prepare() {
273     ALOGV("prepare(%p)", this);
274     Mutex::Autolock autoLock(mLock);
275     return prepare_l();
276 }
277 
prepare_l()278 status_t NuPlayerDriver::prepare_l() {
279     switch (mState) {
280         case STATE_UNPREPARED:
281             mState = STATE_PREPARING;
282 
283             // Make sure we're not posting any notifications, success or
284             // failure information is only communicated through our result
285             // code.
286             mIsAsyncPrepare = false;
287             mPlayer->prepareAsync();
288             while (mState == STATE_PREPARING) {
289                 mCondition.wait(mLock);
290             }
291             return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
292         case STATE_STOPPED:
293             // this is really just paused. handle as seek to start
294             mAtEOS = false;
295             mState = STATE_STOPPED_AND_PREPARING;
296             mIsAsyncPrepare = false;
297             mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
298                     true /* needNotify */);
299             while (mState == STATE_STOPPED_AND_PREPARING) {
300                 mCondition.wait(mLock);
301             }
302             return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
303         default:
304             return INVALID_OPERATION;
305     };
306 }
307 
prepareAsync()308 status_t NuPlayerDriver::prepareAsync() {
309     ALOGV("prepareAsync(%p)", this);
310     Mutex::Autolock autoLock(mLock);
311 
312     switch (mState) {
313         case STATE_UNPREPARED:
314             mState = STATE_PREPARING;
315             mIsAsyncPrepare = true;
316             mPlayer->prepareAsync();
317             return OK;
318         case STATE_STOPPED:
319             // this is really just paused. handle as seek to start
320             mAtEOS = false;
321             mState = STATE_STOPPED_AND_PREPARING;
322             mIsAsyncPrepare = true;
323             mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
324                     true /* needNotify */);
325             return OK;
326         default:
327             return INVALID_OPERATION;
328     };
329 }
330 
start()331 status_t NuPlayerDriver::start() {
332     ALOGV("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
333     Mutex::Autolock autoLock(mLock);
334     return start_l();
335 }
336 
start_l()337 status_t NuPlayerDriver::start_l() {
338     switch (mState) {
339         case STATE_UNPREPARED:
340         {
341             status_t err = prepare_l();
342 
343             if (err != OK) {
344                 return err;
345             }
346 
347             CHECK_EQ(mState, STATE_PREPARED);
348 
349             FALLTHROUGH_INTENDED;
350         }
351 
352         case STATE_PAUSED:
353         case STATE_STOPPED_AND_PREPARED:
354         case STATE_PREPARED:
355         {
356             mPlayer->start();
357 
358             FALLTHROUGH_INTENDED;
359         }
360 
361         case STATE_RUNNING:
362         {
363             if (mAtEOS) {
364                 mPlayer->seekToAsync(0);
365                 mAtEOS = false;
366                 mPositionUs = -1;
367             }
368             break;
369         }
370 
371         default:
372             return INVALID_OPERATION;
373     }
374 
375     mState = STATE_RUNNING;
376 
377     return OK;
378 }
379 
stop()380 status_t NuPlayerDriver::stop() {
381     ALOGD("stop(%p)", this);
382     Mutex::Autolock autoLock(mLock);
383 
384     switch (mState) {
385         case STATE_RUNNING:
386             mPlayer->pause();
387             FALLTHROUGH_INTENDED;
388 
389         case STATE_PAUSED:
390             mState = STATE_STOPPED;
391             notifyListener_l(MEDIA_STOPPED);
392             break;
393 
394         case STATE_PREPARED:
395         case STATE_STOPPED:
396         case STATE_STOPPED_AND_PREPARING:
397         case STATE_STOPPED_AND_PREPARED:
398             mState = STATE_STOPPED;
399             break;
400 
401         default:
402             return INVALID_OPERATION;
403     }
404 
405     return OK;
406 }
407 
pause()408 status_t NuPlayerDriver::pause() {
409     ALOGD("pause(%p)", this);
410     // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
411     // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
412     // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
413     // getCurrentPosition here.
414     int unused;
415     getCurrentPosition(&unused);
416 
417     Mutex::Autolock autoLock(mLock);
418 
419     switch (mState) {
420         case STATE_PAUSED:
421         case STATE_PREPARED:
422             return OK;
423 
424         case STATE_RUNNING:
425             mState = STATE_PAUSED;
426             notifyListener_l(MEDIA_PAUSED);
427             mPlayer->pause();
428             break;
429 
430         default:
431             return INVALID_OPERATION;
432     }
433 
434     return OK;
435 }
436 
isPlaying()437 bool NuPlayerDriver::isPlaying() {
438     return mState == STATE_RUNNING && !mAtEOS;
439 }
440 
setPlaybackSettings(const AudioPlaybackRate & rate)441 status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) {
442     status_t err = mPlayer->setPlaybackSettings(rate);
443     if (err == OK) {
444         // try to update position
445         int unused;
446         getCurrentPosition(&unused);
447         Mutex::Autolock autoLock(mLock);
448         if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
449             mState = STATE_PAUSED;
450             notifyListener_l(MEDIA_PAUSED);
451         } else if (rate.mSpeed != 0.f
452                 && (mState == STATE_PAUSED
453                     || mState == STATE_STOPPED_AND_PREPARED
454                     || mState == STATE_PREPARED)) {
455             err = start_l();
456         }
457     }
458     return err;
459 }
460 
getPlaybackSettings(AudioPlaybackRate * rate)461 status_t NuPlayerDriver::getPlaybackSettings(AudioPlaybackRate *rate) {
462     return mPlayer->getPlaybackSettings(rate);
463 }
464 
setSyncSettings(const AVSyncSettings & sync,float videoFpsHint)465 status_t NuPlayerDriver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
466     return mPlayer->setSyncSettings(sync, videoFpsHint);
467 }
468 
getSyncSettings(AVSyncSettings * sync,float * videoFps)469 status_t NuPlayerDriver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
470     return mPlayer->getSyncSettings(sync, videoFps);
471 }
472 
seekTo(int msec,MediaPlayerSeekMode mode)473 status_t NuPlayerDriver::seekTo(int msec, MediaPlayerSeekMode mode) {
474     ALOGV("seekTo(%p) (%d ms, %d) at state %d", this, msec, mode, mState);
475     Mutex::Autolock autoLock(mLock);
476 
477     int64_t seekTimeUs = msec * 1000LL;
478 
479     switch (mState) {
480         case STATE_PREPARED:
481         case STATE_STOPPED_AND_PREPARED:
482         case STATE_PAUSED:
483         case STATE_RUNNING:
484         {
485             mAtEOS = false;
486             mSeekInProgress = true;
487             // seeks can take a while, so we essentially paused
488             notifyListener_l(MEDIA_PAUSED);
489             mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
490             break;
491         }
492 
493         default:
494             return INVALID_OPERATION;
495     }
496 
497     mPositionUs = seekTimeUs;
498     return OK;
499 }
500 
getCurrentPosition(int * msec)501 status_t NuPlayerDriver::getCurrentPosition(int *msec) {
502     int64_t tempUs = 0;
503     {
504         Mutex::Autolock autoLock(mLock);
505         if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
506             tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
507             *msec = (int)divRound(tempUs, (int64_t)(1000));
508             return OK;
509         }
510     }
511 
512     status_t ret = mPlayer->getCurrentPosition(&tempUs);
513 
514     Mutex::Autolock autoLock(mLock);
515     // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
516     // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
517     // position value that's different the seek to position.
518     if (ret != OK) {
519         tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
520     } else {
521         mPositionUs = tempUs;
522     }
523     *msec = (int)divRound(tempUs, (int64_t)(1000));
524     return OK;
525 }
526 
getDuration(int * msec)527 status_t NuPlayerDriver::getDuration(int *msec) {
528     Mutex::Autolock autoLock(mLock);
529 
530     if (mDurationUs < 0) {
531         return UNKNOWN_ERROR;
532     }
533 
534     *msec = (mDurationUs + 500LL) / 1000;
535 
536     return OK;
537 }
538 
updateMetrics(const char * where)539 void NuPlayerDriver::updateMetrics(const char *where) {
540 
541     if (where == NULL) {
542         where = "unknown";
543     }
544     ALOGV("updateMetrics(%p) from %s at state %d", this, where, mState);
545 
546     // gather the final stats for this record
547     Vector<sp<AMessage>> trackStats;
548     mPlayer->getStats(&trackStats);
549 
550     if (trackStats.size() > 0) {
551         for (size_t i = 0; i < trackStats.size(); ++i) {
552             const sp<AMessage> &stats = trackStats.itemAt(i);
553 
554             AString mime;
555             stats->findString("mime", &mime);
556 
557             AString name;
558             stats->findString("component-name", &name);
559 
560             if (mime.startsWith("video/")) {
561                 int32_t width, height;
562                 mAnalyticsItem->setCString(kPlayerVMime, mime.c_str());
563                 if (!name.empty()) {
564                     mAnalyticsItem->setCString(kPlayerVCodec, name.c_str());
565                 }
566 
567                 if (stats->findInt32("width", &width)
568                         && stats->findInt32("height", &height)) {
569                     mAnalyticsItem->setInt32(kPlayerWidth, width);
570                     mAnalyticsItem->setInt32(kPlayerHeight, height);
571                 }
572 
573                 int64_t numFramesTotal = 0;
574                 int64_t numFramesDropped = 0;
575                 stats->findInt64("frames-total", &numFramesTotal);
576                 stats->findInt64("frames-dropped-output", &numFramesDropped);
577 
578                 mAnalyticsItem->setInt64(kPlayerFrames, numFramesTotal);
579                 mAnalyticsItem->setInt64(kPlayerFramesDropped, numFramesDropped);
580 
581                 float frameRate = 0;
582                 if (stats->findFloat("frame-rate-total", &frameRate)) {
583                     mAnalyticsItem->setDouble(kPlayerFrameRate, (double) frameRate);
584                 }
585 
586             } else if (mime.startsWith("audio/")) {
587                 mAnalyticsItem->setCString(kPlayerAMime, mime.c_str());
588                 if (!name.empty()) {
589                     mAnalyticsItem->setCString(kPlayerACodec, name.c_str());
590                 }
591             }
592         }
593     }
594 
595     // always provide duration and playing time, even if they have 0/unknown values.
596 
597     // getDuration() uses mLock for mutex -- careful where we use it.
598     int duration_ms = -1;
599     getDuration(&duration_ms);
600     mAnalyticsItem->setInt64(kPlayerDuration, duration_ms);
601 
602     mPlayer->updateInternalTimers();
603 
604     mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
605 
606     if (mRebufferingEvents != 0) {
607         mAnalyticsItem->setInt64(kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
608         mAnalyticsItem->setInt32(kPlayerRebufferingCount, mRebufferingEvents);
609         mAnalyticsItem->setInt32(kPlayerRebufferingAtExit, mRebufferingAtExit);
610 
611     }
612 
613     mAnalyticsItem->setCString(kPlayerDataSourceType, mPlayer->getDataSourceType());
614 }
615 
616 
logMetrics(const char * where)617 void NuPlayerDriver::logMetrics(const char *where) {
618     if (where == NULL) {
619         where = "unknown";
620     }
621     ALOGV("logMetrics(%p) from %s at state %d", this, where, mState);
622 
623     if (mAnalyticsItem == NULL || mAnalyticsItem->isEnabled() == false) {
624         return;
625     }
626 
627     // log only non-empty records
628     // we always updateMetrics() before we get here
629     // and that always injects 3 fields (duration, playing time, and
630     // datasource) into the record.
631     // So the canonical "empty" record has 3 elements in it.
632     if (mAnalyticsItem->count() > 3) {
633 
634         mAnalyticsItem->selfrecord();
635 
636         // re-init in case we prepare() and start() again.
637         delete mAnalyticsItem ;
638         mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer);
639         if (mAnalyticsItem) {
640             mAnalyticsItem->setUid(mClientUid);
641         }
642     } else {
643         ALOGV("nothing to record (only %d fields)", mAnalyticsItem->count());
644     }
645 }
646 
reset()647 status_t NuPlayerDriver::reset() {
648     ALOGD("reset(%p) at state %d", this, mState);
649 
650     updateMetrics("reset");
651     logMetrics("reset");
652 
653     Mutex::Autolock autoLock(mLock);
654 
655     switch (mState) {
656         case STATE_IDLE:
657             return OK;
658 
659         case STATE_SET_DATASOURCE_PENDING:
660         case STATE_RESET_IN_PROGRESS:
661             return INVALID_OPERATION;
662 
663         case STATE_PREPARING:
664         {
665             CHECK(mIsAsyncPrepare);
666 
667             notifyListener_l(MEDIA_PREPARED);
668             break;
669         }
670 
671         default:
672             break;
673     }
674 
675     if (mState != STATE_STOPPED) {
676         notifyListener_l(MEDIA_STOPPED);
677     }
678 
679     if (property_get_bool("persist.debug.sf.stats", false)) {
680         Vector<String16> args;
681         dump(-1, args);
682     }
683 
684     mState = STATE_RESET_IN_PROGRESS;
685     mPlayer->resetAsync();
686 
687     while (mState == STATE_RESET_IN_PROGRESS) {
688         mCondition.wait(mLock);
689     }
690 
691     mDurationUs = -1;
692     mPositionUs = -1;
693     mLooping = false;
694     mPlayingTimeUs = 0;
695     mRebufferingTimeUs = 0;
696     mRebufferingEvents = 0;
697     mRebufferingAtExit = false;
698 
699     return OK;
700 }
701 
notifyAt(int64_t mediaTimeUs)702 status_t NuPlayerDriver::notifyAt(int64_t mediaTimeUs) {
703     ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs);
704     return mPlayer->notifyAt(mediaTimeUs);
705 }
706 
setLooping(int loop)707 status_t NuPlayerDriver::setLooping(int loop) {
708     mLooping = loop != 0;
709     return OK;
710 }
711 
playerType()712 player_type NuPlayerDriver::playerType() {
713     return NU_PLAYER;
714 }
715 
invoke(const Parcel & request,Parcel * reply)716 status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
717     if (reply == NULL) {
718         ALOGE("reply is a NULL pointer");
719         return BAD_VALUE;
720     }
721 
722     int32_t methodId;
723     status_t ret = request.readInt32(&methodId);
724     if (ret != OK) {
725         ALOGE("Failed to retrieve the requested method to invoke");
726         return ret;
727     }
728 
729     switch (methodId) {
730         case INVOKE_ID_SET_VIDEO_SCALING_MODE:
731         {
732             int mode = request.readInt32();
733             return mPlayer->setVideoScalingMode(mode);
734         }
735 
736         case INVOKE_ID_GET_TRACK_INFO:
737         {
738             return mPlayer->getTrackInfo(reply);
739         }
740 
741         case INVOKE_ID_SELECT_TRACK:
742         {
743             int trackIndex = request.readInt32();
744             int msec = 0;
745             // getCurrentPosition should always return OK
746             getCurrentPosition(&msec);
747             return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000LL);
748         }
749 
750         case INVOKE_ID_UNSELECT_TRACK:
751         {
752             int trackIndex = request.readInt32();
753             return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */);
754         }
755 
756         case INVOKE_ID_GET_SELECTED_TRACK:
757         {
758             int32_t type = request.readInt32();
759             return mPlayer->getSelectedTrack(type, reply);
760         }
761 
762         default:
763         {
764             return INVALID_OPERATION;
765         }
766     }
767 }
768 
setAudioSink(const sp<AudioSink> & audioSink)769 void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) {
770     mPlayer->setAudioSink(audioSink);
771     mAudioSink = audioSink;
772 }
773 
setParameter(int,const Parcel &)774 status_t NuPlayerDriver::setParameter(
775         int /* key */, const Parcel & /* request */) {
776     return INVALID_OPERATION;
777 }
778 
getParameter(int key,Parcel * reply)779 status_t NuPlayerDriver::getParameter(int key, Parcel *reply) {
780 
781     if (key == FOURCC('m','t','r','X') && mAnalyticsItem != NULL) {
782         // mtrX -- a play on 'metrics' (not matrix)
783         // gather current info all together, parcel it, and send it back
784         updateMetrics("api");
785         mAnalyticsItem->writeToParcel(reply);
786         return OK;
787     }
788 
789     return INVALID_OPERATION;
790 }
791 
getMetadata(const media::Metadata::Filter &,Parcel * records)792 status_t NuPlayerDriver::getMetadata(
793         const media::Metadata::Filter& /* ids */, Parcel *records) {
794     Mutex::Autolock autoLock(mLock);
795 
796     using media::Metadata;
797 
798     Metadata meta(records);
799 
800     meta.appendBool(
801             Metadata::kPauseAvailable,
802             mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE);
803 
804     meta.appendBool(
805             Metadata::kSeekBackwardAvailable,
806             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD);
807 
808     meta.appendBool(
809             Metadata::kSeekForwardAvailable,
810             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD);
811 
812     meta.appendBool(
813             Metadata::kSeekAvailable,
814             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK);
815 
816     return OK;
817 }
818 
notifyResetComplete()819 void NuPlayerDriver::notifyResetComplete() {
820     ALOGD("notifyResetComplete(%p)", this);
821     Mutex::Autolock autoLock(mLock);
822 
823     CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
824     mState = STATE_IDLE;
825     mCondition.broadcast();
826 }
827 
notifySetSurfaceComplete()828 void NuPlayerDriver::notifySetSurfaceComplete() {
829     ALOGV("notifySetSurfaceComplete(%p)", this);
830     Mutex::Autolock autoLock(mLock);
831 
832     CHECK(mSetSurfaceInProgress);
833     mSetSurfaceInProgress = false;
834 
835     mCondition.broadcast();
836 }
837 
notifyDuration(int64_t durationUs)838 void NuPlayerDriver::notifyDuration(int64_t durationUs) {
839     Mutex::Autolock autoLock(mLock);
840     mDurationUs = durationUs;
841 }
842 
notifyMorePlayingTimeUs(int64_t playingUs)843 void NuPlayerDriver::notifyMorePlayingTimeUs(int64_t playingUs) {
844     Mutex::Autolock autoLock(mLock);
845     mPlayingTimeUs += playingUs;
846 }
847 
notifyMoreRebufferingTimeUs(int64_t rebufferingUs)848 void NuPlayerDriver::notifyMoreRebufferingTimeUs(int64_t rebufferingUs) {
849     Mutex::Autolock autoLock(mLock);
850     mRebufferingTimeUs += rebufferingUs;
851     mRebufferingEvents++;
852 }
853 
notifyRebufferingWhenExit(bool status)854 void NuPlayerDriver::notifyRebufferingWhenExit(bool status) {
855     Mutex::Autolock autoLock(mLock);
856     mRebufferingAtExit = status;
857 }
858 
notifySeekComplete()859 void NuPlayerDriver::notifySeekComplete() {
860     ALOGV("notifySeekComplete(%p)", this);
861     Mutex::Autolock autoLock(mLock);
862     mSeekInProgress = false;
863     notifySeekComplete_l();
864 }
865 
notifySeekComplete_l()866 void NuPlayerDriver::notifySeekComplete_l() {
867     bool wasSeeking = true;
868     if (mState == STATE_STOPPED_AND_PREPARING) {
869         wasSeeking = false;
870         mState = STATE_STOPPED_AND_PREPARED;
871         mCondition.broadcast();
872         if (!mIsAsyncPrepare) {
873             // if we are preparing synchronously, no need to notify listener
874             return;
875         }
876     } else if (mState == STATE_STOPPED) {
877         // no need to notify listener
878         return;
879     }
880     notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
881 }
882 
dump(int fd,const Vector<String16> &) const883 status_t NuPlayerDriver::dump(
884         int fd, const Vector<String16> & /* args */) const {
885 
886     Vector<sp<AMessage> > trackStats;
887     mPlayer->getStats(&trackStats);
888 
889     AString logString(" NuPlayer\n");
890     char buf[256] = {0};
891 
892     bool locked = false;
893     for (int i = 0; i < kDumpLockRetries; ++i) {
894         if (mLock.tryLock() == NO_ERROR) {
895             locked = true;
896             break;
897         }
898         usleep(kDumpLockSleepUs);
899     }
900 
901     if (locked) {
902         snprintf(buf, sizeof(buf), "  state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n",
903                 mState, mAtEOS, mLooping, mAutoLoop);
904         mLock.unlock();
905     } else {
906         snprintf(buf, sizeof(buf), "  NPD(%p) lock is taken\n", this);
907     }
908     logString.append(buf);
909 
910     for (size_t i = 0; i < trackStats.size(); ++i) {
911         const sp<AMessage> &stats = trackStats.itemAt(i);
912 
913         AString mime;
914         if (stats->findString("mime", &mime)) {
915             snprintf(buf, sizeof(buf), "  mime(%s)\n", mime.c_str());
916             logString.append(buf);
917         }
918 
919         AString name;
920         if (stats->findString("component-name", &name)) {
921             snprintf(buf, sizeof(buf), "    decoder(%s)\n", name.c_str());
922             logString.append(buf);
923         }
924 
925         if (mime.startsWith("video/")) {
926             int32_t width, height;
927             if (stats->findInt32("width", &width)
928                     && stats->findInt32("height", &height)) {
929                 snprintf(buf, sizeof(buf), "    resolution(%d x %d)\n", width, height);
930                 logString.append(buf);
931             }
932 
933             int64_t numFramesTotal = 0;
934             int64_t numFramesDropped = 0;
935 
936             stats->findInt64("frames-total", &numFramesTotal);
937             stats->findInt64("frames-dropped-output", &numFramesDropped);
938             snprintf(buf, sizeof(buf), "    numFramesTotal(%lld), numFramesDropped(%lld), "
939                      "percentageDropped(%.2f%%)\n",
940                      (long long)numFramesTotal,
941                      (long long)numFramesDropped,
942                      numFramesTotal == 0
943                             ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
944             logString.append(buf);
945         }
946     }
947 
948     ALOGI("%s", logString.c_str());
949 
950     if (fd >= 0) {
951         FILE *out = fdopen(dup(fd), "w");
952         fprintf(out, "%s", logString.c_str());
953         fclose(out);
954         out = NULL;
955     }
956 
957     return OK;
958 }
959 
notifyListener(int msg,int ext1,int ext2,const Parcel * in)960 void NuPlayerDriver::notifyListener(
961         int msg, int ext1, int ext2, const Parcel *in) {
962     Mutex::Autolock autoLock(mLock);
963     notifyListener_l(msg, ext1, ext2, in);
964 }
965 
notifyListener_l(int msg,int ext1,int ext2,const Parcel * in)966 void NuPlayerDriver::notifyListener_l(
967         int msg, int ext1, int ext2, const Parcel *in) {
968     ALOGV("notifyListener_l(%p), (%d, %d, %d, %d), loop setting(%d, %d)",
969             this, msg, ext1, ext2, (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
970     switch (msg) {
971         case MEDIA_PLAYBACK_COMPLETE:
972         {
973             if (mState != STATE_RESET_IN_PROGRESS) {
974                 if (mAutoLoop) {
975                     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
976                     if (mAudioSink != NULL) {
977                         streamType = mAudioSink->getAudioStreamType();
978                     }
979                     if (streamType == AUDIO_STREAM_NOTIFICATION) {
980                         ALOGW("disabling auto-loop for notification");
981                         mAutoLoop = false;
982                     }
983                 }
984                 if (mLooping || mAutoLoop) {
985                     mPlayer->seekToAsync(0);
986                     if (mAudioSink != NULL) {
987                         // The renderer has stopped the sink at the end in order to play out
988                         // the last little bit of audio. If we're looping, we need to restart it.
989                         mAudioSink->start();
990                     }
991                     // don't send completion event when looping
992                     return;
993                 }
994                 if (property_get_bool("persist.debug.sf.stats", false)) {
995                     Vector<String16> args;
996                     dump(-1, args);
997                 }
998                 mPlayer->pause();
999                 mState = STATE_PAUSED;
1000             }
1001             FALLTHROUGH_INTENDED;
1002         }
1003 
1004         case MEDIA_ERROR:
1005         {
1006             // when we have an error, add it to the analytics for this playback.
1007             // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
1008             // [test against msg is due to fall through from previous switch value]
1009             if (msg == MEDIA_ERROR && mAnalyticsItem != NULL) {
1010                 mAnalyticsItem->setInt32(kPlayerError, ext1);
1011                 if (ext2 != 0) {
1012                     mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
1013                 }
1014                 mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
1015             }
1016             mAtEOS = true;
1017             break;
1018         }
1019 
1020         default:
1021             break;
1022     }
1023 
1024     mLock.unlock();
1025     sendEvent(msg, ext1, ext2, in);
1026     mLock.lock();
1027 }
1028 
notifySetDataSourceCompleted(status_t err)1029 void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
1030     Mutex::Autolock autoLock(mLock);
1031 
1032     CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
1033 
1034     mAsyncResult = err;
1035     mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
1036     mCondition.broadcast();
1037 }
1038 
notifyPrepareCompleted(status_t err)1039 void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
1040     ALOGV("notifyPrepareCompleted %d", err);
1041 
1042     Mutex::Autolock autoLock(mLock);
1043 
1044     if (mState != STATE_PREPARING) {
1045         // We were preparing asynchronously when the client called
1046         // reset(), we sent a premature "prepared" notification and
1047         // then initiated the reset. This notification is stale.
1048         CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
1049         return;
1050     }
1051 
1052     CHECK_EQ(mState, STATE_PREPARING);
1053 
1054     mAsyncResult = err;
1055 
1056     if (err == OK) {
1057         // update state before notifying client, so that if client calls back into NuPlayerDriver
1058         // in response, NuPlayerDriver has the right state
1059         mState = STATE_PREPARED;
1060         if (mIsAsyncPrepare) {
1061             notifyListener_l(MEDIA_PREPARED);
1062         }
1063     } else {
1064         mState = STATE_UNPREPARED;
1065         if (mIsAsyncPrepare) {
1066             notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1067         }
1068     }
1069 
1070     sp<MetaData> meta = mPlayer->getFileMeta();
1071     int32_t loop;
1072     if (meta != NULL
1073             && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
1074         mAutoLoop = true;
1075     }
1076 
1077     mCondition.broadcast();
1078 }
1079 
notifyFlagsChanged(uint32_t flags)1080 void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
1081     Mutex::Autolock autoLock(mLock);
1082 
1083     mPlayerFlags = flags;
1084 }
1085 
1086 // Modular DRM
prepareDrm(const uint8_t uuid[16],const Vector<uint8_t> & drmSessionId)1087 status_t NuPlayerDriver::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
1088 {
1089     ALOGV("prepareDrm(%p) state: %d", this, mState);
1090 
1091     // leaving the state verification for mediaplayer.cpp
1092     status_t ret = mPlayer->prepareDrm(uuid, drmSessionId);
1093 
1094     ALOGV("prepareDrm ret: %d", ret);
1095 
1096     return ret;
1097 }
1098 
releaseDrm()1099 status_t NuPlayerDriver::releaseDrm()
1100 {
1101     ALOGV("releaseDrm(%p) state: %d", this, mState);
1102 
1103     // leaving the state verification for mediaplayer.cpp
1104     status_t ret = mPlayer->releaseDrm();
1105 
1106     ALOGV("releaseDrm ret: %d", ret);
1107 
1108     return ret;
1109 }
1110 
stateString(State state)1111 std::string NuPlayerDriver::stateString(State state) {
1112     const char *rval = NULL;
1113     char rawbuffer[16];  // allows "%d"
1114 
1115     switch (state) {
1116         case STATE_IDLE: rval = "IDLE"; break;
1117         case STATE_SET_DATASOURCE_PENDING: rval = "SET_DATASOURCE_PENDING"; break;
1118         case STATE_UNPREPARED: rval = "UNPREPARED"; break;
1119         case STATE_PREPARING: rval = "PREPARING"; break;
1120         case STATE_PREPARED: rval = "PREPARED"; break;
1121         case STATE_RUNNING: rval = "RUNNING"; break;
1122         case STATE_PAUSED: rval = "PAUSED"; break;
1123         case STATE_RESET_IN_PROGRESS: rval = "RESET_IN_PROGRESS"; break;
1124         case STATE_STOPPED: rval = "STOPPED"; break;
1125         case STATE_STOPPED_AND_PREPARING: rval = "STOPPED_AND_PREPARING"; break;
1126         case STATE_STOPPED_AND_PREPARED: rval = "STOPPED_AND_PREPARED"; break;
1127         default:
1128             // yes, this buffer is shared and vulnerable to races
1129             snprintf(rawbuffer, sizeof(rawbuffer), "%d", state);
1130             rval = rawbuffer;
1131             break;
1132     }
1133 
1134     return rval;
1135 }
1136 
1137 }  // namespace android
1138