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