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