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