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