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