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