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/foundation/AUtils.h> 30 #include <media/stagefright/MetaData.h> 31 #include <media/stagefright/Utils.h> 32 33 namespace android { 34 35 NuPlayerDriver::NuPlayerDriver() 36 : mState(STATE_IDLE), 37 mIsAsyncPrepare(false), 38 mAsyncResult(UNKNOWN_ERROR), 39 mSetSurfaceInProgress(false), 40 mDurationUs(-1), 41 mPositionUs(-1), 42 mSeekInProgress(false), 43 mLooper(new ALooper), 44 mPlayerFlags(0), 45 mAtEOS(false), 46 mLooping(false), 47 mAutoLoop(false), 48 mStartupSeekTimeUs(-1) { 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; 58 mLooper->registerHandler(mPlayer); 59 60 mPlayer->setDriver(this); 61 } 62 63 NuPlayerDriver::~NuPlayerDriver() { 64 ALOGV("~NuPlayerDriver(%p)", this); 65 mLooper->stop(); 66 } 67 68 status_t NuPlayerDriver::initCheck() { 69 return OK; 70 } 71 72 status_t NuPlayerDriver::setUID(uid_t uid) { 73 mPlayer->setUID(uid); 74 75 return OK; 76 } 77 78 status_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 100 status_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 119 status_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 138 status_t NuPlayerDriver::setVideoSurfaceTexture( 139 const sp<IGraphicBufferProducer> &bufferProducer) { 140 ALOGV("setVideoSurfaceTexture(%p)", this); 141 Mutex::Autolock autoLock(mLock); 142 143 if (mSetSurfaceInProgress) { 144 return INVALID_OPERATION; 145 } 146 147 switch (mState) { 148 case STATE_SET_DATASOURCE_PENDING: 149 case STATE_RESET_IN_PROGRESS: 150 return INVALID_OPERATION; 151 152 default: 153 break; 154 } 155 156 mSetSurfaceInProgress = true; 157 158 mPlayer->setVideoSurfaceTextureAsync(bufferProducer); 159 160 while (mSetSurfaceInProgress) { 161 mCondition.wait(mLock); 162 } 163 164 return OK; 165 } 166 167 status_t NuPlayerDriver::prepare() { 168 ALOGV("prepare(%p)", this); 169 Mutex::Autolock autoLock(mLock); 170 return prepare_l(); 171 } 172 173 status_t NuPlayerDriver::prepare_l() { 174 switch (mState) { 175 case STATE_UNPREPARED: 176 mState = STATE_PREPARING; 177 178 // Make sure we're not posting any notifications, success or 179 // failure information is only communicated through our result 180 // code. 181 mIsAsyncPrepare = false; 182 mPlayer->prepareAsync(); 183 while (mState == STATE_PREPARING) { 184 mCondition.wait(mLock); 185 } 186 return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR; 187 case STATE_STOPPED: 188 // this is really just paused. handle as seek to start 189 mAtEOS = false; 190 mState = STATE_STOPPED_AND_PREPARING; 191 mIsAsyncPrepare = false; 192 mPlayer->seekToAsync(0, true /* needNotify */); 193 while (mState == STATE_STOPPED_AND_PREPARING) { 194 mCondition.wait(mLock); 195 } 196 return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR; 197 default: 198 return INVALID_OPERATION; 199 }; 200 } 201 202 status_t NuPlayerDriver::prepareAsync() { 203 ALOGV("prepareAsync(%p)", this); 204 Mutex::Autolock autoLock(mLock); 205 206 switch (mState) { 207 case STATE_UNPREPARED: 208 mState = STATE_PREPARING; 209 mIsAsyncPrepare = true; 210 mPlayer->prepareAsync(); 211 return OK; 212 case STATE_STOPPED: 213 // this is really just paused. handle as seek to start 214 mAtEOS = false; 215 mState = STATE_STOPPED_AND_PREPARING; 216 mIsAsyncPrepare = true; 217 mPlayer->seekToAsync(0, true /* needNotify */); 218 return OK; 219 default: 220 return INVALID_OPERATION; 221 }; 222 } 223 224 status_t NuPlayerDriver::start() { 225 ALOGD("start(%p)", this); 226 Mutex::Autolock autoLock(mLock); 227 228 switch (mState) { 229 case STATE_UNPREPARED: 230 { 231 status_t err = prepare_l(); 232 233 if (err != OK) { 234 return err; 235 } 236 237 CHECK_EQ(mState, STATE_PREPARED); 238 239 // fall through 240 } 241 242 case STATE_PREPARED: 243 { 244 mAtEOS = false; 245 mPlayer->start(); 246 247 if (mStartupSeekTimeUs >= 0) { 248 if (mStartupSeekTimeUs > 0) { 249 mPlayer->seekToAsync(mStartupSeekTimeUs); 250 } 251 252 mStartupSeekTimeUs = -1; 253 } 254 break; 255 } 256 257 case STATE_RUNNING: 258 { 259 if (mAtEOS) { 260 mPlayer->seekToAsync(0); 261 mAtEOS = false; 262 mPositionUs = -1; 263 } 264 break; 265 } 266 267 case STATE_PAUSED: 268 case STATE_STOPPED_AND_PREPARED: 269 { 270 if (mAtEOS) { 271 mPlayer->seekToAsync(0); 272 mAtEOS = false; 273 mPlayer->resume(); 274 mPositionUs = -1; 275 } else { 276 mPlayer->resume(); 277 } 278 break; 279 } 280 281 default: 282 return INVALID_OPERATION; 283 } 284 285 mState = STATE_RUNNING; 286 287 return OK; 288 } 289 290 status_t NuPlayerDriver::stop() { 291 ALOGD("stop(%p)", this); 292 Mutex::Autolock autoLock(mLock); 293 294 switch (mState) { 295 case STATE_RUNNING: 296 mPlayer->pause(); 297 // fall through 298 299 case STATE_PAUSED: 300 mState = STATE_STOPPED; 301 notifyListener_l(MEDIA_STOPPED); 302 break; 303 304 case STATE_PREPARED: 305 case STATE_STOPPED: 306 case STATE_STOPPED_AND_PREPARING: 307 case STATE_STOPPED_AND_PREPARED: 308 mState = STATE_STOPPED; 309 break; 310 311 default: 312 return INVALID_OPERATION; 313 } 314 315 return OK; 316 } 317 318 status_t NuPlayerDriver::pause() { 319 Mutex::Autolock autoLock(mLock); 320 321 switch (mState) { 322 case STATE_PAUSED: 323 case STATE_PREPARED: 324 return OK; 325 326 case STATE_RUNNING: 327 mState = STATE_PAUSED; 328 notifyListener_l(MEDIA_PAUSED); 329 mPlayer->pause(); 330 break; 331 332 default: 333 return INVALID_OPERATION; 334 } 335 336 return OK; 337 } 338 339 bool NuPlayerDriver::isPlaying() { 340 return mState == STATE_RUNNING && !mAtEOS; 341 } 342 343 status_t NuPlayerDriver::seekTo(int msec) { 344 ALOGD("seekTo(%p) %d ms", this, msec); 345 Mutex::Autolock autoLock(mLock); 346 347 int64_t seekTimeUs = msec * 1000ll; 348 349 switch (mState) { 350 case STATE_PREPARED: 351 { 352 mStartupSeekTimeUs = seekTimeUs; 353 // pretend that the seek completed. It will actually happen when starting playback. 354 // TODO: actually perform the seek here, so the player is ready to go at the new 355 // location 356 notifySeekComplete_l(); 357 break; 358 } 359 360 case STATE_RUNNING: 361 case STATE_PAUSED: 362 { 363 mAtEOS = false; 364 mSeekInProgress = true; 365 // seeks can take a while, so we essentially paused 366 notifyListener_l(MEDIA_PAUSED); 367 mPlayer->seekToAsync(seekTimeUs, true /* needNotify */); 368 break; 369 } 370 371 default: 372 return INVALID_OPERATION; 373 } 374 375 mPositionUs = seekTimeUs; 376 return OK; 377 } 378 379 status_t NuPlayerDriver::getCurrentPosition(int *msec) { 380 int64_t tempUs = 0; 381 status_t ret = mPlayer->getCurrentPosition(&tempUs); 382 383 Mutex::Autolock autoLock(mLock); 384 // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which 385 // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a 386 // position value that's different the seek to position. 387 if (ret != OK || mSeekInProgress) { 388 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs; 389 } else { 390 mPositionUs = tempUs; 391 } 392 *msec = (int)divRound(tempUs, (int64_t)(1000)); 393 return OK; 394 } 395 396 status_t NuPlayerDriver::getDuration(int *msec) { 397 Mutex::Autolock autoLock(mLock); 398 399 if (mDurationUs < 0) { 400 return UNKNOWN_ERROR; 401 } 402 403 *msec = (mDurationUs + 500ll) / 1000; 404 405 return OK; 406 } 407 408 status_t NuPlayerDriver::reset() { 409 ALOGD("reset(%p)", this); 410 Mutex::Autolock autoLock(mLock); 411 412 switch (mState) { 413 case STATE_IDLE: 414 return OK; 415 416 case STATE_SET_DATASOURCE_PENDING: 417 case STATE_RESET_IN_PROGRESS: 418 return INVALID_OPERATION; 419 420 case STATE_PREPARING: 421 { 422 CHECK(mIsAsyncPrepare); 423 424 notifyListener_l(MEDIA_PREPARED); 425 break; 426 } 427 428 default: 429 break; 430 } 431 432 if (mState != STATE_STOPPED) { 433 notifyListener_l(MEDIA_STOPPED); 434 } 435 436 mState = STATE_RESET_IN_PROGRESS; 437 mPlayer->resetAsync(); 438 439 while (mState == STATE_RESET_IN_PROGRESS) { 440 mCondition.wait(mLock); 441 } 442 443 mDurationUs = -1; 444 mPositionUs = -1; 445 mStartupSeekTimeUs = -1; 446 mLooping = false; 447 448 return OK; 449 } 450 451 status_t NuPlayerDriver::setLooping(int loop) { 452 mLooping = loop != 0; 453 return OK; 454 } 455 456 player_type NuPlayerDriver::playerType() { 457 return NU_PLAYER; 458 } 459 460 status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) { 461 if (reply == NULL) { 462 ALOGE("reply is a NULL pointer"); 463 return BAD_VALUE; 464 } 465 466 int32_t methodId; 467 status_t ret = request.readInt32(&methodId); 468 if (ret != OK) { 469 ALOGE("Failed to retrieve the requested method to invoke"); 470 return ret; 471 } 472 473 switch (methodId) { 474 case INVOKE_ID_SET_VIDEO_SCALING_MODE: 475 { 476 int mode = request.readInt32(); 477 return mPlayer->setVideoScalingMode(mode); 478 } 479 480 case INVOKE_ID_GET_TRACK_INFO: 481 { 482 return mPlayer->getTrackInfo(reply); 483 } 484 485 case INVOKE_ID_SELECT_TRACK: 486 { 487 int trackIndex = request.readInt32(); 488 return mPlayer->selectTrack(trackIndex, true /* select */); 489 } 490 491 case INVOKE_ID_UNSELECT_TRACK: 492 { 493 int trackIndex = request.readInt32(); 494 return mPlayer->selectTrack(trackIndex, false /* select */); 495 } 496 497 case INVOKE_ID_GET_SELECTED_TRACK: 498 { 499 int32_t type = request.readInt32(); 500 return mPlayer->getSelectedTrack(type, reply); 501 } 502 503 default: 504 { 505 return INVALID_OPERATION; 506 } 507 } 508 } 509 510 void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) { 511 mPlayer->setAudioSink(audioSink); 512 mAudioSink = audioSink; 513 } 514 515 status_t NuPlayerDriver::setParameter( 516 int /* key */, const Parcel & /* request */) { 517 return INVALID_OPERATION; 518 } 519 520 status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) { 521 return INVALID_OPERATION; 522 } 523 524 status_t NuPlayerDriver::getMetadata( 525 const media::Metadata::Filter& /* ids */, Parcel *records) { 526 Mutex::Autolock autoLock(mLock); 527 528 using media::Metadata; 529 530 Metadata meta(records); 531 532 meta.appendBool( 533 Metadata::kPauseAvailable, 534 mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE); 535 536 meta.appendBool( 537 Metadata::kSeekBackwardAvailable, 538 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD); 539 540 meta.appendBool( 541 Metadata::kSeekForwardAvailable, 542 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD); 543 544 meta.appendBool( 545 Metadata::kSeekAvailable, 546 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK); 547 548 return OK; 549 } 550 551 void NuPlayerDriver::notifyResetComplete() { 552 ALOGD("notifyResetComplete(%p)", this); 553 Mutex::Autolock autoLock(mLock); 554 555 CHECK_EQ(mState, STATE_RESET_IN_PROGRESS); 556 mState = STATE_IDLE; 557 mCondition.broadcast(); 558 } 559 560 void NuPlayerDriver::notifySetSurfaceComplete() { 561 ALOGV("notifySetSurfaceComplete(%p)", this); 562 Mutex::Autolock autoLock(mLock); 563 564 CHECK(mSetSurfaceInProgress); 565 mSetSurfaceInProgress = false; 566 567 mCondition.broadcast(); 568 } 569 570 void NuPlayerDriver::notifyDuration(int64_t durationUs) { 571 Mutex::Autolock autoLock(mLock); 572 mDurationUs = durationUs; 573 } 574 575 void NuPlayerDriver::notifySeekComplete() { 576 ALOGV("notifySeekComplete(%p)", this); 577 Mutex::Autolock autoLock(mLock); 578 mSeekInProgress = false; 579 notifySeekComplete_l(); 580 } 581 582 void NuPlayerDriver::notifySeekComplete_l() { 583 bool wasSeeking = true; 584 if (mState == STATE_STOPPED_AND_PREPARING) { 585 wasSeeking = false; 586 mState = STATE_STOPPED_AND_PREPARED; 587 mCondition.broadcast(); 588 if (!mIsAsyncPrepare) { 589 // if we are preparing synchronously, no need to notify listener 590 return; 591 } 592 } else if (mState == STATE_STOPPED) { 593 // no need to notify listener 594 return; 595 } 596 notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); 597 } 598 599 status_t NuPlayerDriver::dump( 600 int fd, const Vector<String16> & /* args */) const { 601 int64_t numFramesTotal; 602 int64_t numFramesDropped; 603 mPlayer->getStats(&numFramesTotal, &numFramesDropped); 604 605 FILE *out = fdopen(dup(fd), "w"); 606 607 fprintf(out, " NuPlayer\n"); 608 fprintf(out, " numFramesTotal(%" PRId64 "), numFramesDropped(%" PRId64 "), " 609 "percentageDropped(%.2f)\n", 610 numFramesTotal, 611 numFramesDropped, 612 numFramesTotal == 0 613 ? 0.0 : (double)numFramesDropped / numFramesTotal); 614 615 fclose(out); 616 out = NULL; 617 618 return OK; 619 } 620 621 void NuPlayerDriver::notifyListener( 622 int msg, int ext1, int ext2, const Parcel *in) { 623 Mutex::Autolock autoLock(mLock); 624 notifyListener_l(msg, ext1, ext2, in); 625 } 626 627 void NuPlayerDriver::notifyListener_l( 628 int msg, int ext1, int ext2, const Parcel *in) { 629 switch (msg) { 630 case MEDIA_PLAYBACK_COMPLETE: 631 { 632 if (mState != STATE_RESET_IN_PROGRESS) { 633 if (mLooping || (mAutoLoop 634 && (mAudioSink == NULL || mAudioSink->realtime()))) { 635 mPlayer->seekToAsync(0); 636 break; 637 } 638 639 mPlayer->pause(); 640 mState = STATE_PAUSED; 641 } 642 // fall through 643 } 644 645 case MEDIA_ERROR: 646 { 647 mAtEOS = true; 648 break; 649 } 650 651 default: 652 break; 653 } 654 655 mLock.unlock(); 656 sendEvent(msg, ext1, ext2, in); 657 mLock.lock(); 658 } 659 660 void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) { 661 Mutex::Autolock autoLock(mLock); 662 663 CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING); 664 665 mAsyncResult = err; 666 mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE; 667 mCondition.broadcast(); 668 } 669 670 void NuPlayerDriver::notifyPrepareCompleted(status_t err) { 671 Mutex::Autolock autoLock(mLock); 672 673 if (mState != STATE_PREPARING) { 674 // We were preparing asynchronously when the client called 675 // reset(), we sent a premature "prepared" notification and 676 // then initiated the reset. This notification is stale. 677 CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE); 678 return; 679 } 680 681 CHECK_EQ(mState, STATE_PREPARING); 682 683 mAsyncResult = err; 684 685 if (err == OK) { 686 // update state before notifying client, so that if client calls back into NuPlayerDriver 687 // in response, NuPlayerDriver has the right state 688 mState = STATE_PREPARED; 689 if (mIsAsyncPrepare) { 690 notifyListener_l(MEDIA_PREPARED); 691 } 692 } else { 693 mState = STATE_UNPREPARED; 694 if (mIsAsyncPrepare) { 695 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 696 } 697 } 698 699 sp<MetaData> meta = mPlayer->getFileMeta(); 700 int32_t loop; 701 if (meta != NULL 702 && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { 703 mAutoLoop = true; 704 } 705 706 mCondition.broadcast(); 707 } 708 709 void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) { 710 Mutex::Autolock autoLock(mLock); 711 712 mPlayerFlags = flags; 713 } 714 715 } // namespace android 716