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