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