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