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