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