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 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 63 NuPlayerDriver::~NuPlayerDriver() { 64 ALOGV("~NuPlayerDriver(%p)", this); 65 mLooper->stop(); 66 } 67 68 status_t NuPlayerDriver::initCheck() { 69 return OK; 70 } 71 72 status_t NuPlayerDriver::setUID(uid_t uid) { 73 mPlayer->setUID(uid); 74 75 return OK; 76 } 77 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 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 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 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 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 186 status_t NuPlayerDriver::prepare() { 187 ALOGV("prepare(%p)", this); 188 Mutex::Autolock autoLock(mLock); 189 return prepare_l(); 190 } 191 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 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 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 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 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 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 349 bool NuPlayerDriver::isPlaying() { 350 return mState == STATE_RUNNING && !mAtEOS; 351 } 352 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 373 status_t NuPlayerDriver::getPlaybackSettings(AudioPlaybackRate *rate) { 374 return mPlayer->getPlaybackSettings(rate); 375 } 376 377 status_t NuPlayerDriver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) { 378 return mPlayer->setSyncSettings(sync, videoFpsHint); 379 } 380 381 status_t NuPlayerDriver::getSyncSettings(AVSyncSettings *sync, float *videoFps) { 382 return mPlayer->getSyncSettings(sync, videoFps); 383 } 384 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 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 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 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 500 status_t NuPlayerDriver::setLooping(int loop) { 501 mLooping = loop != 0; 502 return OK; 503 } 504 505 player_type NuPlayerDriver::playerType() { 506 return NU_PLAYER; 507 } 508 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 562 void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) { 563 mPlayer->setAudioSink(audioSink); 564 mAudioSink = audioSink; 565 } 566 567 status_t NuPlayerDriver::setParameter( 568 int /* key */, const Parcel & /* request */) { 569 return INVALID_OPERATION; 570 } 571 572 status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) { 573 return INVALID_OPERATION; 574 } 575 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 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 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 622 void NuPlayerDriver::notifyDuration(int64_t durationUs) { 623 Mutex::Autolock autoLock(mLock); 624 mDurationUs = durationUs; 625 } 626 627 void NuPlayerDriver::notifySeekComplete() { 628 ALOGV("notifySeekComplete(%p)", this); 629 Mutex::Autolock autoLock(mLock); 630 mSeekInProgress = false; 631 notifySeekComplete_l(); 632 } 633 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 651 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 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 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 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 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 815 void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) { 816 Mutex::Autolock autoLock(mLock); 817 818 mPlayerFlags = flags; 819 } 820 821 } // namespace android 822