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