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