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