NuPlayerDriver.cpp revision 3e15aea623a4c7a21719e4a947e72ff5c23494f6
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 22#include "NuPlayerDriver.h" 23 24#include "NuPlayer.h" 25#include "NuPlayerSource.h" 26 27#include <media/stagefright/foundation/ADebug.h> 28#include <media/stagefright/foundation/ALooper.h> 29#include <media/stagefright/MetaData.h> 30#include <media/stagefright/Utils.h> 31 32namespace android { 33 34NuPlayerDriver::NuPlayerDriver() 35 : mState(STATE_IDLE), 36 mIsAsyncPrepare(false), 37 mAsyncResult(UNKNOWN_ERROR), 38 mSetSurfaceInProgress(false), 39 mDurationUs(-1), 40 mPositionUs(-1), 41 mNotifyTimeRealUs(-1), 42 mPauseStartedTimeUs(-1), 43 mNumFramesTotal(0), 44 mNumFramesDropped(0), 45 mLooper(new ALooper), 46 mPlayerFlags(0), 47 mAtEOS(false), 48 mLooping(false), 49 mAutoLoop(false), 50 mStartupSeekTimeUs(-1) { 51 ALOGV("NuPlayerDriver(%p)", this); 52 mLooper->setName("NuPlayerDriver Looper"); 53 54 mLooper->start( 55 false, /* runOnCallingThread */ 56 true, /* canCallJava */ 57 PRIORITY_AUDIO); 58 59 mPlayer = new NuPlayer; 60 mLooper->registerHandler(mPlayer); 61 62 mPlayer->setDriver(this); 63} 64 65NuPlayerDriver::~NuPlayerDriver() { 66 ALOGV("~NuPlayerDriver(%p)", this); 67 mLooper->stop(); 68} 69 70status_t NuPlayerDriver::initCheck() { 71 return OK; 72} 73 74status_t NuPlayerDriver::setUID(uid_t uid) { 75 mPlayer->setUID(uid); 76 77 return OK; 78} 79 80status_t NuPlayerDriver::setDataSource( 81 const sp<IMediaHTTPService> &httpService, 82 const char *url, 83 const KeyedVector<String8, String8> *headers) { 84 ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str()); 85 Mutex::Autolock autoLock(mLock); 86 87 if (mState != STATE_IDLE) { 88 return INVALID_OPERATION; 89 } 90 91 mState = STATE_SET_DATASOURCE_PENDING; 92 93 mPlayer->setDataSourceAsync(httpService, url, headers); 94 95 while (mState == STATE_SET_DATASOURCE_PENDING) { 96 mCondition.wait(mLock); 97 } 98 99 return mAsyncResult; 100} 101 102status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) { 103 ALOGV("setDataSource(%p) file(%d)", this, fd); 104 Mutex::Autolock autoLock(mLock); 105 106 if (mState != STATE_IDLE) { 107 return INVALID_OPERATION; 108 } 109 110 mState = STATE_SET_DATASOURCE_PENDING; 111 112 mPlayer->setDataSourceAsync(fd, offset, length); 113 114 while (mState == STATE_SET_DATASOURCE_PENDING) { 115 mCondition.wait(mLock); 116 } 117 118 return mAsyncResult; 119} 120 121status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) { 122 ALOGV("setDataSource(%p) stream source", this); 123 Mutex::Autolock autoLock(mLock); 124 125 if (mState != STATE_IDLE) { 126 return INVALID_OPERATION; 127 } 128 129 mState = STATE_SET_DATASOURCE_PENDING; 130 131 mPlayer->setDataSourceAsync(source); 132 133 while (mState == STATE_SET_DATASOURCE_PENDING) { 134 mCondition.wait(mLock); 135 } 136 137 return mAsyncResult; 138} 139 140status_t NuPlayerDriver::setVideoSurfaceTexture( 141 const sp<IGraphicBufferProducer> &bufferProducer) { 142 ALOGV("setVideoSurfaceTexture(%p)", this); 143 Mutex::Autolock autoLock(mLock); 144 145 if (mSetSurfaceInProgress) { 146 return INVALID_OPERATION; 147 } 148 149 switch (mState) { 150 case STATE_SET_DATASOURCE_PENDING: 151 case STATE_RESET_IN_PROGRESS: 152 return INVALID_OPERATION; 153 154 default: 155 break; 156 } 157 158 mSetSurfaceInProgress = true; 159 160 mPlayer->setVideoSurfaceTextureAsync(bufferProducer); 161 162 while (mSetSurfaceInProgress) { 163 mCondition.wait(mLock); 164 } 165 166 return OK; 167} 168 169status_t NuPlayerDriver::prepare() { 170 ALOGV("prepare(%p)", this); 171 Mutex::Autolock autoLock(mLock); 172 return prepare_l(); 173} 174 175status_t NuPlayerDriver::prepare_l() { 176 switch (mState) { 177 case STATE_UNPREPARED: 178 mState = STATE_PREPARING; 179 180 // Make sure we're not posting any notifications, success or 181 // failure information is only communicated through our result 182 // code. 183 mIsAsyncPrepare = false; 184 mPlayer->prepareAsync(); 185 while (mState == STATE_PREPARING) { 186 mCondition.wait(mLock); 187 } 188 return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR; 189 case STATE_STOPPED: 190 // this is really just paused. handle as seek to start 191 mAtEOS = false; 192 mState = STATE_STOPPED_AND_PREPARING; 193 mIsAsyncPrepare = false; 194 mPlayer->seekToAsync(0); 195 while (mState == STATE_STOPPED_AND_PREPARING) { 196 mCondition.wait(mLock); 197 } 198 return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR; 199 default: 200 return INVALID_OPERATION; 201 }; 202} 203 204status_t NuPlayerDriver::prepareAsync() { 205 ALOGV("prepareAsync(%p)", this); 206 Mutex::Autolock autoLock(mLock); 207 208 switch (mState) { 209 case STATE_UNPREPARED: 210 mState = STATE_PREPARING; 211 mIsAsyncPrepare = true; 212 mPlayer->prepareAsync(); 213 return OK; 214 case STATE_STOPPED: 215 // this is really just paused. handle as seek to start 216 mAtEOS = false; 217 mState = STATE_STOPPED_AND_PREPARING; 218 mIsAsyncPrepare = true; 219 mPlayer->seekToAsync(0); 220 return OK; 221 default: 222 return INVALID_OPERATION; 223 }; 224} 225 226status_t NuPlayerDriver::start() { 227 ALOGD("start(%p)", this); 228 Mutex::Autolock autoLock(mLock); 229 230 switch (mState) { 231 case STATE_UNPREPARED: 232 { 233 status_t err = prepare_l(); 234 235 if (err != OK) { 236 return err; 237 } 238 239 CHECK_EQ(mState, STATE_PREPARED); 240 241 // fall through 242 } 243 244 case STATE_PREPARED: 245 { 246 mAtEOS = false; 247 mPlayer->start(); 248 249 if (mStartupSeekTimeUs >= 0) { 250 if (mStartupSeekTimeUs > 0) { 251 mPlayer->seekToAsync(mStartupSeekTimeUs); 252 } 253 254 mStartupSeekTimeUs = -1; 255 } 256 break; 257 } 258 259 case STATE_RUNNING: 260 { 261 if (mAtEOS) { 262 mPlayer->seekToAsync(0); 263 mAtEOS = false; 264 mPositionUs = -1; 265 } 266 break; 267 } 268 269 case STATE_PAUSED: 270 case STATE_STOPPED_AND_PREPARED: 271 { 272 if (mAtEOS) { 273 mPlayer->seekToAsync(0); 274 mAtEOS = false; 275 mPlayer->resume(); 276 mPositionUs = -1; 277 } else { 278 mPlayer->resume(); 279 if (mNotifyTimeRealUs != -1) { 280 // Pause time must be set if here by setPauseStartedTimeIfNeeded(). 281 //CHECK(mPauseStartedTimeUs != -1); 282 283 // if no seek occurs, adjust our notify time so that getCurrentPosition() 284 // is continuous if read immediately after calling start(). 285 mNotifyTimeRealUs += ALooper::GetNowUs() - mPauseStartedTimeUs; 286 } 287 } 288 break; 289 } 290 291 default: 292 return INVALID_OPERATION; 293 } 294 295 mState = STATE_RUNNING; 296 mPauseStartedTimeUs = -1; 297 298 return OK; 299} 300 301status_t NuPlayerDriver::stop() { 302 ALOGD("stop(%p)", this); 303 Mutex::Autolock autoLock(mLock); 304 305 switch (mState) { 306 case STATE_RUNNING: 307 mPlayer->pause(); 308 // fall through 309 310 case STATE_PAUSED: 311 mState = STATE_STOPPED; 312 notifyListener_l(MEDIA_STOPPED); 313 break; 314 315 case STATE_PREPARED: 316 case STATE_STOPPED: 317 case STATE_STOPPED_AND_PREPARING: 318 case STATE_STOPPED_AND_PREPARED: 319 mState = STATE_STOPPED; 320 break; 321 322 default: 323 return INVALID_OPERATION; 324 } 325 setPauseStartedTimeIfNeeded(); 326 327 return OK; 328} 329 330status_t NuPlayerDriver::pause() { 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 setPauseStartedTimeIfNeeded(); 340 mState = STATE_PAUSED; 341 notifyListener_l(MEDIA_PAUSED); 342 mPlayer->pause(); 343 break; 344 345 default: 346 return INVALID_OPERATION; 347 } 348 349 return OK; 350} 351 352bool NuPlayerDriver::isPlaying() { 353 return mState == STATE_RUNNING && !mAtEOS; 354} 355 356status_t NuPlayerDriver::seekTo(int msec) { 357 ALOGD("seekTo(%p) %d ms", this, msec); 358 Mutex::Autolock autoLock(mLock); 359 360 int64_t seekTimeUs = msec * 1000ll; 361 362 switch (mState) { 363 case STATE_PREPARED: 364 { 365 mStartupSeekTimeUs = seekTimeUs; 366 // pretend that the seek completed. It will actually happen when starting playback. 367 // TODO: actually perform the seek here, so the player is ready to go at the new 368 // location 369 notifySeekComplete_l(); 370 break; 371 } 372 373 case STATE_RUNNING: 374 case STATE_PAUSED: 375 { 376 mAtEOS = false; 377 // seeks can take a while, so we essentially paused 378 notifyListener_l(MEDIA_PAUSED); 379 mPlayer->seekToAsync(seekTimeUs, true /* needNotify */); 380 break; 381 } 382 383 default: 384 return INVALID_OPERATION; 385 } 386 387 mPositionUs = seekTimeUs; 388 mNotifyTimeRealUs = -1; 389 return OK; 390} 391 392status_t NuPlayerDriver::getCurrentPosition(int *msec) { 393 Mutex::Autolock autoLock(mLock); 394 395 if (mPositionUs < 0) { 396 // mPositionUs is the media time. 397 // It is negative under these cases 398 // (1) == -1 after reset, or very first playback, no stream notification yet. 399 // (2) == -1 start after end of stream, no stream notification yet. 400 // (3) == large negative # after ~292,471 years of continuous playback. 401 402 //CHECK_EQ(mPositionUs, -1); 403 *msec = 0; 404 } else if (mNotifyTimeRealUs == -1) { 405 // A seek has occurred just occurred, no stream notification yet. 406 // mPositionUs (>= 0) is the new media position. 407 *msec = mPositionUs / 1000; 408 } else { 409 // mPosition must be valid (i.e. >= 0) by the first check above. 410 // We're either playing or have pause time set: mPauseStartedTimeUs is >= 0 411 //LOG_ALWAYS_FATAL_IF( 412 // !isPlaying() && mPauseStartedTimeUs < 0, 413 // "Player in non-playing mState(%d) and mPauseStartedTimeUs(%lld) < 0", 414 // mState, (long long)mPauseStartedTimeUs); 415 ALOG_ASSERT(mNotifyTimeRealUs >= 0); 416 int64_t nowUs = 417 (isPlaying() ? ALooper::GetNowUs() : mPauseStartedTimeUs); 418 *msec = (mPositionUs + nowUs - mNotifyTimeRealUs + 500ll) / 1000; 419 // It is possible for *msec to be negative if the media position is > 596 hours. 420 // but we turn on this checking in NDEBUG == 0 mode. 421 ALOG_ASSERT(*msec >= 0); 422 ALOGV("getCurrentPosition nowUs(%lld)", (long long)nowUs); 423 } 424 ALOGV("getCurrentPosition returning(%d) mPositionUs(%lld) mNotifyRealTimeUs(%lld)", 425 *msec, (long long)mPositionUs, (long long)mNotifyTimeRealUs); 426 return OK; 427} 428 429status_t NuPlayerDriver::getDuration(int *msec) { 430 Mutex::Autolock autoLock(mLock); 431 432 if (mDurationUs < 0) { 433 return UNKNOWN_ERROR; 434 } 435 436 *msec = (mDurationUs + 500ll) / 1000; 437 438 return OK; 439} 440 441status_t NuPlayerDriver::reset() { 442 ALOGD("reset(%p)", this); 443 Mutex::Autolock autoLock(mLock); 444 445 switch (mState) { 446 case STATE_IDLE: 447 return OK; 448 449 case STATE_SET_DATASOURCE_PENDING: 450 case STATE_RESET_IN_PROGRESS: 451 return INVALID_OPERATION; 452 453 case STATE_PREPARING: 454 { 455 CHECK(mIsAsyncPrepare); 456 457 notifyListener_l(MEDIA_PREPARED); 458 break; 459 } 460 461 default: 462 break; 463 } 464 465 if (mState != STATE_STOPPED) { 466 notifyListener_l(MEDIA_STOPPED); 467 } 468 469 mState = STATE_RESET_IN_PROGRESS; 470 mPlayer->resetAsync(); 471 472 while (mState == STATE_RESET_IN_PROGRESS) { 473 mCondition.wait(mLock); 474 } 475 476 mDurationUs = -1; 477 mPositionUs = -1; 478 mStartupSeekTimeUs = -1; 479 mLooping = false; 480 481 return OK; 482} 483 484status_t NuPlayerDriver::setLooping(int loop) { 485 mLooping = loop != 0; 486 return OK; 487} 488 489player_type NuPlayerDriver::playerType() { 490 return NU_PLAYER; 491} 492 493status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) { 494 if (reply == NULL) { 495 ALOGE("reply is a NULL pointer"); 496 return BAD_VALUE; 497 } 498 499 int32_t methodId; 500 status_t ret = request.readInt32(&methodId); 501 if (ret != OK) { 502 ALOGE("Failed to retrieve the requested method to invoke"); 503 return ret; 504 } 505 506 switch (methodId) { 507 case INVOKE_ID_SET_VIDEO_SCALING_MODE: 508 { 509 int mode = request.readInt32(); 510 return mPlayer->setVideoScalingMode(mode); 511 } 512 513 case INVOKE_ID_GET_TRACK_INFO: 514 { 515 return mPlayer->getTrackInfo(reply); 516 } 517 518 case INVOKE_ID_SELECT_TRACK: 519 { 520 int trackIndex = request.readInt32(); 521 return mPlayer->selectTrack(trackIndex, true /* select */); 522 } 523 524 case INVOKE_ID_UNSELECT_TRACK: 525 { 526 int trackIndex = request.readInt32(); 527 return mPlayer->selectTrack(trackIndex, false /* select */); 528 } 529 530 case INVOKE_ID_GET_SELECTED_TRACK: 531 { 532 int32_t type = request.readInt32(); 533 return mPlayer->getSelectedTrack(type, reply); 534 } 535 536 default: 537 { 538 return INVALID_OPERATION; 539 } 540 } 541} 542 543void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) { 544 mPlayer->setAudioSink(audioSink); 545 mAudioSink = audioSink; 546} 547 548status_t NuPlayerDriver::setParameter( 549 int /* key */, const Parcel & /* request */) { 550 return INVALID_OPERATION; 551} 552 553status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) { 554 return INVALID_OPERATION; 555} 556 557status_t NuPlayerDriver::getMetadata( 558 const media::Metadata::Filter& /* ids */, Parcel *records) { 559 Mutex::Autolock autoLock(mLock); 560 561 using media::Metadata; 562 563 Metadata meta(records); 564 565 meta.appendBool( 566 Metadata::kPauseAvailable, 567 mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE); 568 569 meta.appendBool( 570 Metadata::kSeekBackwardAvailable, 571 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD); 572 573 meta.appendBool( 574 Metadata::kSeekForwardAvailable, 575 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD); 576 577 meta.appendBool( 578 Metadata::kSeekAvailable, 579 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK); 580 581 return OK; 582} 583 584void NuPlayerDriver::notifyResetComplete() { 585 ALOGI("notifyResetComplete(%p)", this); 586 Mutex::Autolock autoLock(mLock); 587 588 CHECK_EQ(mState, STATE_RESET_IN_PROGRESS); 589 mState = STATE_IDLE; 590 mCondition.broadcast(); 591} 592 593void NuPlayerDriver::notifySetSurfaceComplete() { 594 ALOGV("notifySetSurfaceComplete(%p)", this); 595 Mutex::Autolock autoLock(mLock); 596 597 CHECK(mSetSurfaceInProgress); 598 mSetSurfaceInProgress = false; 599 600 mCondition.broadcast(); 601} 602 603void NuPlayerDriver::notifyDuration(int64_t durationUs) { 604 Mutex::Autolock autoLock(mLock); 605 mDurationUs = durationUs; 606} 607 608void NuPlayerDriver::notifyPosition(int64_t positionUs) { 609 Mutex::Autolock autoLock(mLock); 610 if (isPlaying()) { 611 mPositionUs = positionUs; 612 mNotifyTimeRealUs = ALooper::GetNowUs(); 613 } 614} 615 616void NuPlayerDriver::notifySeekComplete() { 617 ALOGV("notifySeekComplete(%p)", this); 618 Mutex::Autolock autoLock(mLock); 619 notifySeekComplete_l(); 620} 621 622void NuPlayerDriver::notifySeekComplete_l() { 623 bool wasSeeking = true; 624 if (mState == STATE_STOPPED_AND_PREPARING) { 625 wasSeeking = false; 626 mState = STATE_STOPPED_AND_PREPARED; 627 mCondition.broadcast(); 628 if (!mIsAsyncPrepare) { 629 // if we are preparing synchronously, no need to notify listener 630 return; 631 } 632 } else if (mState == STATE_STOPPED) { 633 // no need to notify listener 634 return; 635 } 636 notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); 637} 638 639void NuPlayerDriver::notifyFrameStats( 640 int64_t numFramesTotal, int64_t numFramesDropped) { 641 Mutex::Autolock autoLock(mLock); 642 mNumFramesTotal = numFramesTotal; 643 mNumFramesDropped = numFramesDropped; 644} 645 646status_t NuPlayerDriver::dump( 647 int fd, const Vector<String16> & /* args */) const { 648 Mutex::Autolock autoLock(mLock); 649 650 FILE *out = fdopen(dup(fd), "w"); 651 652 fprintf(out, " NuPlayer\n"); 653 fprintf(out, " numFramesTotal(%" PRId64 "), numFramesDropped(%" PRId64 "), " 654 "percentageDropped(%.2f)\n", 655 mNumFramesTotal, 656 mNumFramesDropped, 657 mNumFramesTotal == 0 658 ? 0.0 : (double)mNumFramesDropped / mNumFramesTotal); 659 660 fclose(out); 661 out = NULL; 662 663 return OK; 664} 665 666void NuPlayerDriver::notifyListener( 667 int msg, int ext1, int ext2, const Parcel *in) { 668 Mutex::Autolock autoLock(mLock); 669 notifyListener_l(msg, ext1, ext2, in); 670} 671 672void NuPlayerDriver::notifyListener_l( 673 int msg, int ext1, int ext2, const Parcel *in) { 674 switch (msg) { 675 case MEDIA_PLAYBACK_COMPLETE: 676 { 677 if (mState != STATE_RESET_IN_PROGRESS) { 678 if (mLooping || (mAutoLoop 679 && (mAudioSink == NULL || mAudioSink->realtime()))) { 680 mPlayer->seekToAsync(0); 681 break; 682 } 683 684 mPlayer->pause(); 685 mState = STATE_PAUSED; 686 } 687 // fall through 688 } 689 690 case MEDIA_ERROR: 691 { 692 mAtEOS = true; 693 setPauseStartedTimeIfNeeded(); 694 break; 695 } 696 697 default: 698 break; 699 } 700 701 mLock.unlock(); 702 sendEvent(msg, ext1, ext2, in); 703 mLock.lock(); 704} 705 706void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) { 707 Mutex::Autolock autoLock(mLock); 708 709 CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING); 710 711 mAsyncResult = err; 712 mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE; 713 mCondition.broadcast(); 714} 715 716void NuPlayerDriver::notifyPrepareCompleted(status_t err) { 717 Mutex::Autolock autoLock(mLock); 718 719 if (mState != STATE_PREPARING) { 720 // We were preparing asynchronously when the client called 721 // reset(), we sent a premature "prepared" notification and 722 // then initiated the reset. This notification is stale. 723 CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE); 724 return; 725 } 726 727 CHECK_EQ(mState, STATE_PREPARING); 728 729 mAsyncResult = err; 730 731 if (err == OK) { 732 // update state before notifying client, so that if client calls back into NuPlayerDriver 733 // in response, NuPlayerDriver has the right state 734 mState = STATE_PREPARED; 735 if (mIsAsyncPrepare) { 736 notifyListener_l(MEDIA_PREPARED); 737 } 738 } else { 739 mState = STATE_UNPREPARED; 740 if (mIsAsyncPrepare) { 741 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 742 } 743 } 744 745 sp<MetaData> meta = mPlayer->getFileMeta(); 746 int32_t loop; 747 if (meta != NULL 748 && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { 749 mAutoLoop = true; 750 } 751 752 mCondition.broadcast(); 753} 754 755void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) { 756 Mutex::Autolock autoLock(mLock); 757 758 mPlayerFlags = flags; 759} 760 761void NuPlayerDriver::setPauseStartedTimeIfNeeded() { 762 if (mPauseStartedTimeUs == -1) { 763 mPauseStartedTimeUs = ALooper::GetNowUs(); 764 } 765} 766 767} // namespace android 768