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