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