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 namespace android {
35 
NuPlayerDriver(pid_t pid)36 NuPlayerDriver::NuPlayerDriver(pid_t pid)
37     : mState(STATE_IDLE),
38       mIsAsyncPrepare(false),
39       mAsyncResult(UNKNOWN_ERROR),
40       mSetSurfaceInProgress(false),
41       mDurationUs(-1),
42       mPositionUs(-1),
43       mSeekInProgress(false),
44       mLooper(new ALooper),
45       mPlayerFlags(0),
46       mAtEOS(false),
47       mLooping(false),
48       mAutoLoop(false),
49       mStartupSeekTimeUs(-1) {
50     ALOGV("NuPlayerDriver(%p)", this);
51     mLooper->setName("NuPlayerDriver Looper");
52 
53     mLooper->start(
54             false, /* runOnCallingThread */
55             true,  /* canCallJava */
56             PRIORITY_AUDIO);
57 
58     mPlayer = new NuPlayer(pid);
59     mLooper->registerHandler(mPlayer);
60 
61     mPlayer->setDriver(this);
62 }
63 
~NuPlayerDriver()64 NuPlayerDriver::~NuPlayerDriver() {
65     ALOGV("~NuPlayerDriver(%p)", this);
66     mLooper->stop();
67 }
68 
initCheck()69 status_t NuPlayerDriver::initCheck() {
70     return OK;
71 }
72 
setUID(uid_t uid)73 status_t NuPlayerDriver::setUID(uid_t uid) {
74     mPlayer->setUID(uid);
75 
76     return OK;
77 }
78 
setDataSource(const sp<IMediaHTTPService> & httpService,const char * url,const KeyedVector<String8,String8> * headers)79 status_t NuPlayerDriver::setDataSource(
80         const sp<IMediaHTTPService> &httpService,
81         const char *url,
82         const KeyedVector<String8, String8> *headers) {
83     ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str());
84     Mutex::Autolock autoLock(mLock);
85 
86     if (mState != STATE_IDLE) {
87         return INVALID_OPERATION;
88     }
89 
90     mState = STATE_SET_DATASOURCE_PENDING;
91 
92     mPlayer->setDataSourceAsync(httpService, url, headers);
93 
94     while (mState == STATE_SET_DATASOURCE_PENDING) {
95         mCondition.wait(mLock);
96     }
97 
98     return mAsyncResult;
99 }
100 
setDataSource(int fd,int64_t offset,int64_t length)101 status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
102     ALOGV("setDataSource(%p) file(%d)", this, fd);
103     Mutex::Autolock autoLock(mLock);
104 
105     if (mState != STATE_IDLE) {
106         return INVALID_OPERATION;
107     }
108 
109     mState = STATE_SET_DATASOURCE_PENDING;
110 
111     mPlayer->setDataSourceAsync(fd, offset, length);
112 
113     while (mState == STATE_SET_DATASOURCE_PENDING) {
114         mCondition.wait(mLock);
115     }
116 
117     return mAsyncResult;
118 }
119 
setDataSource(const sp<IStreamSource> & source)120 status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
121     ALOGV("setDataSource(%p) stream source", this);
122     Mutex::Autolock autoLock(mLock);
123 
124     if (mState != STATE_IDLE) {
125         return INVALID_OPERATION;
126     }
127 
128     mState = STATE_SET_DATASOURCE_PENDING;
129 
130     mPlayer->setDataSourceAsync(source);
131 
132     while (mState == STATE_SET_DATASOURCE_PENDING) {
133         mCondition.wait(mLock);
134     }
135 
136     return mAsyncResult;
137 }
138 
setDataSource(const sp<DataSource> & source)139 status_t NuPlayerDriver::setDataSource(const sp<DataSource> &source) {
140     ALOGV("setDataSource(%p) callback source", this);
141     Mutex::Autolock autoLock(mLock);
142 
143     if (mState != STATE_IDLE) {
144         return INVALID_OPERATION;
145     }
146 
147     mState = STATE_SET_DATASOURCE_PENDING;
148 
149     mPlayer->setDataSourceAsync(source);
150 
151     while (mState == STATE_SET_DATASOURCE_PENDING) {
152         mCondition.wait(mLock);
153     }
154 
155     return mAsyncResult;
156 }
157 
setVideoSurfaceTexture(const sp<IGraphicBufferProducer> & bufferProducer)158 status_t NuPlayerDriver::setVideoSurfaceTexture(
159         const sp<IGraphicBufferProducer> &bufferProducer) {
160     ALOGV("setVideoSurfaceTexture(%p)", this);
161     Mutex::Autolock autoLock(mLock);
162 
163     if (mSetSurfaceInProgress) {
164         return INVALID_OPERATION;
165     }
166 
167     switch (mState) {
168         case STATE_SET_DATASOURCE_PENDING:
169         case STATE_RESET_IN_PROGRESS:
170             return INVALID_OPERATION;
171 
172         default:
173             break;
174     }
175 
176     mSetSurfaceInProgress = true;
177 
178     mPlayer->setVideoSurfaceTextureAsync(bufferProducer);
179 
180     while (mSetSurfaceInProgress) {
181         mCondition.wait(mLock);
182     }
183 
184     return OK;
185 }
186 
prepare()187 status_t NuPlayerDriver::prepare() {
188     ALOGV("prepare(%p)", this);
189     Mutex::Autolock autoLock(mLock);
190     return prepare_l();
191 }
192 
prepare_l()193 status_t NuPlayerDriver::prepare_l() {
194     switch (mState) {
195         case STATE_UNPREPARED:
196             mState = STATE_PREPARING;
197 
198             // Make sure we're not posting any notifications, success or
199             // failure information is only communicated through our result
200             // code.
201             mIsAsyncPrepare = false;
202             mPlayer->prepareAsync();
203             while (mState == STATE_PREPARING) {
204                 mCondition.wait(mLock);
205             }
206             return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
207         case STATE_STOPPED:
208             // this is really just paused. handle as seek to start
209             mAtEOS = false;
210             mState = STATE_STOPPED_AND_PREPARING;
211             mIsAsyncPrepare = false;
212             mPlayer->seekToAsync(0, true /* needNotify */);
213             while (mState == STATE_STOPPED_AND_PREPARING) {
214                 mCondition.wait(mLock);
215             }
216             return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
217         default:
218             return INVALID_OPERATION;
219     };
220 }
221 
prepareAsync()222 status_t NuPlayerDriver::prepareAsync() {
223     ALOGV("prepareAsync(%p)", this);
224     Mutex::Autolock autoLock(mLock);
225 
226     switch (mState) {
227         case STATE_UNPREPARED:
228             mState = STATE_PREPARING;
229             mIsAsyncPrepare = true;
230             mPlayer->prepareAsync();
231             return OK;
232         case STATE_STOPPED:
233             // this is really just paused. handle as seek to start
234             mAtEOS = false;
235             mState = STATE_STOPPED_AND_PREPARING;
236             mIsAsyncPrepare = true;
237             mPlayer->seekToAsync(0, true /* needNotify */);
238             return OK;
239         default:
240             return INVALID_OPERATION;
241     };
242 }
243 
start()244 status_t NuPlayerDriver::start() {
245     ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
246     Mutex::Autolock autoLock(mLock);
247 
248     switch (mState) {
249         case STATE_UNPREPARED:
250         {
251             status_t err = prepare_l();
252 
253             if (err != OK) {
254                 return err;
255             }
256 
257             CHECK_EQ(mState, STATE_PREPARED);
258 
259             // fall through
260         }
261 
262         case STATE_PAUSED:
263         case STATE_STOPPED_AND_PREPARED:
264         {
265             if (mAtEOS && mStartupSeekTimeUs < 0) {
266                 mStartupSeekTimeUs = 0;
267                 mPositionUs = -1;
268             }
269 
270             // fall through
271         }
272 
273         case STATE_PREPARED:
274         {
275             mAtEOS = false;
276             mPlayer->start();
277 
278             if (mStartupSeekTimeUs >= 0) {
279                 mPlayer->seekToAsync(mStartupSeekTimeUs);
280                 mStartupSeekTimeUs = -1;
281             }
282             break;
283         }
284 
285         case STATE_RUNNING:
286         {
287             if (mAtEOS) {
288                 mPlayer->seekToAsync(0);
289                 mAtEOS = false;
290                 mPositionUs = -1;
291             }
292             break;
293         }
294 
295         default:
296             return INVALID_OPERATION;
297     }
298 
299     mState = STATE_RUNNING;
300 
301     return OK;
302 }
303 
stop()304 status_t NuPlayerDriver::stop() {
305     ALOGD("stop(%p)", this);
306     Mutex::Autolock autoLock(mLock);
307 
308     switch (mState) {
309         case STATE_RUNNING:
310             mPlayer->pause();
311             // fall through
312 
313         case STATE_PAUSED:
314             mState = STATE_STOPPED;
315             notifyListener_l(MEDIA_STOPPED);
316             break;
317 
318         case STATE_PREPARED:
319         case STATE_STOPPED:
320         case STATE_STOPPED_AND_PREPARING:
321         case STATE_STOPPED_AND_PREPARED:
322             mState = STATE_STOPPED;
323             break;
324 
325         default:
326             return INVALID_OPERATION;
327     }
328 
329     return OK;
330 }
331 
pause()332 status_t NuPlayerDriver::pause() {
333     // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
334     // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
335     // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
336     // getCurrentPosition here.
337     int msec;
338     getCurrentPosition(&msec);
339 
340     Mutex::Autolock autoLock(mLock);
341 
342     switch (mState) {
343         case STATE_PAUSED:
344         case STATE_PREPARED:
345             return OK;
346 
347         case STATE_RUNNING:
348             mState = STATE_PAUSED;
349             notifyListener_l(MEDIA_PAUSED);
350             mPlayer->pause();
351             break;
352 
353         default:
354             return INVALID_OPERATION;
355     }
356 
357     return OK;
358 }
359 
isPlaying()360 bool NuPlayerDriver::isPlaying() {
361     return mState == STATE_RUNNING && !mAtEOS;
362 }
363 
setPlaybackSettings(const AudioPlaybackRate & rate)364 status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) {
365     Mutex::Autolock autoLock(mLock);
366     status_t err = mPlayer->setPlaybackSettings(rate);
367     if (err == OK) {
368         if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
369             mState = STATE_PAUSED;
370             // try to update position
371             (void)mPlayer->getCurrentPosition(&mPositionUs);
372             notifyListener_l(MEDIA_PAUSED);
373         } else if (rate.mSpeed != 0.f && mState == STATE_PAUSED) {
374             mState = STATE_RUNNING;
375         }
376     }
377     return err;
378 }
379 
getPlaybackSettings(AudioPlaybackRate * rate)380 status_t NuPlayerDriver::getPlaybackSettings(AudioPlaybackRate *rate) {
381     return mPlayer->getPlaybackSettings(rate);
382 }
383 
setSyncSettings(const AVSyncSettings & sync,float videoFpsHint)384 status_t NuPlayerDriver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
385     return mPlayer->setSyncSettings(sync, videoFpsHint);
386 }
387 
getSyncSettings(AVSyncSettings * sync,float * videoFps)388 status_t NuPlayerDriver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
389     return mPlayer->getSyncSettings(sync, videoFps);
390 }
391 
seekTo(int msec)392 status_t NuPlayerDriver::seekTo(int msec) {
393     ALOGD("seekTo(%p) %d ms", this, msec);
394     Mutex::Autolock autoLock(mLock);
395 
396     int64_t seekTimeUs = msec * 1000ll;
397 
398     switch (mState) {
399         case STATE_PREPARED:
400         case STATE_STOPPED_AND_PREPARED:
401         case STATE_PAUSED:
402             mStartupSeekTimeUs = seekTimeUs;
403             // fall through.
404         case STATE_RUNNING:
405         {
406             mAtEOS = false;
407             mSeekInProgress = true;
408             // seeks can take a while, so we essentially paused
409             notifyListener_l(MEDIA_PAUSED);
410             mPlayer->seekToAsync(seekTimeUs, true /* needNotify */);
411             break;
412         }
413 
414         default:
415             return INVALID_OPERATION;
416     }
417 
418     mPositionUs = seekTimeUs;
419     return OK;
420 }
421 
getCurrentPosition(int * msec)422 status_t NuPlayerDriver::getCurrentPosition(int *msec) {
423     int64_t tempUs = 0;
424     {
425         Mutex::Autolock autoLock(mLock);
426         if (mSeekInProgress || mState == STATE_PAUSED) {
427             tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
428             *msec = (int)divRound(tempUs, (int64_t)(1000));
429             return OK;
430         }
431     }
432 
433     status_t ret = mPlayer->getCurrentPosition(&tempUs);
434 
435     Mutex::Autolock autoLock(mLock);
436     // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
437     // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
438     // position value that's different the seek to position.
439     if (ret != OK) {
440         tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
441     } else {
442         mPositionUs = tempUs;
443     }
444     *msec = (int)divRound(tempUs, (int64_t)(1000));
445     return OK;
446 }
447 
getDuration(int * msec)448 status_t NuPlayerDriver::getDuration(int *msec) {
449     Mutex::Autolock autoLock(mLock);
450 
451     if (mDurationUs < 0) {
452         return UNKNOWN_ERROR;
453     }
454 
455     *msec = (mDurationUs + 500ll) / 1000;
456 
457     return OK;
458 }
459 
reset()460 status_t NuPlayerDriver::reset() {
461     ALOGD("reset(%p)", this);
462     Mutex::Autolock autoLock(mLock);
463 
464     switch (mState) {
465         case STATE_IDLE:
466             return OK;
467 
468         case STATE_SET_DATASOURCE_PENDING:
469         case STATE_RESET_IN_PROGRESS:
470             return INVALID_OPERATION;
471 
472         case STATE_PREPARING:
473         {
474             CHECK(mIsAsyncPrepare);
475 
476             notifyListener_l(MEDIA_PREPARED);
477             break;
478         }
479 
480         default:
481             break;
482     }
483 
484     if (mState != STATE_STOPPED) {
485         notifyListener_l(MEDIA_STOPPED);
486     }
487 
488     char value[PROPERTY_VALUE_MAX];
489     if (property_get("persist.debug.sf.stats", value, NULL) &&
490             (!strcmp("1", value) || !strcasecmp("true", value))) {
491         Vector<String16> args;
492         dump(-1, args);
493     }
494 
495     mState = STATE_RESET_IN_PROGRESS;
496     mPlayer->resetAsync();
497 
498     while (mState == STATE_RESET_IN_PROGRESS) {
499         mCondition.wait(mLock);
500     }
501 
502     mDurationUs = -1;
503     mPositionUs = -1;
504     mStartupSeekTimeUs = -1;
505     mLooping = false;
506 
507     return OK;
508 }
509 
setLooping(int loop)510 status_t NuPlayerDriver::setLooping(int loop) {
511     mLooping = loop != 0;
512     return OK;
513 }
514 
playerType()515 player_type NuPlayerDriver::playerType() {
516     return NU_PLAYER;
517 }
518 
invoke(const Parcel & request,Parcel * reply)519 status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
520     if (reply == NULL) {
521         ALOGE("reply is a NULL pointer");
522         return BAD_VALUE;
523     }
524 
525     int32_t methodId;
526     status_t ret = request.readInt32(&methodId);
527     if (ret != OK) {
528         ALOGE("Failed to retrieve the requested method to invoke");
529         return ret;
530     }
531 
532     switch (methodId) {
533         case INVOKE_ID_SET_VIDEO_SCALING_MODE:
534         {
535             int mode = request.readInt32();
536             return mPlayer->setVideoScalingMode(mode);
537         }
538 
539         case INVOKE_ID_GET_TRACK_INFO:
540         {
541             return mPlayer->getTrackInfo(reply);
542         }
543 
544         case INVOKE_ID_SELECT_TRACK:
545         {
546             int trackIndex = request.readInt32();
547             int msec = 0;
548             // getCurrentPosition should always return OK
549             getCurrentPosition(&msec);
550             return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000ll);
551         }
552 
553         case INVOKE_ID_UNSELECT_TRACK:
554         {
555             int trackIndex = request.readInt32();
556             return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */);
557         }
558 
559         case INVOKE_ID_GET_SELECTED_TRACK:
560         {
561             int32_t type = request.readInt32();
562             return mPlayer->getSelectedTrack(type, reply);
563         }
564 
565         default:
566         {
567             return INVALID_OPERATION;
568         }
569     }
570 }
571 
setAudioSink(const sp<AudioSink> & audioSink)572 void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) {
573     mPlayer->setAudioSink(audioSink);
574     mAudioSink = audioSink;
575 }
576 
setParameter(int,const Parcel &)577 status_t NuPlayerDriver::setParameter(
578         int /* key */, const Parcel & /* request */) {
579     return INVALID_OPERATION;
580 }
581 
getParameter(int,Parcel *)582 status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) {
583     return INVALID_OPERATION;
584 }
585 
getMetadata(const media::Metadata::Filter &,Parcel * records)586 status_t NuPlayerDriver::getMetadata(
587         const media::Metadata::Filter& /* ids */, Parcel *records) {
588     Mutex::Autolock autoLock(mLock);
589 
590     using media::Metadata;
591 
592     Metadata meta(records);
593 
594     meta.appendBool(
595             Metadata::kPauseAvailable,
596             mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE);
597 
598     meta.appendBool(
599             Metadata::kSeekBackwardAvailable,
600             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD);
601 
602     meta.appendBool(
603             Metadata::kSeekForwardAvailable,
604             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD);
605 
606     meta.appendBool(
607             Metadata::kSeekAvailable,
608             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK);
609 
610     return OK;
611 }
612 
notifyResetComplete()613 void NuPlayerDriver::notifyResetComplete() {
614     ALOGD("notifyResetComplete(%p)", this);
615     Mutex::Autolock autoLock(mLock);
616 
617     CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
618     mState = STATE_IDLE;
619     mCondition.broadcast();
620 }
621 
notifySetSurfaceComplete()622 void NuPlayerDriver::notifySetSurfaceComplete() {
623     ALOGV("notifySetSurfaceComplete(%p)", this);
624     Mutex::Autolock autoLock(mLock);
625 
626     CHECK(mSetSurfaceInProgress);
627     mSetSurfaceInProgress = false;
628 
629     mCondition.broadcast();
630 }
631 
notifyDuration(int64_t durationUs)632 void NuPlayerDriver::notifyDuration(int64_t durationUs) {
633     Mutex::Autolock autoLock(mLock);
634     mDurationUs = durationUs;
635 }
636 
notifySeekComplete()637 void NuPlayerDriver::notifySeekComplete() {
638     ALOGV("notifySeekComplete(%p)", this);
639     Mutex::Autolock autoLock(mLock);
640     mSeekInProgress = false;
641     notifySeekComplete_l();
642 }
643 
notifySeekComplete_l()644 void NuPlayerDriver::notifySeekComplete_l() {
645     bool wasSeeking = true;
646     if (mState == STATE_STOPPED_AND_PREPARING) {
647         wasSeeking = false;
648         mState = STATE_STOPPED_AND_PREPARED;
649         mCondition.broadcast();
650         if (!mIsAsyncPrepare) {
651             // if we are preparing synchronously, no need to notify listener
652             return;
653         }
654     } else if (mState == STATE_STOPPED) {
655         // no need to notify listener
656         return;
657     }
658     notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
659 }
660 
dump(int fd,const Vector<String16> &) const661 status_t NuPlayerDriver::dump(
662         int fd, const Vector<String16> & /* args */) const {
663 
664     Vector<sp<AMessage> > trackStats;
665     mPlayer->getStats(&trackStats);
666 
667     AString logString(" NuPlayer\n");
668     char buf[256] = {0};
669 
670     for (size_t i = 0; i < trackStats.size(); ++i) {
671         const sp<AMessage> &stats = trackStats.itemAt(i);
672 
673         AString mime;
674         if (stats->findString("mime", &mime)) {
675             snprintf(buf, sizeof(buf), "  mime(%s)\n", mime.c_str());
676             logString.append(buf);
677         }
678 
679         AString name;
680         if (stats->findString("component-name", &name)) {
681             snprintf(buf, sizeof(buf), "    decoder(%s)\n", name.c_str());
682             logString.append(buf);
683         }
684 
685         if (mime.startsWith("video/")) {
686             int32_t width, height;
687             if (stats->findInt32("width", &width)
688                     && stats->findInt32("height", &height)) {
689                 snprintf(buf, sizeof(buf), "    resolution(%d x %d)\n", width, height);
690                 logString.append(buf);
691             }
692 
693             int64_t numFramesTotal = 0;
694             int64_t numFramesDropped = 0;
695 
696             stats->findInt64("frames-total", &numFramesTotal);
697             stats->findInt64("frames-dropped-output", &numFramesDropped);
698             snprintf(buf, sizeof(buf), "    numFramesTotal(%lld), numFramesDropped(%lld), "
699                      "percentageDropped(%.2f%%)\n",
700                      (long long)numFramesTotal,
701                      (long long)numFramesDropped,
702                      numFramesTotal == 0
703                             ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
704             logString.append(buf);
705         }
706     }
707 
708     ALOGI("%s", logString.c_str());
709 
710     if (fd >= 0) {
711         FILE *out = fdopen(dup(fd), "w");
712         fprintf(out, "%s", logString.c_str());
713         fclose(out);
714         out = NULL;
715     }
716 
717     return OK;
718 }
719 
notifyListener(int msg,int ext1,int ext2,const Parcel * in)720 void NuPlayerDriver::notifyListener(
721         int msg, int ext1, int ext2, const Parcel *in) {
722     Mutex::Autolock autoLock(mLock);
723     notifyListener_l(msg, ext1, ext2, in);
724 }
725 
notifyListener_l(int msg,int ext1,int ext2,const Parcel * in)726 void NuPlayerDriver::notifyListener_l(
727         int msg, int ext1, int ext2, const Parcel *in) {
728     ALOGD("notifyListener_l(%p), (%d, %d, %d)", this, msg, ext1, ext2);
729     switch (msg) {
730         case MEDIA_PLAYBACK_COMPLETE:
731         {
732             if (mState != STATE_RESET_IN_PROGRESS) {
733                 if (mAutoLoop) {
734                     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
735                     if (mAudioSink != NULL) {
736                         streamType = mAudioSink->getAudioStreamType();
737                     }
738                     if (streamType == AUDIO_STREAM_NOTIFICATION) {
739                         ALOGW("disabling auto-loop for notification");
740                         mAutoLoop = false;
741                     }
742                 }
743                 if (mLooping || mAutoLoop) {
744                     mPlayer->seekToAsync(0);
745                     if (mAudioSink != NULL) {
746                         // The renderer has stopped the sink at the end in order to play out
747                         // the last little bit of audio. If we're looping, we need to restart it.
748                         mAudioSink->start();
749                     }
750                     break;
751                 }
752 
753                 mPlayer->pause();
754                 mState = STATE_PAUSED;
755             }
756             // fall through
757         }
758 
759         case MEDIA_ERROR:
760         {
761             mAtEOS = true;
762             break;
763         }
764 
765         default:
766             break;
767     }
768 
769     mLock.unlock();
770     sendEvent(msg, ext1, ext2, in);
771     mLock.lock();
772 }
773 
notifySetDataSourceCompleted(status_t err)774 void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
775     Mutex::Autolock autoLock(mLock);
776 
777     CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
778 
779     mAsyncResult = err;
780     mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
781     mCondition.broadcast();
782 }
783 
notifyPrepareCompleted(status_t err)784 void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
785     Mutex::Autolock autoLock(mLock);
786 
787     if (mState != STATE_PREPARING) {
788         // We were preparing asynchronously when the client called
789         // reset(), we sent a premature "prepared" notification and
790         // then initiated the reset. This notification is stale.
791         CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
792         return;
793     }
794 
795     CHECK_EQ(mState, STATE_PREPARING);
796 
797     mAsyncResult = err;
798 
799     if (err == OK) {
800         // update state before notifying client, so that if client calls back into NuPlayerDriver
801         // in response, NuPlayerDriver has the right state
802         mState = STATE_PREPARED;
803         if (mIsAsyncPrepare) {
804             notifyListener_l(MEDIA_PREPARED);
805         }
806     } else {
807         mState = STATE_UNPREPARED;
808         if (mIsAsyncPrepare) {
809             notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
810         }
811     }
812 
813     sp<MetaData> meta = mPlayer->getFileMeta();
814     int32_t loop;
815     if (meta != NULL
816             && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
817         mAutoLoop = true;
818     }
819 
820     mCondition.broadcast();
821 }
822 
notifyFlagsChanged(uint32_t flags)823 void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
824     Mutex::Autolock autoLock(mLock);
825 
826     mPlayerFlags = flags;
827 }
828 
829 }  // namespace android
830