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