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