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