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