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