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