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