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 <android-base/macros.h> 21 #include <utils/Log.h> 22 #include <cutils/properties.h> 23 24 #include "NuPlayerDriver.h" 25 26 #include "NuPlayer.h" 27 #include "NuPlayerSource.h" 28 29 #include <media/stagefright/foundation/ADebug.h> 30 #include <media/stagefright/foundation/ALooper.h> 31 #include <media/stagefright/foundation/AUtils.h> 32 #include <media/stagefright/foundation/ByteUtils.h> 33 #include <media/stagefright/MediaClock.h> 34 #include <media/stagefright/MetaData.h> 35 #include <media/stagefright/Utils.h> 36 37 #include <media/IMediaAnalyticsService.h> 38 39 static const int kDumpLockRetries = 50; 40 static const int kDumpLockSleepUs = 20000; 41 42 namespace android { 43 44 // key for media statistics 45 static const char *kKeyPlayer = "nuplayer"; 46 // attrs for media statistics 47 // NB: these are matched with public Java API constants defined 48 // in frameworks/base/media/java/android/media/MediaPlayer.java 49 // These must be kept synchronized with the constants there. 50 static const char *kPlayerVMime = "android.media.mediaplayer.video.mime"; 51 static const char *kPlayerVCodec = "android.media.mediaplayer.video.codec"; 52 static const char *kPlayerWidth = "android.media.mediaplayer.width"; 53 static const char *kPlayerHeight = "android.media.mediaplayer.height"; 54 static const char *kPlayerFrames = "android.media.mediaplayer.frames"; 55 static const char *kPlayerFramesDropped = "android.media.mediaplayer.dropped"; 56 static const char *kPlayerFrameRate = "android.media.mediaplayer.fps"; 57 static const char *kPlayerAMime = "android.media.mediaplayer.audio.mime"; 58 static const char *kPlayerACodec = "android.media.mediaplayer.audio.codec"; 59 static const char *kPlayerDuration = "android.media.mediaplayer.durationMs"; 60 static const char *kPlayerPlaying = "android.media.mediaplayer.playingMs"; 61 static const char *kPlayerError = "android.media.mediaplayer.err"; 62 static const char *kPlayerErrorCode = "android.media.mediaplayer.errcode"; 63 64 // NB: These are not yet exposed as public Java API constants. 65 static const char *kPlayerErrorState = "android.media.mediaplayer.errstate"; 66 static const char *kPlayerDataSourceType = "android.media.mediaplayer.dataSource"; 67 // 68 static const char *kPlayerRebuffering = "android.media.mediaplayer.rebufferingMs"; 69 static const char *kPlayerRebufferingCount = "android.media.mediaplayer.rebuffers"; 70 static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit"; 71 72 73 NuPlayerDriver::NuPlayerDriver(pid_t pid) 74 : mState(STATE_IDLE), 75 mIsAsyncPrepare(false), 76 mAsyncResult(UNKNOWN_ERROR), 77 mSetSurfaceInProgress(false), 78 mDurationUs(-1), 79 mPositionUs(-1), 80 mSeekInProgress(false), 81 mPlayingTimeUs(0), 82 mRebufferingTimeUs(0), 83 mRebufferingEvents(0), 84 mRebufferingAtExit(false), 85 mLooper(new ALooper), 86 mMediaClock(new MediaClock), 87 mPlayer(new NuPlayer(pid, mMediaClock)), 88 mPlayerFlags(0), 89 mAnalyticsItem(NULL), 90 mClientUid(-1), 91 mAtEOS(false), 92 mLooping(false), 93 mAutoLoop(false) { 94 ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid); 95 mLooper->setName("NuPlayerDriver Looper"); 96 97 mMediaClock->init(); 98 99 // set up an analytics record 100 mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer); 101 102 mLooper->start( 103 false, /* runOnCallingThread */ 104 true, /* canCallJava */ 105 PRIORITY_AUDIO); 106 107 mLooper->registerHandler(mPlayer); 108 109 mPlayer->init(this); 110 } 111 112 NuPlayerDriver::~NuPlayerDriver() { 113 ALOGV("~NuPlayerDriver(%p)", this); 114 mLooper->stop(); 115 116 // finalize any pending metrics, usually a no-op. 117 updateMetrics("destructor"); 118 logMetrics("destructor"); 119 120 if (mAnalyticsItem != NULL) { 121 delete mAnalyticsItem; 122 mAnalyticsItem = NULL; 123 } 124 } 125 126 status_t NuPlayerDriver::initCheck() { 127 return OK; 128 } 129 130 status_t NuPlayerDriver::setUID(uid_t uid) { 131 mPlayer->setUID(uid); 132 mClientUid = uid; 133 if (mAnalyticsItem) { 134 mAnalyticsItem->setUid(mClientUid); 135 } 136 137 return OK; 138 } 139 140 status_t NuPlayerDriver::setDataSource( 141 const sp<IMediaHTTPService> &httpService, 142 const char *url, 143 const KeyedVector<String8, String8> *headers) { 144 ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str()); 145 Mutex::Autolock autoLock(mLock); 146 147 if (mState != STATE_IDLE) { 148 return INVALID_OPERATION; 149 } 150 151 mState = STATE_SET_DATASOURCE_PENDING; 152 153 mPlayer->setDataSourceAsync(httpService, url, headers); 154 155 while (mState == STATE_SET_DATASOURCE_PENDING) { 156 mCondition.wait(mLock); 157 } 158 159 return mAsyncResult; 160 } 161 162 status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) { 163 ALOGV("setDataSource(%p) file(%d)", this, fd); 164 Mutex::Autolock autoLock(mLock); 165 166 if (mState != STATE_IDLE) { 167 return INVALID_OPERATION; 168 } 169 170 mState = STATE_SET_DATASOURCE_PENDING; 171 172 mPlayer->setDataSourceAsync(fd, offset, length); 173 174 while (mState == STATE_SET_DATASOURCE_PENDING) { 175 mCondition.wait(mLock); 176 } 177 178 return mAsyncResult; 179 } 180 181 status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) { 182 ALOGV("setDataSource(%p) stream source", this); 183 Mutex::Autolock autoLock(mLock); 184 185 if (mState != STATE_IDLE) { 186 return INVALID_OPERATION; 187 } 188 189 mState = STATE_SET_DATASOURCE_PENDING; 190 191 mPlayer->setDataSourceAsync(source); 192 193 while (mState == STATE_SET_DATASOURCE_PENDING) { 194 mCondition.wait(mLock); 195 } 196 197 return mAsyncResult; 198 } 199 200 status_t NuPlayerDriver::setDataSource(const sp<DataSource> &source) { 201 ALOGV("setDataSource(%p) callback source", this); 202 Mutex::Autolock autoLock(mLock); 203 204 if (mState != STATE_IDLE) { 205 return INVALID_OPERATION; 206 } 207 208 mState = STATE_SET_DATASOURCE_PENDING; 209 210 mPlayer->setDataSourceAsync(source); 211 212 while (mState == STATE_SET_DATASOURCE_PENDING) { 213 mCondition.wait(mLock); 214 } 215 216 return mAsyncResult; 217 } 218 219 status_t NuPlayerDriver::setVideoSurfaceTexture( 220 const sp<IGraphicBufferProducer> &bufferProducer) { 221 ALOGV("setVideoSurfaceTexture(%p)", this); 222 Mutex::Autolock autoLock(mLock); 223 224 if (mSetSurfaceInProgress) { 225 return INVALID_OPERATION; 226 } 227 228 switch (mState) { 229 case STATE_SET_DATASOURCE_PENDING: 230 case STATE_RESET_IN_PROGRESS: 231 return INVALID_OPERATION; 232 233 default: 234 break; 235 } 236 237 mSetSurfaceInProgress = true; 238 239 mPlayer->setVideoSurfaceTextureAsync(bufferProducer); 240 241 while (mSetSurfaceInProgress) { 242 mCondition.wait(mLock); 243 } 244 245 return OK; 246 } 247 248 status_t NuPlayerDriver::getBufferingSettings(BufferingSettings* buffering) { 249 ALOGV("getBufferingSettings(%p)", this); 250 { 251 Mutex::Autolock autoLock(mLock); 252 if (mState == STATE_IDLE) { 253 return INVALID_OPERATION; 254 } 255 } 256 257 return mPlayer->getBufferingSettings(buffering); 258 } 259 260 status_t NuPlayerDriver::setBufferingSettings(const BufferingSettings& buffering) { 261 ALOGV("setBufferingSettings(%p)", this); 262 { 263 Mutex::Autolock autoLock(mLock); 264 if (mState == STATE_IDLE) { 265 return INVALID_OPERATION; 266 } 267 } 268 269 return mPlayer->setBufferingSettings(buffering); 270 } 271 272 status_t NuPlayerDriver::prepare() { 273 ALOGV("prepare(%p)", this); 274 Mutex::Autolock autoLock(mLock); 275 return prepare_l(); 276 } 277 278 status_t NuPlayerDriver::prepare_l() { 279 switch (mState) { 280 case STATE_UNPREPARED: 281 mState = STATE_PREPARING; 282 283 // Make sure we're not posting any notifications, success or 284 // failure information is only communicated through our result 285 // code. 286 mIsAsyncPrepare = false; 287 mPlayer->prepareAsync(); 288 while (mState == STATE_PREPARING) { 289 mCondition.wait(mLock); 290 } 291 return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR; 292 case STATE_STOPPED: 293 // this is really just paused. handle as seek to start 294 mAtEOS = false; 295 mState = STATE_STOPPED_AND_PREPARING; 296 mIsAsyncPrepare = false; 297 mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, 298 true /* needNotify */); 299 while (mState == STATE_STOPPED_AND_PREPARING) { 300 mCondition.wait(mLock); 301 } 302 return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR; 303 default: 304 return INVALID_OPERATION; 305 }; 306 } 307 308 status_t NuPlayerDriver::prepareAsync() { 309 ALOGV("prepareAsync(%p)", this); 310 Mutex::Autolock autoLock(mLock); 311 312 switch (mState) { 313 case STATE_UNPREPARED: 314 mState = STATE_PREPARING; 315 mIsAsyncPrepare = true; 316 mPlayer->prepareAsync(); 317 return OK; 318 case STATE_STOPPED: 319 // this is really just paused. handle as seek to start 320 mAtEOS = false; 321 mState = STATE_STOPPED_AND_PREPARING; 322 mIsAsyncPrepare = true; 323 mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, 324 true /* needNotify */); 325 return OK; 326 default: 327 return INVALID_OPERATION; 328 }; 329 } 330 331 status_t NuPlayerDriver::start() { 332 ALOGV("start(%p), state is %d, eos is %d", this, mState, mAtEOS); 333 Mutex::Autolock autoLock(mLock); 334 return start_l(); 335 } 336 337 status_t NuPlayerDriver::start_l() { 338 switch (mState) { 339 case STATE_UNPREPARED: 340 { 341 status_t err = prepare_l(); 342 343 if (err != OK) { 344 return err; 345 } 346 347 CHECK_EQ(mState, STATE_PREPARED); 348 349 FALLTHROUGH_INTENDED; 350 } 351 352 case STATE_PAUSED: 353 case STATE_STOPPED_AND_PREPARED: 354 case STATE_PREPARED: 355 { 356 mPlayer->start(); 357 358 FALLTHROUGH_INTENDED; 359 } 360 361 case STATE_RUNNING: 362 { 363 if (mAtEOS) { 364 mPlayer->seekToAsync(0); 365 mAtEOS = false; 366 mPositionUs = -1; 367 } 368 break; 369 } 370 371 default: 372 return INVALID_OPERATION; 373 } 374 375 mState = STATE_RUNNING; 376 377 return OK; 378 } 379 380 status_t NuPlayerDriver::stop() { 381 ALOGD("stop(%p)", this); 382 Mutex::Autolock autoLock(mLock); 383 384 switch (mState) { 385 case STATE_RUNNING: 386 mPlayer->pause(); 387 FALLTHROUGH_INTENDED; 388 389 case STATE_PAUSED: 390 mState = STATE_STOPPED; 391 notifyListener_l(MEDIA_STOPPED); 392 break; 393 394 case STATE_PREPARED: 395 case STATE_STOPPED: 396 case STATE_STOPPED_AND_PREPARING: 397 case STATE_STOPPED_AND_PREPARED: 398 mState = STATE_STOPPED; 399 break; 400 401 default: 402 return INVALID_OPERATION; 403 } 404 405 return OK; 406 } 407 408 status_t NuPlayerDriver::pause() { 409 ALOGD("pause(%p)", this); 410 // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear 411 // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the 412 // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling 413 // getCurrentPosition here. 414 int unused; 415 getCurrentPosition(&unused); 416 417 Mutex::Autolock autoLock(mLock); 418 419 switch (mState) { 420 case STATE_PAUSED: 421 case STATE_PREPARED: 422 return OK; 423 424 case STATE_RUNNING: 425 mState = STATE_PAUSED; 426 notifyListener_l(MEDIA_PAUSED); 427 mPlayer->pause(); 428 break; 429 430 default: 431 return INVALID_OPERATION; 432 } 433 434 return OK; 435 } 436 437 bool NuPlayerDriver::isPlaying() { 438 return mState == STATE_RUNNING && !mAtEOS; 439 } 440 441 status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) { 442 status_t err = mPlayer->setPlaybackSettings(rate); 443 if (err == OK) { 444 // try to update position 445 int unused; 446 getCurrentPosition(&unused); 447 Mutex::Autolock autoLock(mLock); 448 if (rate.mSpeed == 0.f && mState == STATE_RUNNING) { 449 mState = STATE_PAUSED; 450 notifyListener_l(MEDIA_PAUSED); 451 } else if (rate.mSpeed != 0.f 452 && (mState == STATE_PAUSED 453 || mState == STATE_STOPPED_AND_PREPARED 454 || mState == STATE_PREPARED)) { 455 err = start_l(); 456 } 457 } 458 return err; 459 } 460 461 status_t NuPlayerDriver::getPlaybackSettings(AudioPlaybackRate *rate) { 462 return mPlayer->getPlaybackSettings(rate); 463 } 464 465 status_t NuPlayerDriver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) { 466 return mPlayer->setSyncSettings(sync, videoFpsHint); 467 } 468 469 status_t NuPlayerDriver::getSyncSettings(AVSyncSettings *sync, float *videoFps) { 470 return mPlayer->getSyncSettings(sync, videoFps); 471 } 472 473 status_t NuPlayerDriver::seekTo(int msec, MediaPlayerSeekMode mode) { 474 ALOGV("seekTo(%p) (%d ms, %d) at state %d", this, msec, mode, mState); 475 Mutex::Autolock autoLock(mLock); 476 477 int64_t seekTimeUs = msec * 1000LL; 478 479 switch (mState) { 480 case STATE_PREPARED: 481 case STATE_STOPPED_AND_PREPARED: 482 case STATE_PAUSED: 483 case STATE_RUNNING: 484 { 485 mAtEOS = false; 486 mSeekInProgress = true; 487 // seeks can take a while, so we essentially paused 488 notifyListener_l(MEDIA_PAUSED); 489 mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */); 490 break; 491 } 492 493 default: 494 return INVALID_OPERATION; 495 } 496 497 mPositionUs = seekTimeUs; 498 return OK; 499 } 500 501 status_t NuPlayerDriver::getCurrentPosition(int *msec) { 502 int64_t tempUs = 0; 503 { 504 Mutex::Autolock autoLock(mLock); 505 if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) { 506 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs; 507 *msec = (int)divRound(tempUs, (int64_t)(1000)); 508 return OK; 509 } 510 } 511 512 status_t ret = mPlayer->getCurrentPosition(&tempUs); 513 514 Mutex::Autolock autoLock(mLock); 515 // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which 516 // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a 517 // position value that's different the seek to position. 518 if (ret != OK) { 519 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs; 520 } else { 521 mPositionUs = tempUs; 522 } 523 *msec = (int)divRound(tempUs, (int64_t)(1000)); 524 return OK; 525 } 526 527 status_t NuPlayerDriver::getDuration(int *msec) { 528 Mutex::Autolock autoLock(mLock); 529 530 if (mDurationUs < 0) { 531 return UNKNOWN_ERROR; 532 } 533 534 *msec = (mDurationUs + 500LL) / 1000; 535 536 return OK; 537 } 538 539 void NuPlayerDriver::updateMetrics(const char *where) { 540 541 if (where == NULL) { 542 where = "unknown"; 543 } 544 ALOGV("updateMetrics(%p) from %s at state %d", this, where, mState); 545 546 // gather the final stats for this record 547 Vector<sp<AMessage>> trackStats; 548 mPlayer->getStats(&trackStats); 549 550 if (trackStats.size() > 0) { 551 for (size_t i = 0; i < trackStats.size(); ++i) { 552 const sp<AMessage> &stats = trackStats.itemAt(i); 553 554 AString mime; 555 stats->findString("mime", &mime); 556 557 AString name; 558 stats->findString("component-name", &name); 559 560 if (mime.startsWith("video/")) { 561 int32_t width, height; 562 mAnalyticsItem->setCString(kPlayerVMime, mime.c_str()); 563 if (!name.empty()) { 564 mAnalyticsItem->setCString(kPlayerVCodec, name.c_str()); 565 } 566 567 if (stats->findInt32("width", &width) 568 && stats->findInt32("height", &height)) { 569 mAnalyticsItem->setInt32(kPlayerWidth, width); 570 mAnalyticsItem->setInt32(kPlayerHeight, height); 571 } 572 573 int64_t numFramesTotal = 0; 574 int64_t numFramesDropped = 0; 575 stats->findInt64("frames-total", &numFramesTotal); 576 stats->findInt64("frames-dropped-output", &numFramesDropped); 577 578 mAnalyticsItem->setInt64(kPlayerFrames, numFramesTotal); 579 mAnalyticsItem->setInt64(kPlayerFramesDropped, numFramesDropped); 580 581 float frameRate = 0; 582 if (stats->findFloat("frame-rate-total", &frameRate)) { 583 mAnalyticsItem->setDouble(kPlayerFrameRate, (double) frameRate); 584 } 585 586 } else if (mime.startsWith("audio/")) { 587 mAnalyticsItem->setCString(kPlayerAMime, mime.c_str()); 588 if (!name.empty()) { 589 mAnalyticsItem->setCString(kPlayerACodec, name.c_str()); 590 } 591 } 592 } 593 } 594 595 // always provide duration and playing time, even if they have 0/unknown values. 596 597 // getDuration() uses mLock for mutex -- careful where we use it. 598 int duration_ms = -1; 599 getDuration(&duration_ms); 600 mAnalyticsItem->setInt64(kPlayerDuration, duration_ms); 601 602 mPlayer->updateInternalTimers(); 603 604 mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 ); 605 606 if (mRebufferingEvents != 0) { 607 mAnalyticsItem->setInt64(kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 ); 608 mAnalyticsItem->setInt32(kPlayerRebufferingCount, mRebufferingEvents); 609 mAnalyticsItem->setInt32(kPlayerRebufferingAtExit, mRebufferingAtExit); 610 611 } 612 613 mAnalyticsItem->setCString(kPlayerDataSourceType, mPlayer->getDataSourceType()); 614 } 615 616 617 void NuPlayerDriver::logMetrics(const char *where) { 618 if (where == NULL) { 619 where = "unknown"; 620 } 621 ALOGV("logMetrics(%p) from %s at state %d", this, where, mState); 622 623 if (mAnalyticsItem == NULL || mAnalyticsItem->isEnabled() == false) { 624 return; 625 } 626 627 // log only non-empty records 628 // we always updateMetrics() before we get here 629 // and that always injects 3 fields (duration, playing time, and 630 // datasource) into the record. 631 // So the canonical "empty" record has 3 elements in it. 632 if (mAnalyticsItem->count() > 3) { 633 634 mAnalyticsItem->selfrecord(); 635 636 // re-init in case we prepare() and start() again. 637 delete mAnalyticsItem ; 638 mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer); 639 if (mAnalyticsItem) { 640 mAnalyticsItem->setUid(mClientUid); 641 } 642 } else { 643 ALOGV("nothing to record (only %d fields)", mAnalyticsItem->count()); 644 } 645 } 646 647 status_t NuPlayerDriver::reset() { 648 ALOGD("reset(%p) at state %d", this, mState); 649 650 updateMetrics("reset"); 651 logMetrics("reset"); 652 653 Mutex::Autolock autoLock(mLock); 654 655 switch (mState) { 656 case STATE_IDLE: 657 return OK; 658 659 case STATE_SET_DATASOURCE_PENDING: 660 case STATE_RESET_IN_PROGRESS: 661 return INVALID_OPERATION; 662 663 case STATE_PREPARING: 664 { 665 CHECK(mIsAsyncPrepare); 666 667 notifyListener_l(MEDIA_PREPARED); 668 break; 669 } 670 671 default: 672 break; 673 } 674 675 if (mState != STATE_STOPPED) { 676 notifyListener_l(MEDIA_STOPPED); 677 } 678 679 if (property_get_bool("persist.debug.sf.stats", false)) { 680 Vector<String16> args; 681 dump(-1, args); 682 } 683 684 mState = STATE_RESET_IN_PROGRESS; 685 mPlayer->resetAsync(); 686 687 while (mState == STATE_RESET_IN_PROGRESS) { 688 mCondition.wait(mLock); 689 } 690 691 mDurationUs = -1; 692 mPositionUs = -1; 693 mLooping = false; 694 mPlayingTimeUs = 0; 695 mRebufferingTimeUs = 0; 696 mRebufferingEvents = 0; 697 mRebufferingAtExit = false; 698 699 return OK; 700 } 701 702 status_t NuPlayerDriver::notifyAt(int64_t mediaTimeUs) { 703 ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs); 704 return mPlayer->notifyAt(mediaTimeUs); 705 } 706 707 status_t NuPlayerDriver::setLooping(int loop) { 708 mLooping = loop != 0; 709 return OK; 710 } 711 712 player_type NuPlayerDriver::playerType() { 713 return NU_PLAYER; 714 } 715 716 status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) { 717 if (reply == NULL) { 718 ALOGE("reply is a NULL pointer"); 719 return BAD_VALUE; 720 } 721 722 int32_t methodId; 723 status_t ret = request.readInt32(&methodId); 724 if (ret != OK) { 725 ALOGE("Failed to retrieve the requested method to invoke"); 726 return ret; 727 } 728 729 switch (methodId) { 730 case INVOKE_ID_SET_VIDEO_SCALING_MODE: 731 { 732 int mode = request.readInt32(); 733 return mPlayer->setVideoScalingMode(mode); 734 } 735 736 case INVOKE_ID_GET_TRACK_INFO: 737 { 738 return mPlayer->getTrackInfo(reply); 739 } 740 741 case INVOKE_ID_SELECT_TRACK: 742 { 743 int trackIndex = request.readInt32(); 744 int msec = 0; 745 // getCurrentPosition should always return OK 746 getCurrentPosition(&msec); 747 return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000LL); 748 } 749 750 case INVOKE_ID_UNSELECT_TRACK: 751 { 752 int trackIndex = request.readInt32(); 753 return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */); 754 } 755 756 case INVOKE_ID_GET_SELECTED_TRACK: 757 { 758 int32_t type = request.readInt32(); 759 return mPlayer->getSelectedTrack(type, reply); 760 } 761 762 default: 763 { 764 return INVALID_OPERATION; 765 } 766 } 767 } 768 769 void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) { 770 mPlayer->setAudioSink(audioSink); 771 mAudioSink = audioSink; 772 } 773 774 status_t NuPlayerDriver::setParameter( 775 int /* key */, const Parcel & /* request */) { 776 return INVALID_OPERATION; 777 } 778 779 status_t NuPlayerDriver::getParameter(int key, Parcel *reply) { 780 781 if (key == FOURCC('m','t','r','X') && mAnalyticsItem != NULL) { 782 // mtrX -- a play on 'metrics' (not matrix) 783 // gather current info all together, parcel it, and send it back 784 updateMetrics("api"); 785 mAnalyticsItem->writeToParcel(reply); 786 return OK; 787 } 788 789 return INVALID_OPERATION; 790 } 791 792 status_t NuPlayerDriver::getMetadata( 793 const media::Metadata::Filter& /* ids */, Parcel *records) { 794 Mutex::Autolock autoLock(mLock); 795 796 using media::Metadata; 797 798 Metadata meta(records); 799 800 meta.appendBool( 801 Metadata::kPauseAvailable, 802 mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE); 803 804 meta.appendBool( 805 Metadata::kSeekBackwardAvailable, 806 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD); 807 808 meta.appendBool( 809 Metadata::kSeekForwardAvailable, 810 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD); 811 812 meta.appendBool( 813 Metadata::kSeekAvailable, 814 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK); 815 816 return OK; 817 } 818 819 void NuPlayerDriver::notifyResetComplete() { 820 ALOGD("notifyResetComplete(%p)", this); 821 Mutex::Autolock autoLock(mLock); 822 823 CHECK_EQ(mState, STATE_RESET_IN_PROGRESS); 824 mState = STATE_IDLE; 825 mCondition.broadcast(); 826 } 827 828 void NuPlayerDriver::notifySetSurfaceComplete() { 829 ALOGV("notifySetSurfaceComplete(%p)", this); 830 Mutex::Autolock autoLock(mLock); 831 832 CHECK(mSetSurfaceInProgress); 833 mSetSurfaceInProgress = false; 834 835 mCondition.broadcast(); 836 } 837 838 void NuPlayerDriver::notifyDuration(int64_t durationUs) { 839 Mutex::Autolock autoLock(mLock); 840 mDurationUs = durationUs; 841 } 842 843 void NuPlayerDriver::notifyMorePlayingTimeUs(int64_t playingUs) { 844 Mutex::Autolock autoLock(mLock); 845 mPlayingTimeUs += playingUs; 846 } 847 848 void NuPlayerDriver::notifyMoreRebufferingTimeUs(int64_t rebufferingUs) { 849 Mutex::Autolock autoLock(mLock); 850 mRebufferingTimeUs += rebufferingUs; 851 mRebufferingEvents++; 852 } 853 854 void NuPlayerDriver::notifyRebufferingWhenExit(bool status) { 855 Mutex::Autolock autoLock(mLock); 856 mRebufferingAtExit = status; 857 } 858 859 void NuPlayerDriver::notifySeekComplete() { 860 ALOGV("notifySeekComplete(%p)", this); 861 Mutex::Autolock autoLock(mLock); 862 mSeekInProgress = false; 863 notifySeekComplete_l(); 864 } 865 866 void NuPlayerDriver::notifySeekComplete_l() { 867 bool wasSeeking = true; 868 if (mState == STATE_STOPPED_AND_PREPARING) { 869 wasSeeking = false; 870 mState = STATE_STOPPED_AND_PREPARED; 871 mCondition.broadcast(); 872 if (!mIsAsyncPrepare) { 873 // if we are preparing synchronously, no need to notify listener 874 return; 875 } 876 } else if (mState == STATE_STOPPED) { 877 // no need to notify listener 878 return; 879 } 880 notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); 881 } 882 883 status_t NuPlayerDriver::dump( 884 int fd, const Vector<String16> & /* args */) const { 885 886 Vector<sp<AMessage> > trackStats; 887 mPlayer->getStats(&trackStats); 888 889 AString logString(" NuPlayer\n"); 890 char buf[256] = {0}; 891 892 bool locked = false; 893 for (int i = 0; i < kDumpLockRetries; ++i) { 894 if (mLock.tryLock() == NO_ERROR) { 895 locked = true; 896 break; 897 } 898 usleep(kDumpLockSleepUs); 899 } 900 901 if (locked) { 902 snprintf(buf, sizeof(buf), " state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n", 903 mState, mAtEOS, mLooping, mAutoLoop); 904 mLock.unlock(); 905 } else { 906 snprintf(buf, sizeof(buf), " NPD(%p) lock is taken\n", this); 907 } 908 logString.append(buf); 909 910 for (size_t i = 0; i < trackStats.size(); ++i) { 911 const sp<AMessage> &stats = trackStats.itemAt(i); 912 913 AString mime; 914 if (stats->findString("mime", &mime)) { 915 snprintf(buf, sizeof(buf), " mime(%s)\n", mime.c_str()); 916 logString.append(buf); 917 } 918 919 AString name; 920 if (stats->findString("component-name", &name)) { 921 snprintf(buf, sizeof(buf), " decoder(%s)\n", name.c_str()); 922 logString.append(buf); 923 } 924 925 if (mime.startsWith("video/")) { 926 int32_t width, height; 927 if (stats->findInt32("width", &width) 928 && stats->findInt32("height", &height)) { 929 snprintf(buf, sizeof(buf), " resolution(%d x %d)\n", width, height); 930 logString.append(buf); 931 } 932 933 int64_t numFramesTotal = 0; 934 int64_t numFramesDropped = 0; 935 936 stats->findInt64("frames-total", &numFramesTotal); 937 stats->findInt64("frames-dropped-output", &numFramesDropped); 938 snprintf(buf, sizeof(buf), " numFramesTotal(%lld), numFramesDropped(%lld), " 939 "percentageDropped(%.2f%%)\n", 940 (long long)numFramesTotal, 941 (long long)numFramesDropped, 942 numFramesTotal == 0 943 ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal); 944 logString.append(buf); 945 } 946 } 947 948 ALOGI("%s", logString.c_str()); 949 950 if (fd >= 0) { 951 FILE *out = fdopen(dup(fd), "w"); 952 fprintf(out, "%s", logString.c_str()); 953 fclose(out); 954 out = NULL; 955 } 956 957 return OK; 958 } 959 960 void NuPlayerDriver::notifyListener( 961 int msg, int ext1, int ext2, const Parcel *in) { 962 Mutex::Autolock autoLock(mLock); 963 notifyListener_l(msg, ext1, ext2, in); 964 } 965 966 void NuPlayerDriver::notifyListener_l( 967 int msg, int ext1, int ext2, const Parcel *in) { 968 ALOGV("notifyListener_l(%p), (%d, %d, %d, %d), loop setting(%d, %d)", 969 this, msg, ext1, ext2, (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping); 970 switch (msg) { 971 case MEDIA_PLAYBACK_COMPLETE: 972 { 973 if (mState != STATE_RESET_IN_PROGRESS) { 974 if (mAutoLoop) { 975 audio_stream_type_t streamType = AUDIO_STREAM_MUSIC; 976 if (mAudioSink != NULL) { 977 streamType = mAudioSink->getAudioStreamType(); 978 } 979 if (streamType == AUDIO_STREAM_NOTIFICATION) { 980 ALOGW("disabling auto-loop for notification"); 981 mAutoLoop = false; 982 } 983 } 984 if (mLooping || mAutoLoop) { 985 mPlayer->seekToAsync(0); 986 if (mAudioSink != NULL) { 987 // The renderer has stopped the sink at the end in order to play out 988 // the last little bit of audio. If we're looping, we need to restart it. 989 mAudioSink->start(); 990 } 991 // don't send completion event when looping 992 return; 993 } 994 if (property_get_bool("persist.debug.sf.stats", false)) { 995 Vector<String16> args; 996 dump(-1, args); 997 } 998 mPlayer->pause(); 999 mState = STATE_PAUSED; 1000 } 1001 FALLTHROUGH_INTENDED; 1002 } 1003 1004 case MEDIA_ERROR: 1005 { 1006 // when we have an error, add it to the analytics for this playback. 1007 // ext1 is our primary 'error type' value. Only add ext2 when non-zero. 1008 // [test against msg is due to fall through from previous switch value] 1009 if (msg == MEDIA_ERROR && mAnalyticsItem != NULL) { 1010 mAnalyticsItem->setInt32(kPlayerError, ext1); 1011 if (ext2 != 0) { 1012 mAnalyticsItem->setInt32(kPlayerErrorCode, ext2); 1013 } 1014 mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str()); 1015 } 1016 mAtEOS = true; 1017 break; 1018 } 1019 1020 default: 1021 break; 1022 } 1023 1024 mLock.unlock(); 1025 sendEvent(msg, ext1, ext2, in); 1026 mLock.lock(); 1027 } 1028 1029 void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) { 1030 Mutex::Autolock autoLock(mLock); 1031 1032 CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING); 1033 1034 mAsyncResult = err; 1035 mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE; 1036 mCondition.broadcast(); 1037 } 1038 1039 void NuPlayerDriver::notifyPrepareCompleted(status_t err) { 1040 ALOGV("notifyPrepareCompleted %d", err); 1041 1042 Mutex::Autolock autoLock(mLock); 1043 1044 if (mState != STATE_PREPARING) { 1045 // We were preparing asynchronously when the client called 1046 // reset(), we sent a premature "prepared" notification and 1047 // then initiated the reset. This notification is stale. 1048 CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE); 1049 return; 1050 } 1051 1052 CHECK_EQ(mState, STATE_PREPARING); 1053 1054 mAsyncResult = err; 1055 1056 if (err == OK) { 1057 // update state before notifying client, so that if client calls back into NuPlayerDriver 1058 // in response, NuPlayerDriver has the right state 1059 mState = STATE_PREPARED; 1060 if (mIsAsyncPrepare) { 1061 notifyListener_l(MEDIA_PREPARED); 1062 } 1063 } else { 1064 mState = STATE_UNPREPARED; 1065 if (mIsAsyncPrepare) { 1066 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 1067 } 1068 } 1069 1070 sp<MetaData> meta = mPlayer->getFileMeta(); 1071 int32_t loop; 1072 if (meta != NULL 1073 && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { 1074 mAutoLoop = true; 1075 } 1076 1077 mCondition.broadcast(); 1078 } 1079 1080 void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) { 1081 Mutex::Autolock autoLock(mLock); 1082 1083 mPlayerFlags = flags; 1084 } 1085 1086 // Modular DRM 1087 status_t NuPlayerDriver::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId) 1088 { 1089 ALOGV("prepareDrm(%p) state: %d", this, mState); 1090 1091 // leaving the state verification for mediaplayer.cpp 1092 status_t ret = mPlayer->prepareDrm(uuid, drmSessionId); 1093 1094 ALOGV("prepareDrm ret: %d", ret); 1095 1096 return ret; 1097 } 1098 1099 status_t NuPlayerDriver::releaseDrm() 1100 { 1101 ALOGV("releaseDrm(%p) state: %d", this, mState); 1102 1103 // leaving the state verification for mediaplayer.cpp 1104 status_t ret = mPlayer->releaseDrm(); 1105 1106 ALOGV("releaseDrm ret: %d", ret); 1107 1108 return ret; 1109 } 1110 1111 std::string NuPlayerDriver::stateString(State state) { 1112 const char *rval = NULL; 1113 char rawbuffer[16]; // allows "%d" 1114 1115 switch (state) { 1116 case STATE_IDLE: rval = "IDLE"; break; 1117 case STATE_SET_DATASOURCE_PENDING: rval = "SET_DATASOURCE_PENDING"; break; 1118 case STATE_UNPREPARED: rval = "UNPREPARED"; break; 1119 case STATE_PREPARING: rval = "PREPARING"; break; 1120 case STATE_PREPARED: rval = "PREPARED"; break; 1121 case STATE_RUNNING: rval = "RUNNING"; break; 1122 case STATE_PAUSED: rval = "PAUSED"; break; 1123 case STATE_RESET_IN_PROGRESS: rval = "RESET_IN_PROGRESS"; break; 1124 case STATE_STOPPED: rval = "STOPPED"; break; 1125 case STATE_STOPPED_AND_PREPARING: rval = "STOPPED_AND_PREPARING"; break; 1126 case STATE_STOPPED_AND_PREPARED: rval = "STOPPED_AND_PREPARED"; break; 1127 default: 1128 // yes, this buffer is shared and vulnerable to races 1129 snprintf(rawbuffer, sizeof(rawbuffer), "%d", state); 1130 rval = rawbuffer; 1131 break; 1132 } 1133 1134 return rval; 1135 } 1136 1137 } // namespace android 1138