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