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