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