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