AwesomePlayer.cpp revision 3d97e23fcd78f752443cb6c30a1ee39f49f1f987
1/*
2 * Copyright (C) 2009 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#undef DEBUG_HDCP
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "AwesomePlayer"
21#define ATRACE_TAG ATRACE_TAG_VIDEO
22#include <utils/Log.h>
23#include <utils/Trace.h>
24
25#include <dlfcn.h>
26
27#include "include/AwesomePlayer.h"
28#include "include/DRMExtractor.h"
29#include "include/SoftwareRenderer.h"
30#include "include/NuCachedSource2.h"
31#include "include/ThrottledSource.h"
32#include "include/MPEG2TSExtractor.h"
33#include "include/WVMExtractor.h"
34
35#include <binder/IPCThreadState.h>
36#include <binder/IServiceManager.h>
37#include <media/IMediaPlayerService.h>
38#include <media/stagefright/foundation/hexdump.h>
39#include <media/stagefright/foundation/ADebug.h>
40#include <media/stagefright/timedtext/TimedTextDriver.h>
41#include <media/stagefright/AudioPlayer.h>
42#include <media/stagefright/DataSource.h>
43#include <media/stagefright/FileSource.h>
44#include <media/stagefright/MediaBuffer.h>
45#include <media/stagefright/MediaDefs.h>
46#include <media/stagefright/MediaExtractor.h>
47#include <media/stagefright/MediaSource.h>
48#include <media/stagefright/MetaData.h>
49#include <media/stagefright/OMXCodec.h>
50#include <media/stagefright/Utils.h>
51
52#include <gui/IGraphicBufferProducer.h>
53#include <gui/Surface.h>
54
55#include <media/stagefright/foundation/AMessage.h>
56
57#include <cutils/properties.h>
58
59#define USE_SURFACE_ALLOC 1
60#define FRAME_DROP_FREQ 0
61
62namespace android {
63
64static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
65static int64_t kHighWaterMarkUs = 5000000ll;  // 5secs
66static const size_t kLowWaterMarkBytes = 40000;
67static const size_t kHighWaterMarkBytes = 200000;
68
69// maximum time in paused state when offloading audio decompression. When elapsed, the AudioPlayer
70// is destroyed to allow the audio DSP to power down.
71static int64_t kOffloadPauseMaxUs = 60000000ll;
72
73
74struct AwesomeEvent : public TimedEventQueue::Event {
75    AwesomeEvent(
76            AwesomePlayer *player,
77            void (AwesomePlayer::*method)())
78        : mPlayer(player),
79          mMethod(method) {
80    }
81
82protected:
83    virtual ~AwesomeEvent() {}
84
85    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
86        (mPlayer->*mMethod)();
87    }
88
89private:
90    AwesomePlayer *mPlayer;
91    void (AwesomePlayer::*mMethod)();
92
93    AwesomeEvent(const AwesomeEvent &);
94    AwesomeEvent &operator=(const AwesomeEvent &);
95};
96
97struct AwesomeLocalRenderer : public AwesomeRenderer {
98    AwesomeLocalRenderer(
99            const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
100        : mTarget(new SoftwareRenderer(nativeWindow, meta)) {
101    }
102
103    virtual void render(MediaBuffer *buffer) {
104        render((const uint8_t *)buffer->data() + buffer->range_offset(),
105               buffer->range_length());
106    }
107
108    void render(const void *data, size_t size) {
109        mTarget->render(data, size, NULL);
110    }
111
112protected:
113    virtual ~AwesomeLocalRenderer() {
114        delete mTarget;
115        mTarget = NULL;
116    }
117
118private:
119    SoftwareRenderer *mTarget;
120
121    AwesomeLocalRenderer(const AwesomeLocalRenderer &);
122    AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
123};
124
125struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
126    AwesomeNativeWindowRenderer(
127            const sp<ANativeWindow> &nativeWindow,
128            int32_t rotationDegrees)
129        : mNativeWindow(nativeWindow) {
130        applyRotation(rotationDegrees);
131    }
132
133    virtual void render(MediaBuffer *buffer) {
134        ATRACE_CALL();
135        int64_t timeUs;
136        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
137        native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000);
138        status_t err = mNativeWindow->queueBuffer(
139                mNativeWindow.get(), buffer->graphicBuffer().get(), -1);
140        if (err != 0) {
141            ALOGE("queueBuffer failed with error %s (%d)", strerror(-err),
142                    -err);
143            return;
144        }
145
146        sp<MetaData> metaData = buffer->meta_data();
147        metaData->setInt32(kKeyRendered, 1);
148    }
149
150protected:
151    virtual ~AwesomeNativeWindowRenderer() {}
152
153private:
154    sp<ANativeWindow> mNativeWindow;
155
156    void applyRotation(int32_t rotationDegrees) {
157        uint32_t transform;
158        switch (rotationDegrees) {
159            case 0: transform = 0; break;
160            case 90: transform = HAL_TRANSFORM_ROT_90; break;
161            case 180: transform = HAL_TRANSFORM_ROT_180; break;
162            case 270: transform = HAL_TRANSFORM_ROT_270; break;
163            default: transform = 0; break;
164        }
165
166        if (transform) {
167            CHECK_EQ(0, native_window_set_buffers_transform(
168                        mNativeWindow.get(), transform));
169        }
170    }
171
172    AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
173    AwesomeNativeWindowRenderer &operator=(
174            const AwesomeNativeWindowRenderer &);
175};
176
177// To collect the decoder usage
178void addBatteryData(uint32_t params) {
179    sp<IBinder> binder =
180        defaultServiceManager()->getService(String16("media.player"));
181    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
182    CHECK(service.get() != NULL);
183
184    service->addBatteryData(params);
185}
186
187////////////////////////////////////////////////////////////////////////////////
188AwesomePlayer::AwesomePlayer()
189    : mQueueStarted(false),
190      mUIDValid(false),
191      mTimeSource(NULL),
192      mVideoRenderingStarted(false),
193      mVideoRendererIsPreview(false),
194      mMediaRenderingStartGeneration(0),
195      mStartGeneration(0),
196      mAudioPlayer(NULL),
197      mDisplayWidth(0),
198      mDisplayHeight(0),
199      mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
200      mFlags(0),
201      mExtractorFlags(0),
202      mVideoBuffer(NULL),
203      mDecryptHandle(NULL),
204      mLastVideoTimeUs(-1),
205      mTextDriver(NULL),
206      mOffloadAudio(false),
207      mAudioTearDown(false) {
208    CHECK_EQ(mClient.connect(), (status_t)OK);
209
210    DataSource::RegisterDefaultSniffers();
211
212    mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
213    mVideoEventPending = false;
214    mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
215    mStreamDoneEventPending = false;
216    mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
217    mBufferingEventPending = false;
218    mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);
219    mVideoLagEventPending = false;
220
221    mCheckAudioStatusEvent = new AwesomeEvent(
222            this, &AwesomePlayer::onCheckAudioStatus);
223
224    mAudioStatusEventPending = false;
225
226    mAudioTearDownEvent = new AwesomeEvent(this,
227                              &AwesomePlayer::onAudioTearDownEvent);
228    mAudioTearDownEventPending = false;
229
230    reset();
231}
232
233AwesomePlayer::~AwesomePlayer() {
234    if (mQueueStarted) {
235        mQueue.stop();
236    }
237
238    reset();
239
240    mClient.disconnect();
241}
242
243void AwesomePlayer::cancelPlayerEvents(bool keepNotifications) {
244    mQueue.cancelEvent(mVideoEvent->eventID());
245    mVideoEventPending = false;
246    mQueue.cancelEvent(mVideoLagEvent->eventID());
247    mVideoLagEventPending = false;
248
249    if (mOffloadAudio) {
250        mQueue.cancelEvent(mAudioTearDownEvent->eventID());
251        mAudioTearDownEventPending = false;
252    }
253
254    if (!keepNotifications) {
255        mQueue.cancelEvent(mStreamDoneEvent->eventID());
256        mStreamDoneEventPending = false;
257        mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
258        mAudioStatusEventPending = false;
259
260        mQueue.cancelEvent(mBufferingEvent->eventID());
261        mBufferingEventPending = false;
262        mAudioTearDown = false;
263    }
264}
265
266void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
267    Mutex::Autolock autoLock(mLock);
268    mListener = listener;
269}
270
271void AwesomePlayer::setUID(uid_t uid) {
272    ALOGV("AwesomePlayer running on behalf of uid %d", uid);
273
274    mUID = uid;
275    mUIDValid = true;
276}
277
278status_t AwesomePlayer::setDataSource(
279        const char *uri, const KeyedVector<String8, String8> *headers) {
280    Mutex::Autolock autoLock(mLock);
281    return setDataSource_l(uri, headers);
282}
283
284status_t AwesomePlayer::setDataSource_l(
285        const char *uri, const KeyedVector<String8, String8> *headers) {
286    reset_l();
287
288    mUri = uri;
289
290    if (headers) {
291        mUriHeaders = *headers;
292
293        ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
294        if (index >= 0) {
295            // Browser is in "incognito" mode, suppress logging URLs.
296
297            // This isn't something that should be passed to the server.
298            mUriHeaders.removeItemsAt(index);
299
300            modifyFlags(INCOGNITO, SET);
301        }
302    }
303
304    ALOGI("setDataSource_l(URL suppressed)");
305
306    // The actual work will be done during preparation in the call to
307    // ::finishSetDataSource_l to avoid blocking the calling thread in
308    // setDataSource for any significant time.
309
310    {
311        Mutex::Autolock autoLock(mStatsLock);
312        mStats.mFd = -1;
313        mStats.mURI = mUri;
314    }
315
316    return OK;
317}
318
319status_t AwesomePlayer::setDataSource(
320        int fd, int64_t offset, int64_t length) {
321    Mutex::Autolock autoLock(mLock);
322
323    reset_l();
324
325    sp<DataSource> dataSource = new FileSource(fd, offset, length);
326
327    status_t err = dataSource->initCheck();
328
329    if (err != OK) {
330        return err;
331    }
332
333    mFileSource = dataSource;
334
335    {
336        Mutex::Autolock autoLock(mStatsLock);
337        mStats.mFd = fd;
338        mStats.mURI = String8();
339    }
340
341    return setDataSource_l(dataSource);
342}
343
344status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source) {
345    return INVALID_OPERATION;
346}
347
348status_t AwesomePlayer::setDataSource_l(
349        const sp<DataSource> &dataSource) {
350    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
351
352    if (extractor == NULL) {
353        return UNKNOWN_ERROR;
354    }
355
356    if (extractor->getDrmFlag()) {
357        checkDrmStatus(dataSource);
358    }
359
360    return setDataSource_l(extractor);
361}
362
363void AwesomePlayer::checkDrmStatus(const sp<DataSource>& dataSource) {
364    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
365    if (mDecryptHandle != NULL) {
366        CHECK(mDrmManagerClient);
367        if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
368            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
369        }
370    }
371}
372
373status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
374    // Attempt to approximate overall stream bitrate by summing all
375    // tracks' individual bitrates, if not all of them advertise bitrate,
376    // we have to fail.
377
378    int64_t totalBitRate = 0;
379
380    mExtractor = extractor;
381    for (size_t i = 0; i < extractor->countTracks(); ++i) {
382        sp<MetaData> meta = extractor->getTrackMetaData(i);
383
384        int32_t bitrate;
385        if (!meta->findInt32(kKeyBitRate, &bitrate)) {
386            const char *mime;
387            CHECK(meta->findCString(kKeyMIMEType, &mime));
388            ALOGV("track of type '%s' does not publish bitrate", mime);
389
390            totalBitRate = -1;
391            break;
392        }
393
394        totalBitRate += bitrate;
395    }
396
397    mBitrate = totalBitRate;
398
399    ALOGV("mBitrate = %lld bits/sec", mBitrate);
400
401    {
402        Mutex::Autolock autoLock(mStatsLock);
403        mStats.mBitrate = mBitrate;
404        mStats.mTracks.clear();
405        mStats.mAudioTrackIndex = -1;
406        mStats.mVideoTrackIndex = -1;
407    }
408
409    bool haveAudio = false;
410    bool haveVideo = false;
411    for (size_t i = 0; i < extractor->countTracks(); ++i) {
412        sp<MetaData> meta = extractor->getTrackMetaData(i);
413
414        const char *_mime;
415        CHECK(meta->findCString(kKeyMIMEType, &_mime));
416
417        String8 mime = String8(_mime);
418
419        if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) {
420            setVideoSource(extractor->getTrack(i));
421            haveVideo = true;
422
423            // Set the presentation/display size
424            int32_t displayWidth, displayHeight;
425            bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
426            if (success) {
427                success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
428            }
429            if (success) {
430                mDisplayWidth = displayWidth;
431                mDisplayHeight = displayHeight;
432            }
433
434            {
435                Mutex::Autolock autoLock(mStatsLock);
436                mStats.mVideoTrackIndex = mStats.mTracks.size();
437                mStats.mTracks.push();
438                TrackStat *stat =
439                    &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
440                stat->mMIME = mime.string();
441            }
442        } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) {
443            setAudioSource(extractor->getTrack(i));
444            haveAudio = true;
445            mActiveAudioTrackIndex = i;
446
447            {
448                Mutex::Autolock autoLock(mStatsLock);
449                mStats.mAudioTrackIndex = mStats.mTracks.size();
450                mStats.mTracks.push();
451                TrackStat *stat =
452                    &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
453                stat->mMIME = mime.string();
454            }
455
456            if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_AUDIO_VORBIS)) {
457                // Only do this for vorbis audio, none of the other audio
458                // formats even support this ringtone specific hack and
459                // retrieving the metadata on some extractors may turn out
460                // to be very expensive.
461                sp<MetaData> fileMeta = extractor->getMetaData();
462                int32_t loop;
463                if (fileMeta != NULL
464                        && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
465                    modifyFlags(AUTO_LOOPING, SET);
466                }
467            }
468        } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
469            addTextSource_l(i, extractor->getTrack(i));
470        }
471    }
472
473    if (!haveAudio && !haveVideo) {
474        if (mWVMExtractor != NULL) {
475            return mWVMExtractor->getError();
476        } else {
477            return UNKNOWN_ERROR;
478        }
479    }
480
481    mExtractorFlags = extractor->flags();
482
483    return OK;
484}
485
486void AwesomePlayer::reset() {
487    Mutex::Autolock autoLock(mLock);
488    reset_l();
489}
490
491void AwesomePlayer::reset_l() {
492    mVideoRenderingStarted = false;
493    mActiveAudioTrackIndex = -1;
494    mDisplayWidth = 0;
495    mDisplayHeight = 0;
496
497    notifyListener_l(MEDIA_STOPPED);
498
499    if (mDecryptHandle != NULL) {
500            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
501                    Playback::STOP, 0);
502            mDecryptHandle = NULL;
503            mDrmManagerClient = NULL;
504    }
505
506    if (mFlags & PLAYING) {
507        uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
508        if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
509            params |= IMediaPlayerService::kBatteryDataTrackAudio;
510        }
511        if (mVideoSource != NULL) {
512            params |= IMediaPlayerService::kBatteryDataTrackVideo;
513        }
514        addBatteryData(params);
515    }
516
517    if (mFlags & PREPARING) {
518        modifyFlags(PREPARE_CANCELLED, SET);
519        if (mConnectingDataSource != NULL) {
520            ALOGI("interrupting the connection process");
521            mConnectingDataSource->disconnect();
522        }
523
524        if (mFlags & PREPARING_CONNECTED) {
525            // We are basically done preparing, we're just buffering
526            // enough data to start playback, we can safely interrupt that.
527            finishAsyncPrepare_l();
528        }
529    }
530
531    while (mFlags & PREPARING) {
532        mPreparedCondition.wait(mLock);
533    }
534
535    cancelPlayerEvents();
536
537    mWVMExtractor.clear();
538    mCachedSource.clear();
539    mAudioTrack.clear();
540    mVideoTrack.clear();
541    mExtractor.clear();
542
543    // Shutdown audio first, so that the response to the reset request
544    // appears to happen instantaneously as far as the user is concerned
545    // If we did this later, audio would continue playing while we
546    // shutdown the video-related resources and the player appear to
547    // not be as responsive to a reset request.
548    if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
549            && mAudioSource != NULL) {
550        // If we had an audio player, it would have effectively
551        // taken possession of the audio source and stopped it when
552        // _it_ is stopped. Otherwise this is still our responsibility.
553        mAudioSource->stop();
554    }
555    mAudioSource.clear();
556    mOmxSource.clear();
557
558    mTimeSource = NULL;
559
560    delete mAudioPlayer;
561    mAudioPlayer = NULL;
562
563    if (mTextDriver != NULL) {
564        delete mTextDriver;
565        mTextDriver = NULL;
566    }
567
568    mVideoRenderer.clear();
569
570    if (mVideoSource != NULL) {
571        shutdownVideoDecoder_l();
572    }
573
574    mDurationUs = -1;
575    modifyFlags(0, ASSIGN);
576    mExtractorFlags = 0;
577    mTimeSourceDeltaUs = 0;
578    mVideoTimeUs = 0;
579
580    mSeeking = NO_SEEK;
581    mSeekNotificationSent = true;
582    mSeekTimeUs = 0;
583
584    mUri.setTo("");
585    mUriHeaders.clear();
586
587    mFileSource.clear();
588
589    mBitrate = -1;
590    mLastVideoTimeUs = -1;
591
592    {
593        Mutex::Autolock autoLock(mStatsLock);
594        mStats.mFd = -1;
595        mStats.mURI = String8();
596        mStats.mBitrate = -1;
597        mStats.mAudioTrackIndex = -1;
598        mStats.mVideoTrackIndex = -1;
599        mStats.mNumVideoFramesDecoded = 0;
600        mStats.mNumVideoFramesDropped = 0;
601        mStats.mVideoWidth = -1;
602        mStats.mVideoHeight = -1;
603        mStats.mFlags = 0;
604        mStats.mTracks.clear();
605    }
606
607    mWatchForAudioSeekComplete = false;
608    mWatchForAudioEOS = false;
609}
610
611void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
612    if ((mListener != NULL) && !mAudioTearDown) {
613        sp<MediaPlayerBase> listener = mListener.promote();
614
615        if (listener != NULL) {
616            listener->sendEvent(msg, ext1, ext2);
617        }
618    }
619}
620
621bool AwesomePlayer::getBitrate(int64_t *bitrate) {
622    off64_t size;
623    if (mDurationUs > 0 && mCachedSource != NULL
624            && mCachedSource->getSize(&size) == OK) {
625        *bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
626        return true;
627    }
628
629    if (mBitrate >= 0) {
630        *bitrate = mBitrate;
631        return true;
632    }
633
634    *bitrate = 0;
635
636    return false;
637}
638
639// Returns true iff cached duration is available/applicable.
640bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
641    int64_t bitrate;
642
643    if (mCachedSource != NULL && getBitrate(&bitrate) && (bitrate > 0)) {
644        status_t finalStatus;
645        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
646        *durationUs = cachedDataRemaining * 8000000ll / bitrate;
647        *eos = (finalStatus != OK);
648        return true;
649    } else if (mWVMExtractor != NULL) {
650        status_t finalStatus;
651        *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus);
652        *eos = (finalStatus != OK);
653        return true;
654    }
655
656    return false;
657}
658
659void AwesomePlayer::ensureCacheIsFetching_l() {
660    if (mCachedSource != NULL) {
661        mCachedSource->resumeFetchingIfNecessary();
662    }
663}
664
665void AwesomePlayer::onVideoLagUpdate() {
666    Mutex::Autolock autoLock(mLock);
667    if (!mVideoLagEventPending) {
668        return;
669    }
670    mVideoLagEventPending = false;
671
672    int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs();
673    int64_t videoLateByUs = audioTimeUs - mVideoTimeUs;
674
675    if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) {
676        ALOGV("video late by %lld ms.", videoLateByUs / 1000ll);
677
678        notifyListener_l(
679                MEDIA_INFO,
680                MEDIA_INFO_VIDEO_TRACK_LAGGING,
681                videoLateByUs / 1000ll);
682    }
683
684    postVideoLagEvent_l();
685}
686
687void AwesomePlayer::onBufferingUpdate() {
688    Mutex::Autolock autoLock(mLock);
689    if (!mBufferingEventPending) {
690        return;
691    }
692    mBufferingEventPending = false;
693
694    if (mCachedSource != NULL) {
695        status_t finalStatus;
696        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
697        bool eos = (finalStatus != OK);
698
699        if (eos) {
700            if (finalStatus == ERROR_END_OF_STREAM) {
701                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
702            }
703            if (mFlags & PREPARING) {
704                ALOGV("cache has reached EOS, prepare is done.");
705                finishAsyncPrepare_l();
706            }
707        } else {
708            int64_t bitrate;
709            if (getBitrate(&bitrate)) {
710                size_t cachedSize = mCachedSource->cachedSize();
711                int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
712
713                int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
714                if (percentage > 100) {
715                    percentage = 100;
716                }
717
718                notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
719            } else {
720                // We don't know the bitrate of the stream, use absolute size
721                // limits to maintain the cache.
722
723                if ((mFlags & PLAYING) && !eos
724                        && (cachedDataRemaining < kLowWaterMarkBytes)) {
725                    ALOGI("cache is running low (< %d) , pausing.",
726                         kLowWaterMarkBytes);
727                    modifyFlags(CACHE_UNDERRUN, SET);
728                    pause_l();
729                    ensureCacheIsFetching_l();
730                    sendCacheStats();
731                    notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
732                } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
733                    if (mFlags & CACHE_UNDERRUN) {
734                        ALOGI("cache has filled up (> %d), resuming.",
735                             kHighWaterMarkBytes);
736                        modifyFlags(CACHE_UNDERRUN, CLEAR);
737                        play_l();
738                    } else if (mFlags & PREPARING) {
739                        ALOGV("cache has filled up (> %d), prepare is done",
740                             kHighWaterMarkBytes);
741                        finishAsyncPrepare_l();
742                    }
743                }
744            }
745        }
746    } else if (mWVMExtractor != NULL) {
747        status_t finalStatus;
748
749        int64_t cachedDurationUs
750            = mWVMExtractor->getCachedDurationUs(&finalStatus);
751
752        bool eos = (finalStatus != OK);
753
754        if (eos) {
755            if (finalStatus == ERROR_END_OF_STREAM) {
756                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
757            }
758            if (mFlags & PREPARING) {
759                ALOGV("cache has reached EOS, prepare is done.");
760                finishAsyncPrepare_l();
761            }
762        } else {
763            int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
764            if (percentage > 100) {
765                percentage = 100;
766            }
767
768            notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
769        }
770    }
771
772    int64_t cachedDurationUs;
773    bool eos;
774    if (getCachedDuration_l(&cachedDurationUs, &eos)) {
775        ALOGV("cachedDurationUs = %.2f secs, eos=%d",
776             cachedDurationUs / 1E6, eos);
777
778        if ((mFlags & PLAYING) && !eos
779                && (cachedDurationUs < kLowWaterMarkUs)) {
780            modifyFlags(CACHE_UNDERRUN, SET);
781            ALOGI("cache is running low (%.2f secs) , pausing.",
782                  cachedDurationUs / 1E6);
783            pause_l();
784            ensureCacheIsFetching_l();
785            sendCacheStats();
786            notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
787        } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
788            if (mFlags & CACHE_UNDERRUN) {
789                modifyFlags(CACHE_UNDERRUN, CLEAR);
790                ALOGI("cache has filled up (%.2f secs), resuming.",
791                      cachedDurationUs / 1E6);
792                play_l();
793            } else if (mFlags & PREPARING) {
794                ALOGV("cache has filled up (%.2f secs), prepare is done",
795                     cachedDurationUs / 1E6);
796                finishAsyncPrepare_l();
797            }
798        }
799    }
800
801    postBufferingEvent_l();
802}
803
804void AwesomePlayer::sendCacheStats() {
805    sp<MediaPlayerBase> listener = mListener.promote();
806    if (listener != NULL) {
807        int32_t kbps = 0;
808        status_t err = UNKNOWN_ERROR;
809        if (mCachedSource != NULL) {
810            err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
811        } else if (mWVMExtractor != NULL) {
812            err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
813        }
814        if (err == OK) {
815            listener->sendEvent(
816                MEDIA_INFO, MEDIA_INFO_NETWORK_BANDWIDTH, kbps);
817        }
818    }
819}
820
821void AwesomePlayer::onStreamDone() {
822    // Posted whenever any stream finishes playing.
823    ATRACE_CALL();
824
825    Mutex::Autolock autoLock(mLock);
826    if (!mStreamDoneEventPending) {
827        return;
828    }
829    mStreamDoneEventPending = false;
830
831    if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
832        ALOGV("MEDIA_ERROR %d", mStreamDoneStatus);
833
834        notifyListener_l(
835                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
836
837        pause_l(true /* at eos */);
838
839        modifyFlags(AT_EOS, SET);
840        return;
841    }
842
843    const bool allDone =
844        (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
845            && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
846
847    if (!allDone) {
848        return;
849    }
850
851    if ((mFlags & LOOPING)
852            || ((mFlags & AUTO_LOOPING)
853                && (mAudioSink == NULL || mAudioSink->realtime()))) {
854        // Don't AUTO_LOOP if we're being recorded, since that cannot be
855        // turned off and recording would go on indefinitely.
856
857        seekTo_l(0);
858
859        if (mVideoSource != NULL) {
860            postVideoEvent_l();
861        }
862    } else {
863        ALOGV("MEDIA_PLAYBACK_COMPLETE");
864        notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
865
866        pause_l(true /* at eos */);
867
868        // If audio hasn't completed MEDIA_SEEK_COMPLETE yet,
869        // notify MEDIA_SEEK_COMPLETE to observer immediately for state persistence.
870        if (mWatchForAudioSeekComplete) {
871            notifyListener_l(MEDIA_SEEK_COMPLETE);
872            mWatchForAudioSeekComplete = false;
873        }
874
875        modifyFlags(AT_EOS, SET);
876    }
877}
878
879status_t AwesomePlayer::play() {
880    ATRACE_CALL();
881
882    Mutex::Autolock autoLock(mLock);
883
884    modifyFlags(CACHE_UNDERRUN, CLEAR);
885
886    return play_l();
887}
888
889status_t AwesomePlayer::play_l() {
890    modifyFlags(SEEK_PREVIEW, CLEAR);
891
892    if (mFlags & PLAYING) {
893        return OK;
894    }
895
896    if (!(mFlags & PREPARED)) {
897        status_t err = prepare_l();
898
899        if (err != OK) {
900            return err;
901        }
902    }
903
904    modifyFlags(PLAYING, SET);
905    modifyFlags(FIRST_FRAME, SET);
906
907    if (mDecryptHandle != NULL) {
908        int64_t position;
909        getPosition(&position);
910        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
911                Playback::START, position / 1000);
912    }
913
914    if (mAudioSource != NULL) {
915        if (mAudioPlayer == NULL) {
916            createAudioPlayer_l();
917        }
918
919        CHECK(!(mFlags & AUDIO_RUNNING));
920
921        if (mVideoSource == NULL) {
922
923            // We don't want to post an error notification at this point,
924            // the error returned from MediaPlayer::start() will suffice.
925
926            status_t err = startAudioPlayer_l(
927                    false /* sendErrorNotification */);
928
929            if ((err != OK) && mOffloadAudio) {
930                ALOGI("play_l() cannot create offload output, fallback to sw decode");
931                int64_t curTimeUs;
932                getPosition(&curTimeUs);
933
934                delete mAudioPlayer;
935                mAudioPlayer = NULL;
936                // if the player was started it will take care of stopping the source when destroyed
937                if (!(mFlags & AUDIOPLAYER_STARTED)) {
938                    mAudioSource->stop();
939                }
940                modifyFlags((AUDIO_RUNNING | AUDIOPLAYER_STARTED), CLEAR);
941                mOffloadAudio = false;
942                mAudioSource = mOmxSource;
943                if (mAudioSource != NULL) {
944                    err = mAudioSource->start();
945
946                    if (err != OK) {
947                        mAudioSource.clear();
948                    } else {
949                        mSeekNotificationSent = true;
950                        if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
951                            seekTo_l(curTimeUs);
952                        }
953                        createAudioPlayer_l();
954                        err = startAudioPlayer_l(false);
955                    }
956                }
957            }
958
959            if (err != OK) {
960                delete mAudioPlayer;
961                mAudioPlayer = NULL;
962
963                modifyFlags((PLAYING | FIRST_FRAME), CLEAR);
964
965                if (mDecryptHandle != NULL) {
966                    mDrmManagerClient->setPlaybackStatus(
967                            mDecryptHandle, Playback::STOP, 0);
968                }
969
970                return err;
971            }
972        }
973    }
974
975    if (mTimeSource == NULL && mAudioPlayer == NULL) {
976        mTimeSource = &mSystemTimeSource;
977    }
978
979    if (mVideoSource != NULL) {
980        // Kick off video playback
981        postVideoEvent_l();
982
983        if (mAudioSource != NULL && mVideoSource != NULL) {
984            postVideoLagEvent_l();
985        }
986    }
987
988    if (mFlags & AT_EOS) {
989        // Legacy behaviour, if a stream finishes playing and then
990        // is started again, we play from the start...
991        seekTo_l(0);
992    }
993
994    uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted
995        | IMediaPlayerService::kBatteryDataTrackDecoder;
996    if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
997        params |= IMediaPlayerService::kBatteryDataTrackAudio;
998    }
999    if (mVideoSource != NULL) {
1000        params |= IMediaPlayerService::kBatteryDataTrackVideo;
1001    }
1002    addBatteryData(params);
1003
1004    return OK;
1005}
1006
1007void AwesomePlayer::createAudioPlayer_l()
1008{
1009    uint32_t flags = 0;
1010    int64_t cachedDurationUs;
1011    bool eos;
1012
1013    if (mOffloadAudio) {
1014        flags |= AudioPlayer::USE_OFFLOAD;
1015    } else if (mVideoSource == NULL
1016            && (mDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US ||
1017            (getCachedDuration_l(&cachedDurationUs, &eos) &&
1018            cachedDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US))) {
1019        flags |= AudioPlayer::ALLOW_DEEP_BUFFERING;
1020    }
1021    if (isStreamingHTTP()) {
1022        flags |= AudioPlayer::IS_STREAMING;
1023    }
1024    if (mVideoSource != NULL) {
1025        flags |= AudioPlayer::HAS_VIDEO;
1026    }
1027
1028    mAudioPlayer = new AudioPlayer(mAudioSink, flags, this);
1029    mAudioPlayer->setSource(mAudioSource);
1030
1031    mTimeSource = mAudioPlayer;
1032
1033    // If there was a seek request before we ever started,
1034    // honor the request now.
1035    // Make sure to do this before starting the audio player
1036    // to avoid a race condition.
1037    seekAudioIfNecessary_l();
1038}
1039
1040void AwesomePlayer::notifyIfMediaStarted_l() {
1041    if (mMediaRenderingStartGeneration == mStartGeneration) {
1042        mMediaRenderingStartGeneration = -1;
1043        notifyListener_l(MEDIA_STARTED);
1044    }
1045}
1046
1047status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) {
1048    CHECK(!(mFlags & AUDIO_RUNNING));
1049    status_t err = OK;
1050
1051    if (mAudioSource == NULL || mAudioPlayer == NULL) {
1052        return OK;
1053    }
1054
1055    if (mOffloadAudio) {
1056        mQueue.cancelEvent(mAudioTearDownEvent->eventID());
1057        mAudioTearDownEventPending = false;
1058    }
1059
1060    if (!(mFlags & AUDIOPLAYER_STARTED)) {
1061        bool wasSeeking = mAudioPlayer->isSeeking();
1062
1063        // We've already started the MediaSource in order to enable
1064        // the prefetcher to read its data.
1065        err = mAudioPlayer->start(
1066                true /* sourceAlreadyStarted */);
1067
1068        if (err != OK) {
1069            if (sendErrorNotification) {
1070                notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1071            }
1072
1073            return err;
1074        }
1075
1076        modifyFlags(AUDIOPLAYER_STARTED, SET);
1077
1078        if (wasSeeking) {
1079            CHECK(!mAudioPlayer->isSeeking());
1080
1081            // We will have finished the seek while starting the audio player.
1082            postAudioSeekComplete();
1083        } else {
1084            notifyIfMediaStarted_l();
1085        }
1086    } else {
1087        err = mAudioPlayer->resume();
1088    }
1089
1090    if (err == OK) {
1091        modifyFlags(AUDIO_RUNNING, SET);
1092
1093        mWatchForAudioEOS = true;
1094    }
1095
1096    return err;
1097}
1098
1099void AwesomePlayer::notifyVideoSize_l() {
1100    ATRACE_CALL();
1101    sp<MetaData> meta = mVideoSource->getFormat();
1102
1103    int32_t cropLeft, cropTop, cropRight, cropBottom;
1104    if (!meta->findRect(
1105                kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
1106        int32_t width, height;
1107        CHECK(meta->findInt32(kKeyWidth, &width));
1108        CHECK(meta->findInt32(kKeyHeight, &height));
1109
1110        cropLeft = cropTop = 0;
1111        cropRight = width - 1;
1112        cropBottom = height - 1;
1113
1114        ALOGV("got dimensions only %d x %d", width, height);
1115    } else {
1116        ALOGV("got crop rect %d, %d, %d, %d",
1117             cropLeft, cropTop, cropRight, cropBottom);
1118    }
1119
1120    int32_t displayWidth;
1121    if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
1122        ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
1123        mDisplayWidth = displayWidth;
1124    }
1125    int32_t displayHeight;
1126    if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
1127        ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight);
1128        mDisplayHeight = displayHeight;
1129    }
1130
1131    int32_t usableWidth = cropRight - cropLeft + 1;
1132    int32_t usableHeight = cropBottom - cropTop + 1;
1133    if (mDisplayWidth != 0) {
1134        usableWidth = mDisplayWidth;
1135    }
1136    if (mDisplayHeight != 0) {
1137        usableHeight = mDisplayHeight;
1138    }
1139
1140    {
1141        Mutex::Autolock autoLock(mStatsLock);
1142        mStats.mVideoWidth = usableWidth;
1143        mStats.mVideoHeight = usableHeight;
1144    }
1145
1146    int32_t rotationDegrees;
1147    if (!mVideoTrack->getFormat()->findInt32(
1148                kKeyRotation, &rotationDegrees)) {
1149        rotationDegrees = 0;
1150    }
1151
1152    if (rotationDegrees == 90 || rotationDegrees == 270) {
1153        notifyListener_l(
1154                MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
1155    } else {
1156        notifyListener_l(
1157                MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
1158    }
1159}
1160
1161void AwesomePlayer::initRenderer_l() {
1162    ATRACE_CALL();
1163
1164    if (mNativeWindow == NULL) {
1165        return;
1166    }
1167
1168    sp<MetaData> meta = mVideoSource->getFormat();
1169
1170    int32_t format;
1171    const char *component;
1172    int32_t decodedWidth, decodedHeight;
1173    CHECK(meta->findInt32(kKeyColorFormat, &format));
1174    CHECK(meta->findCString(kKeyDecoderComponent, &component));
1175    CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
1176    CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
1177
1178    int32_t rotationDegrees;
1179    if (!mVideoTrack->getFormat()->findInt32(
1180                kKeyRotation, &rotationDegrees)) {
1181        rotationDegrees = 0;
1182    }
1183
1184    mVideoRenderer.clear();
1185
1186    // Must ensure that mVideoRenderer's destructor is actually executed
1187    // before creating a new one.
1188    IPCThreadState::self()->flushCommands();
1189
1190    // Even if set scaling mode fails, we will continue anyway
1191    setVideoScalingMode_l(mVideoScalingMode);
1192    if (USE_SURFACE_ALLOC
1193            && !strncmp(component, "OMX.", 4)
1194            && strncmp(component, "OMX.google.", 11)
1195            && strcmp(component, "OMX.Nvidia.mpeg2v.decode")) {
1196        // Hardware decoders avoid the CPU color conversion by decoding
1197        // directly to ANativeBuffers, so we must use a renderer that
1198        // just pushes those buffers to the ANativeWindow.
1199        mVideoRenderer =
1200            new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);
1201    } else {
1202        // Other decoders are instantiated locally and as a consequence
1203        // allocate their buffers in local address space.  This renderer
1204        // then performs a color conversion and copy to get the data
1205        // into the ANativeBuffer.
1206        mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta);
1207    }
1208}
1209
1210status_t AwesomePlayer::pause() {
1211    ATRACE_CALL();
1212
1213    Mutex::Autolock autoLock(mLock);
1214
1215    modifyFlags(CACHE_UNDERRUN, CLEAR);
1216
1217    return pause_l();
1218}
1219
1220status_t AwesomePlayer::pause_l(bool at_eos) {
1221    if (!(mFlags & PLAYING)) {
1222        return OK;
1223    }
1224
1225    notifyListener_l(MEDIA_PAUSED);
1226    mMediaRenderingStartGeneration = ++mStartGeneration;
1227
1228    cancelPlayerEvents(true /* keepNotifications */);
1229
1230    if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
1231        // If we played the audio stream to completion we
1232        // want to make sure that all samples remaining in the audio
1233        // track's queue are played out.
1234        mAudioPlayer->pause(at_eos /* playPendingSamples */);
1235        // send us a reminder to tear down the AudioPlayer if paused for too long.
1236        if (mOffloadAudio) {
1237            postAudioTearDownEvent(kOffloadPauseMaxUs);
1238        }
1239        modifyFlags(AUDIO_RUNNING, CLEAR);
1240    }
1241
1242    if (mFlags & TEXTPLAYER_INITIALIZED) {
1243        mTextDriver->pause();
1244        modifyFlags(TEXT_RUNNING, CLEAR);
1245    }
1246
1247    modifyFlags(PLAYING, CLEAR);
1248
1249    if (mDecryptHandle != NULL) {
1250        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1251                Playback::PAUSE, 0);
1252    }
1253
1254    uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
1255    if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
1256        params |= IMediaPlayerService::kBatteryDataTrackAudio;
1257    }
1258    if (mVideoSource != NULL) {
1259        params |= IMediaPlayerService::kBatteryDataTrackVideo;
1260    }
1261
1262    addBatteryData(params);
1263
1264    return OK;
1265}
1266
1267bool AwesomePlayer::isPlaying() const {
1268    return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
1269}
1270
1271status_t AwesomePlayer::setSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer) {
1272    Mutex::Autolock autoLock(mLock);
1273
1274    status_t err;
1275    if (bufferProducer != NULL) {
1276        err = setNativeWindow_l(new Surface(bufferProducer));
1277    } else {
1278        err = setNativeWindow_l(NULL);
1279    }
1280
1281    return err;
1282}
1283
1284void AwesomePlayer::shutdownVideoDecoder_l() {
1285    if (mVideoBuffer) {
1286        mVideoBuffer->release();
1287        mVideoBuffer = NULL;
1288    }
1289
1290    mVideoSource->stop();
1291
1292    // The following hack is necessary to ensure that the OMX
1293    // component is completely released by the time we may try
1294    // to instantiate it again.
1295    wp<MediaSource> tmp = mVideoSource;
1296    mVideoSource.clear();
1297    while (tmp.promote() != NULL) {
1298        usleep(1000);
1299    }
1300    IPCThreadState::self()->flushCommands();
1301    ALOGV("video decoder shutdown completed");
1302}
1303
1304status_t AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
1305    mNativeWindow = native;
1306
1307    if (mVideoSource == NULL) {
1308        return OK;
1309    }
1310
1311    ALOGV("attempting to reconfigure to use new surface");
1312
1313    bool wasPlaying = (mFlags & PLAYING) != 0;
1314
1315    pause_l();
1316    mVideoRenderer.clear();
1317
1318    shutdownVideoDecoder_l();
1319
1320    status_t err = initVideoDecoder();
1321
1322    if (err != OK) {
1323        ALOGE("failed to reinstantiate video decoder after surface change.");
1324        return err;
1325    }
1326
1327    if (mLastVideoTimeUs >= 0) {
1328        mSeeking = SEEK;
1329        mSeekTimeUs = mLastVideoTimeUs;
1330        modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
1331    }
1332
1333    if (wasPlaying) {
1334        play_l();
1335    }
1336
1337    return OK;
1338}
1339
1340void AwesomePlayer::setAudioSink(
1341        const sp<MediaPlayerBase::AudioSink> &audioSink) {
1342    Mutex::Autolock autoLock(mLock);
1343
1344    mAudioSink = audioSink;
1345}
1346
1347status_t AwesomePlayer::setLooping(bool shouldLoop) {
1348    Mutex::Autolock autoLock(mLock);
1349
1350    modifyFlags(LOOPING, CLEAR);
1351
1352    if (shouldLoop) {
1353        modifyFlags(LOOPING, SET);
1354    }
1355
1356    return OK;
1357}
1358
1359status_t AwesomePlayer::getDuration(int64_t *durationUs) {
1360    Mutex::Autolock autoLock(mMiscStateLock);
1361
1362    if (mDurationUs < 0) {
1363        return UNKNOWN_ERROR;
1364    }
1365
1366    *durationUs = mDurationUs;
1367
1368    return OK;
1369}
1370
1371status_t AwesomePlayer::getPosition(int64_t *positionUs) {
1372    if (mSeeking != NO_SEEK) {
1373        *positionUs = mSeekTimeUs;
1374    } else if (mVideoSource != NULL
1375            && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
1376        Mutex::Autolock autoLock(mMiscStateLock);
1377        *positionUs = mVideoTimeUs;
1378    } else if (mAudioPlayer != NULL) {
1379        *positionUs = mAudioPlayer->getMediaTimeUs();
1380    } else {
1381        *positionUs = 0;
1382    }
1383    return OK;
1384}
1385
1386status_t AwesomePlayer::seekTo(int64_t timeUs) {
1387    ATRACE_CALL();
1388
1389    if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
1390        Mutex::Autolock autoLock(mLock);
1391        return seekTo_l(timeUs);
1392    }
1393
1394    return OK;
1395}
1396
1397status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
1398    if (mFlags & CACHE_UNDERRUN) {
1399        modifyFlags(CACHE_UNDERRUN, CLEAR);
1400        play_l();
1401    }
1402
1403    if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) {
1404        // Video playback completed before, there's no pending
1405        // video event right now. In order for this new seek
1406        // to be honored, we need to post one.
1407
1408        postVideoEvent_l();
1409    }
1410
1411    mSeeking = SEEK;
1412    mSeekNotificationSent = false;
1413    mSeekTimeUs = timeUs;
1414    modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
1415
1416    notifyListener_l(MEDIA_PAUSED);
1417    mMediaRenderingStartGeneration = ++mStartGeneration;
1418
1419    seekAudioIfNecessary_l();
1420
1421    if (mFlags & TEXTPLAYER_INITIALIZED) {
1422        mTextDriver->seekToAsync(mSeekTimeUs);
1423    }
1424
1425    if (!(mFlags & PLAYING)) {
1426        ALOGV("seeking while paused, sending SEEK_COMPLETE notification"
1427             " immediately.");
1428
1429        notifyListener_l(MEDIA_SEEK_COMPLETE);
1430        mSeekNotificationSent = true;
1431
1432        if ((mFlags & PREPARED) && mVideoSource != NULL) {
1433            modifyFlags(SEEK_PREVIEW, SET);
1434            postVideoEvent_l();
1435        }
1436    }
1437
1438    return OK;
1439}
1440
1441void AwesomePlayer::seekAudioIfNecessary_l() {
1442    if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) {
1443        mAudioPlayer->seekTo(mSeekTimeUs);
1444
1445        mWatchForAudioSeekComplete = true;
1446        mWatchForAudioEOS = true;
1447
1448        if (mDecryptHandle != NULL) {
1449            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1450                    Playback::PAUSE, 0);
1451            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1452                    Playback::START, mSeekTimeUs / 1000);
1453        }
1454    }
1455}
1456
1457void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
1458    CHECK(source != NULL);
1459
1460    mAudioTrack = source;
1461}
1462
1463void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp<MediaSource>& source) {
1464    CHECK(source != NULL);
1465
1466    if (mTextDriver == NULL) {
1467        mTextDriver = new TimedTextDriver(mListener);
1468    }
1469
1470    mTextDriver->addInBandTextSource(trackIndex, source);
1471}
1472
1473status_t AwesomePlayer::initAudioDecoder() {
1474    ATRACE_CALL();
1475
1476    sp<MetaData> meta = mAudioTrack->getFormat();
1477
1478    const char *mime;
1479    CHECK(meta->findCString(kKeyMIMEType, &mime));
1480    // Check whether there is a hardware codec for this stream
1481    // This doesn't guarantee that the hardware has a free stream
1482    // but it avoids us attempting to open (and re-open) an offload
1483    // stream to hardware that doesn't have the necessary codec
1484    mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL), isStreamingHTTP());
1485
1486    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
1487        ALOGV("createAudioPlayer: bypass OMX (raw)");
1488        mAudioSource = mAudioTrack;
1489    } else {
1490        // If offloading we still create a OMX decoder as a fall-back
1491        // but we don't start it
1492        mOmxSource = OMXCodec::Create(
1493                mClient.interface(), mAudioTrack->getFormat(),
1494                false, // createEncoder
1495                mAudioTrack);
1496
1497        if (mOffloadAudio) {
1498            ALOGV("createAudioPlayer: bypass OMX (offload)");
1499            mAudioSource = mAudioTrack;
1500        } else {
1501            mAudioSource = mOmxSource;
1502        }
1503    }
1504
1505    if (mAudioSource != NULL) {
1506        int64_t durationUs;
1507        if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1508            Mutex::Autolock autoLock(mMiscStateLock);
1509            if (mDurationUs < 0 || durationUs > mDurationUs) {
1510                mDurationUs = durationUs;
1511            }
1512        }
1513
1514        status_t err = mAudioSource->start();
1515
1516        if (err != OK) {
1517            mAudioSource.clear();
1518            mOmxSource.clear();
1519            return err;
1520        }
1521    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1522        // For legacy reasons we're simply going to ignore the absence
1523        // of an audio decoder for QCELP instead of aborting playback
1524        // altogether.
1525        return OK;
1526    }
1527
1528    if (mAudioSource != NULL) {
1529        Mutex::Autolock autoLock(mStatsLock);
1530        TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
1531        const char *component;
1532        if (!mAudioSource->getFormat()
1533                ->findCString(kKeyDecoderComponent, &component)) {
1534            component = "none";
1535        }
1536
1537        stat->mDecoderName = component;
1538    }
1539
1540    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1541}
1542
1543void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1544    CHECK(source != NULL);
1545
1546    mVideoTrack = source;
1547}
1548
1549status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
1550    ATRACE_CALL();
1551
1552    // Either the application or the DRM system can independently say
1553    // that there must be a hardware-protected path to an external video sink.
1554    // For now we always require a hardware-protected path to external video sink
1555    // if content is DRMed, but eventually this could be optional per DRM agent.
1556    // When the application wants protection, then
1557    //   (USE_SURFACE_ALLOC && (mSurface != 0) &&
1558    //   (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp))
1559    // will be true, but that part is already handled by SurfaceFlinger.
1560
1561#ifdef DEBUG_HDCP
1562    // For debugging, we allow a system property to control the protected usage.
1563    // In case of uninitialized or unexpected property, we default to "DRM only".
1564    bool setProtectionBit = false;
1565    char value[PROPERTY_VALUE_MAX];
1566    if (property_get("persist.sys.hdcp_checking", value, NULL)) {
1567        if (!strcmp(value, "never")) {
1568            // nop
1569        } else if (!strcmp(value, "always")) {
1570            setProtectionBit = true;
1571        } else if (!strcmp(value, "drm-only")) {
1572            if (mDecryptHandle != NULL) {
1573                setProtectionBit = true;
1574            }
1575        // property value is empty, or unexpected value
1576        } else {
1577            if (mDecryptHandle != NULL) {
1578                setProtectionBit = true;
1579            }
1580        }
1581    // can' read property value
1582    } else {
1583        if (mDecryptHandle != NULL) {
1584            setProtectionBit = true;
1585        }
1586    }
1587    // note that usage bit is already cleared, so no need to clear it in the "else" case
1588    if (setProtectionBit) {
1589        flags |= OMXCodec::kEnableGrallocUsageProtected;
1590    }
1591#else
1592    if (mDecryptHandle != NULL) {
1593        flags |= OMXCodec::kEnableGrallocUsageProtected;
1594    }
1595#endif
1596    ALOGV("initVideoDecoder flags=0x%x", flags);
1597    mVideoSource = OMXCodec::Create(
1598            mClient.interface(), mVideoTrack->getFormat(),
1599            false, // createEncoder
1600            mVideoTrack,
1601            NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
1602
1603    if (mVideoSource != NULL) {
1604        int64_t durationUs;
1605        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1606            Mutex::Autolock autoLock(mMiscStateLock);
1607            if (mDurationUs < 0 || durationUs > mDurationUs) {
1608                mDurationUs = durationUs;
1609            }
1610        }
1611
1612        status_t err = mVideoSource->start();
1613
1614        if (err != OK) {
1615            ALOGE("failed to start video source");
1616            mVideoSource.clear();
1617            return err;
1618        }
1619    }
1620
1621    if (mVideoSource != NULL) {
1622        const char *componentName;
1623        CHECK(mVideoSource->getFormat()
1624                ->findCString(kKeyDecoderComponent, &componentName));
1625
1626        {
1627            Mutex::Autolock autoLock(mStatsLock);
1628            TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
1629
1630            stat->mDecoderName = componentName;
1631        }
1632
1633        static const char *kPrefix = "OMX.Nvidia.";
1634        static const char *kSuffix = ".decode";
1635        static const size_t kSuffixLength = strlen(kSuffix);
1636
1637        size_t componentNameLength = strlen(componentName);
1638
1639        if (!strncmp(componentName, kPrefix, strlen(kPrefix))
1640                && componentNameLength >= kSuffixLength
1641                && !strcmp(&componentName[
1642                    componentNameLength - kSuffixLength], kSuffix)) {
1643            modifyFlags(SLOW_DECODER_HACK, SET);
1644        }
1645    }
1646
1647    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1648}
1649
1650void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1651    ATRACE_CALL();
1652
1653    if (mSeeking == SEEK_VIDEO_ONLY) {
1654        mSeeking = NO_SEEK;
1655        return;
1656    }
1657
1658    if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) {
1659        return;
1660    }
1661
1662    if (mAudioPlayer != NULL) {
1663        ALOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
1664
1665        // If we don't have a video time, seek audio to the originally
1666        // requested seek time instead.
1667
1668        mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1669        mWatchForAudioSeekComplete = true;
1670        mWatchForAudioEOS = true;
1671    } else if (!mSeekNotificationSent) {
1672        // If we're playing video only, report seek complete now,
1673        // otherwise audio player will notify us later.
1674        notifyListener_l(MEDIA_SEEK_COMPLETE);
1675        mSeekNotificationSent = true;
1676    }
1677
1678    modifyFlags(FIRST_FRAME, SET);
1679    mSeeking = NO_SEEK;
1680
1681    if (mDecryptHandle != NULL) {
1682        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1683                Playback::PAUSE, 0);
1684        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1685                Playback::START, videoTimeUs / 1000);
1686    }
1687}
1688
1689void AwesomePlayer::onVideoEvent() {
1690    ATRACE_CALL();
1691    Mutex::Autolock autoLock(mLock);
1692    if (!mVideoEventPending) {
1693        // The event has been cancelled in reset_l() but had already
1694        // been scheduled for execution at that time.
1695        return;
1696    }
1697    mVideoEventPending = false;
1698
1699    if (mSeeking != NO_SEEK) {
1700        if (mVideoBuffer) {
1701            mVideoBuffer->release();
1702            mVideoBuffer = NULL;
1703        }
1704
1705        if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL
1706                && !(mFlags & SEEK_PREVIEW)) {
1707            // We're going to seek the video source first, followed by
1708            // the audio source.
1709            // In order to avoid jumps in the DataSource offset caused by
1710            // the audio codec prefetching data from the old locations
1711            // while the video codec is already reading data from the new
1712            // locations, we'll "pause" the audio source, causing it to
1713            // stop reading input data until a subsequent seek.
1714
1715            if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
1716                mAudioPlayer->pause();
1717
1718                modifyFlags(AUDIO_RUNNING, CLEAR);
1719            }
1720            mAudioSource->pause();
1721        }
1722    }
1723
1724    if (!mVideoBuffer) {
1725        MediaSource::ReadOptions options;
1726        if (mSeeking != NO_SEEK) {
1727            ALOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1728
1729            options.setSeekTo(
1730                    mSeekTimeUs,
1731                    mSeeking == SEEK_VIDEO_ONLY
1732                        ? MediaSource::ReadOptions::SEEK_NEXT_SYNC
1733                        : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
1734        }
1735        for (;;) {
1736            status_t err = mVideoSource->read(&mVideoBuffer, &options);
1737            options.clearSeekTo();
1738
1739            if (err != OK) {
1740                CHECK(mVideoBuffer == NULL);
1741
1742                if (err == INFO_FORMAT_CHANGED) {
1743                    ALOGV("VideoSource signalled format change.");
1744
1745                    notifyVideoSize_l();
1746
1747                    if (mVideoRenderer != NULL) {
1748                        mVideoRendererIsPreview = false;
1749                        initRenderer_l();
1750                    }
1751                    continue;
1752                }
1753
1754                // So video playback is complete, but we may still have
1755                // a seek request pending that needs to be applied
1756                // to the audio track.
1757                if (mSeeking != NO_SEEK) {
1758                    ALOGV("video stream ended while seeking!");
1759                }
1760                finishSeekIfNecessary(-1);
1761
1762                if (mAudioPlayer != NULL
1763                        && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1764                    startAudioPlayer_l();
1765                }
1766
1767                modifyFlags(VIDEO_AT_EOS, SET);
1768                postStreamDoneEvent_l(err);
1769                return;
1770            }
1771
1772            if (mVideoBuffer->range_length() == 0) {
1773                // Some decoders, notably the PV AVC software decoder
1774                // return spurious empty buffers that we just want to ignore.
1775
1776                mVideoBuffer->release();
1777                mVideoBuffer = NULL;
1778                continue;
1779            }
1780
1781            break;
1782        }
1783
1784        {
1785            Mutex::Autolock autoLock(mStatsLock);
1786            ++mStats.mNumVideoFramesDecoded;
1787        }
1788    }
1789
1790    int64_t timeUs;
1791    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1792
1793    mLastVideoTimeUs = timeUs;
1794
1795    if (mSeeking == SEEK_VIDEO_ONLY) {
1796        if (mSeekTimeUs > timeUs) {
1797            ALOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us",
1798                 mSeekTimeUs, timeUs);
1799        }
1800    }
1801
1802    {
1803        Mutex::Autolock autoLock(mMiscStateLock);
1804        mVideoTimeUs = timeUs;
1805    }
1806
1807    SeekType wasSeeking = mSeeking;
1808    finishSeekIfNecessary(timeUs);
1809
1810    if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1811        status_t err = startAudioPlayer_l();
1812        if (err != OK) {
1813            ALOGE("Starting the audio player failed w/ err %d", err);
1814            return;
1815        }
1816    }
1817
1818    if ((mFlags & TEXTPLAYER_INITIALIZED)
1819            && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
1820        mTextDriver->start();
1821        modifyFlags(TEXT_RUNNING, SET);
1822    }
1823
1824    TimeSource *ts =
1825        ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED))
1826            ? &mSystemTimeSource : mTimeSource;
1827
1828    if (mFlags & FIRST_FRAME) {
1829        modifyFlags(FIRST_FRAME, CLEAR);
1830        mSinceLastDropped = 0;
1831        mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
1832    }
1833
1834    int64_t realTimeUs, mediaTimeUs;
1835    if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
1836        && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1837        mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1838    }
1839
1840    if (wasSeeking == SEEK_VIDEO_ONLY) {
1841        int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1842
1843        int64_t latenessUs = nowUs - timeUs;
1844
1845        ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
1846
1847        if (latenessUs > 0) {
1848            ALOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6);
1849        }
1850    }
1851
1852    if (wasSeeking == NO_SEEK) {
1853        // Let's display the first frame after seeking right away.
1854
1855        int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1856
1857        int64_t latenessUs = nowUs - timeUs;
1858
1859        ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
1860
1861        if (latenessUs > 500000ll
1862                && mAudioPlayer != NULL
1863                && mAudioPlayer->getMediaTimeMapping(
1864                    &realTimeUs, &mediaTimeUs)) {
1865            if (mWVMExtractor == NULL) {
1866                ALOGI("we're much too late (%.2f secs), video skipping ahead",
1867                     latenessUs / 1E6);
1868
1869                mVideoBuffer->release();
1870                mVideoBuffer = NULL;
1871
1872                mSeeking = SEEK_VIDEO_ONLY;
1873                mSeekTimeUs = mediaTimeUs;
1874
1875                postVideoEvent_l();
1876                return;
1877            } else {
1878                // The widevine extractor doesn't deal well with seeking
1879                // audio and video independently. We'll just have to wait
1880                // until the decoder catches up, which won't be long at all.
1881                ALOGI("we're very late (%.2f secs)", latenessUs / 1E6);
1882            }
1883        }
1884
1885        if (latenessUs > 40000) {
1886            // We're more than 40ms late.
1887            ALOGV("we're late by %lld us (%.2f secs)",
1888                 latenessUs, latenessUs / 1E6);
1889
1890            if (!(mFlags & SLOW_DECODER_HACK)
1891                    || mSinceLastDropped > FRAME_DROP_FREQ)
1892            {
1893                ALOGV("we're late by %lld us (%.2f secs) dropping "
1894                     "one after %d frames",
1895                     latenessUs, latenessUs / 1E6, mSinceLastDropped);
1896
1897                mSinceLastDropped = 0;
1898                mVideoBuffer->release();
1899                mVideoBuffer = NULL;
1900
1901                {
1902                    Mutex::Autolock autoLock(mStatsLock);
1903                    ++mStats.mNumVideoFramesDropped;
1904                }
1905
1906                postVideoEvent_l();
1907                return;
1908            }
1909        }
1910
1911        if (latenessUs < -10000) {
1912            // We're more than 10ms early.
1913            postVideoEvent_l(10000);
1914            return;
1915        }
1916    }
1917
1918    if ((mNativeWindow != NULL)
1919            && (mVideoRendererIsPreview || mVideoRenderer == NULL)) {
1920        mVideoRendererIsPreview = false;
1921
1922        initRenderer_l();
1923    }
1924
1925    if (mVideoRenderer != NULL) {
1926        mSinceLastDropped++;
1927        mVideoRenderer->render(mVideoBuffer);
1928        if (!mVideoRenderingStarted) {
1929            mVideoRenderingStarted = true;
1930            notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START);
1931        }
1932
1933        notifyIfMediaStarted_l();
1934    }
1935
1936    mVideoBuffer->release();
1937    mVideoBuffer = NULL;
1938
1939    if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) {
1940        modifyFlags(SEEK_PREVIEW, CLEAR);
1941        return;
1942    }
1943
1944    postVideoEvent_l();
1945}
1946
1947void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1948    ATRACE_CALL();
1949
1950    if (mVideoEventPending) {
1951        return;
1952    }
1953
1954    mVideoEventPending = true;
1955    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1956}
1957
1958void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
1959    if (mStreamDoneEventPending) {
1960        return;
1961    }
1962    mStreamDoneEventPending = true;
1963
1964    mStreamDoneStatus = status;
1965    mQueue.postEvent(mStreamDoneEvent);
1966}
1967
1968void AwesomePlayer::postBufferingEvent_l() {
1969    if (mBufferingEventPending) {
1970        return;
1971    }
1972    mBufferingEventPending = true;
1973    mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1974}
1975
1976void AwesomePlayer::postVideoLagEvent_l() {
1977    if (mVideoLagEventPending) {
1978        return;
1979    }
1980    mVideoLagEventPending = true;
1981    mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
1982}
1983
1984void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) {
1985    Mutex::Autolock autoLock(mAudioLock);
1986    if (mAudioStatusEventPending) {
1987        return;
1988    }
1989    mAudioStatusEventPending = true;
1990    // Do not honor delay when looping in order to limit audio gap
1991    if (mFlags & (LOOPING | AUTO_LOOPING)) {
1992        delayUs = 0;
1993    }
1994    mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs);
1995}
1996
1997void AwesomePlayer::postAudioTearDownEvent(int64_t delayUs) {
1998    Mutex::Autolock autoLock(mAudioLock);
1999    if (mAudioTearDownEventPending) {
2000        return;
2001    }
2002    mAudioTearDownEventPending = true;
2003    mQueue.postEventWithDelay(mAudioTearDownEvent, delayUs);
2004}
2005
2006void AwesomePlayer::onCheckAudioStatus() {
2007    {
2008        Mutex::Autolock autoLock(mAudioLock);
2009        if (!mAudioStatusEventPending) {
2010            // Event was dispatched and while we were blocking on the mutex,
2011            // has already been cancelled.
2012            return;
2013        }
2014
2015        mAudioStatusEventPending = false;
2016    }
2017
2018    Mutex::Autolock autoLock(mLock);
2019
2020    if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
2021        mWatchForAudioSeekComplete = false;
2022
2023        if (!mSeekNotificationSent) {
2024            notifyListener_l(MEDIA_SEEK_COMPLETE);
2025            mSeekNotificationSent = true;
2026        }
2027
2028        mSeeking = NO_SEEK;
2029
2030        notifyIfMediaStarted_l();
2031    }
2032
2033    status_t finalStatus;
2034    if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
2035        mWatchForAudioEOS = false;
2036        modifyFlags(AUDIO_AT_EOS, SET);
2037        modifyFlags(FIRST_FRAME, SET);
2038        postStreamDoneEvent_l(finalStatus);
2039    }
2040}
2041
2042status_t AwesomePlayer::prepare() {
2043    ATRACE_CALL();
2044    Mutex::Autolock autoLock(mLock);
2045    return prepare_l();
2046}
2047
2048status_t AwesomePlayer::prepare_l() {
2049    if (mFlags & PREPARED) {
2050        return OK;
2051    }
2052
2053    if (mFlags & PREPARING) {
2054        return UNKNOWN_ERROR;
2055    }
2056
2057    mIsAsyncPrepare = false;
2058    status_t err = prepareAsync_l();
2059
2060    if (err != OK) {
2061        return err;
2062    }
2063
2064    while (mFlags & PREPARING) {
2065        mPreparedCondition.wait(mLock);
2066    }
2067
2068    return mPrepareResult;
2069}
2070
2071status_t AwesomePlayer::prepareAsync() {
2072    ATRACE_CALL();
2073    Mutex::Autolock autoLock(mLock);
2074
2075    if (mFlags & PREPARING) {
2076        return UNKNOWN_ERROR;  // async prepare already pending
2077    }
2078
2079    mIsAsyncPrepare = true;
2080    return prepareAsync_l();
2081}
2082
2083status_t AwesomePlayer::prepareAsync_l() {
2084    if (mFlags & PREPARING) {
2085        return UNKNOWN_ERROR;  // async prepare already pending
2086    }
2087
2088    if (!mQueueStarted) {
2089        mQueue.start();
2090        mQueueStarted = true;
2091    }
2092
2093    modifyFlags(PREPARING, SET);
2094    mAsyncPrepareEvent = new AwesomeEvent(
2095            this, &AwesomePlayer::onPrepareAsyncEvent);
2096
2097    mQueue.postEvent(mAsyncPrepareEvent);
2098
2099    return OK;
2100}
2101
2102status_t AwesomePlayer::finishSetDataSource_l() {
2103    ATRACE_CALL();
2104    sp<DataSource> dataSource;
2105
2106    bool isWidevineStreaming = false;
2107    if (!strncasecmp("widevine://", mUri.string(), 11)) {
2108        isWidevineStreaming = true;
2109
2110        String8 newURI = String8("http://");
2111        newURI.append(mUri.string() + 11);
2112
2113        mUri = newURI;
2114    }
2115
2116    AString sniffedMIME;
2117
2118    if (!strncasecmp("http://", mUri.string(), 7)
2119            || !strncasecmp("https://", mUri.string(), 8)
2120            || isWidevineStreaming) {
2121        mConnectingDataSource = HTTPBase::Create(
2122                (mFlags & INCOGNITO)
2123                    ? HTTPBase::kFlagIncognito
2124                    : 0);
2125
2126        if (mUIDValid) {
2127            mConnectingDataSource->setUID(mUID);
2128        }
2129
2130        String8 cacheConfig;
2131        bool disconnectAtHighwatermark;
2132        NuCachedSource2::RemoveCacheSpecificHeaders(
2133                &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark);
2134
2135        mLock.unlock();
2136        status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
2137        mLock.lock();
2138
2139        if (err != OK) {
2140            mConnectingDataSource.clear();
2141
2142            ALOGI("mConnectingDataSource->connect() returned %d", err);
2143            return err;
2144        }
2145
2146        if (!isWidevineStreaming) {
2147            // The widevine extractor does its own caching.
2148
2149#if 0
2150            mCachedSource = new NuCachedSource2(
2151                    new ThrottledSource(
2152                        mConnectingDataSource, 50 * 1024 /* bytes/sec */));
2153#else
2154            mCachedSource = new NuCachedSource2(
2155                    mConnectingDataSource,
2156                    cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
2157                    disconnectAtHighwatermark);
2158#endif
2159
2160            dataSource = mCachedSource;
2161        } else {
2162            dataSource = mConnectingDataSource;
2163        }
2164
2165        mConnectingDataSource.clear();
2166
2167        String8 contentType = dataSource->getMIMEType();
2168
2169        if (strncasecmp(contentType.string(), "audio/", 6)) {
2170            // We're not doing this for streams that appear to be audio-only
2171            // streams to ensure that even low bandwidth streams start
2172            // playing back fairly instantly.
2173
2174            // We're going to prefill the cache before trying to instantiate
2175            // the extractor below, as the latter is an operation that otherwise
2176            // could block on the datasource for a significant amount of time.
2177            // During that time we'd be unable to abort the preparation phase
2178            // without this prefill.
2179            if (mCachedSource != NULL) {
2180                // We're going to prefill the cache before trying to instantiate
2181                // the extractor below, as the latter is an operation that otherwise
2182                // could block on the datasource for a significant amount of time.
2183                // During that time we'd be unable to abort the preparation phase
2184                // without this prefill.
2185
2186                mLock.unlock();
2187
2188                // Initially make sure we have at least 192 KB for the sniff
2189                // to complete without blocking.
2190                static const size_t kMinBytesForSniffing = 192 * 1024;
2191
2192                off64_t metaDataSize = -1ll;
2193                for (;;) {
2194                    status_t finalStatus;
2195                    size_t cachedDataRemaining =
2196                        mCachedSource->approxDataRemaining(&finalStatus);
2197
2198                    if (finalStatus != OK
2199                            || (metaDataSize >= 0
2200                                && cachedDataRemaining >= metaDataSize)
2201                            || (mFlags & PREPARE_CANCELLED)) {
2202                        break;
2203                    }
2204
2205                    ALOGV("now cached %d bytes of data", cachedDataRemaining);
2206
2207                    if (metaDataSize < 0
2208                            && cachedDataRemaining >= kMinBytesForSniffing) {
2209                        String8 tmp;
2210                        float confidence;
2211                        sp<AMessage> meta;
2212                        if (!dataSource->sniff(&tmp, &confidence, &meta)) {
2213                            mLock.lock();
2214                            return UNKNOWN_ERROR;
2215                        }
2216
2217                        // We successfully identified the file's extractor to
2218                        // be, remember this mime type so we don't have to
2219                        // sniff it again when we call MediaExtractor::Create()
2220                        // below.
2221                        sniffedMIME = tmp.string();
2222
2223                        if (meta == NULL
2224                                || !meta->findInt64(
2225                                    "meta-data-size", &metaDataSize)) {
2226                            metaDataSize = kHighWaterMarkBytes;
2227                        }
2228
2229                        CHECK_GE(metaDataSize, 0ll);
2230                        ALOGV("metaDataSize = %lld bytes", metaDataSize);
2231                    }
2232
2233                    usleep(200000);
2234                }
2235
2236                mLock.lock();
2237            }
2238
2239            if (mFlags & PREPARE_CANCELLED) {
2240                ALOGI("Prepare cancelled while waiting for initial cache fill.");
2241                return UNKNOWN_ERROR;
2242            }
2243        }
2244    } else {
2245        dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
2246    }
2247
2248    if (dataSource == NULL) {
2249        return UNKNOWN_ERROR;
2250    }
2251
2252    sp<MediaExtractor> extractor;
2253
2254    if (isWidevineStreaming) {
2255        String8 mimeType;
2256        float confidence;
2257        sp<AMessage> dummy;
2258        bool success;
2259
2260        // SniffWVM is potentially blocking since it may require network access.
2261        // Do not call it with mLock held.
2262        mLock.unlock();
2263        success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
2264        mLock.lock();
2265
2266        if (!success
2267                || strcasecmp(
2268                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
2269            return ERROR_UNSUPPORTED;
2270        }
2271
2272        mWVMExtractor = new WVMExtractor(dataSource);
2273        mWVMExtractor->setAdaptiveStreamingMode(true);
2274        if (mUIDValid)
2275            mWVMExtractor->setUID(mUID);
2276        extractor = mWVMExtractor;
2277    } else {
2278        extractor = MediaExtractor::Create(
2279                dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
2280
2281        if (extractor == NULL) {
2282            return UNKNOWN_ERROR;
2283        }
2284    }
2285
2286    if (extractor->getDrmFlag()) {
2287        checkDrmStatus(dataSource);
2288    }
2289
2290    status_t err = setDataSource_l(extractor);
2291
2292    if (err != OK) {
2293        mWVMExtractor.clear();
2294
2295        return err;
2296    }
2297
2298    return OK;
2299}
2300
2301void AwesomePlayer::abortPrepare(status_t err) {
2302    CHECK(err != OK);
2303
2304    if (mIsAsyncPrepare) {
2305        notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
2306    }
2307
2308    mPrepareResult = err;
2309    modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
2310    mAsyncPrepareEvent = NULL;
2311    mPreparedCondition.broadcast();
2312    mAudioTearDown = false;
2313}
2314
2315// static
2316bool AwesomePlayer::ContinuePreparation(void *cookie) {
2317    AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
2318
2319    return (me->mFlags & PREPARE_CANCELLED) == 0;
2320}
2321
2322void AwesomePlayer::onPrepareAsyncEvent() {
2323    Mutex::Autolock autoLock(mLock);
2324    beginPrepareAsync_l();
2325}
2326
2327void AwesomePlayer::beginPrepareAsync_l() {
2328    if (mFlags & PREPARE_CANCELLED) {
2329        ALOGI("prepare was cancelled before doing anything");
2330        abortPrepare(UNKNOWN_ERROR);
2331        return;
2332    }
2333
2334    if (mUri.size() > 0) {
2335        status_t err = finishSetDataSource_l();
2336
2337        if (err != OK) {
2338            abortPrepare(err);
2339            return;
2340        }
2341    }
2342
2343    if (mVideoTrack != NULL && mVideoSource == NULL) {
2344        status_t err = initVideoDecoder();
2345
2346        if (err != OK) {
2347            abortPrepare(err);
2348            return;
2349        }
2350    }
2351
2352    if (mAudioTrack != NULL && mAudioSource == NULL) {
2353        status_t err = initAudioDecoder();
2354
2355        if (err != OK) {
2356            abortPrepare(err);
2357            return;
2358        }
2359    }
2360
2361    modifyFlags(PREPARING_CONNECTED, SET);
2362
2363    if (isStreamingHTTP()) {
2364        postBufferingEvent_l();
2365    } else {
2366        finishAsyncPrepare_l();
2367    }
2368}
2369
2370void AwesomePlayer::finishAsyncPrepare_l() {
2371    if (mIsAsyncPrepare) {
2372        if (mVideoSource == NULL) {
2373            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
2374        } else {
2375            notifyVideoSize_l();
2376        }
2377
2378        notifyListener_l(MEDIA_PREPARED);
2379    }
2380
2381    mPrepareResult = OK;
2382    modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
2383    modifyFlags(PREPARED, SET);
2384    mAsyncPrepareEvent = NULL;
2385    mPreparedCondition.broadcast();
2386
2387    if (mAudioTearDown) {
2388        if (mPrepareResult == OK) {
2389            if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
2390                seekTo_l(mAudioTearDownPosition);
2391            }
2392
2393            if (mAudioTearDownWasPlaying) {
2394                modifyFlags(CACHE_UNDERRUN, CLEAR);
2395                play_l();
2396            }
2397        }
2398        mAudioTearDown = false;
2399    }
2400}
2401
2402uint32_t AwesomePlayer::flags() const {
2403    return mExtractorFlags;
2404}
2405
2406void AwesomePlayer::postAudioEOS(int64_t delayUs) {
2407    postCheckAudioStatusEvent(delayUs);
2408}
2409
2410void AwesomePlayer::postAudioSeekComplete() {
2411    postCheckAudioStatusEvent(0);
2412}
2413
2414void AwesomePlayer::postAudioTearDown() {
2415    postAudioTearDownEvent(0);
2416}
2417
2418status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
2419    switch (key) {
2420        case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS:
2421        {
2422            return setCacheStatCollectFreq(request);
2423        }
2424        case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE:
2425        {
2426            if (mAudioPlayer != NULL) {
2427                return mAudioPlayer->setPlaybackRatePermille(request.readInt32());
2428            } else {
2429                return NO_INIT;
2430            }
2431        }
2432        default:
2433        {
2434            return ERROR_UNSUPPORTED;
2435        }
2436    }
2437}
2438
2439status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) {
2440    if (mCachedSource != NULL) {
2441        int32_t freqMs = request.readInt32();
2442        ALOGD("Request to keep cache stats in the past %d ms",
2443            freqMs);
2444        return mCachedSource->setCacheStatCollectFreq(freqMs);
2445    }
2446    return ERROR_UNSUPPORTED;
2447}
2448
2449status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
2450    switch (key) {
2451    case KEY_PARAMETER_AUDIO_CHANNEL_COUNT:
2452        {
2453            int32_t channelCount;
2454            if (mAudioTrack == 0 ||
2455                    !mAudioTrack->getFormat()->findInt32(kKeyChannelCount, &channelCount)) {
2456                channelCount = 0;
2457            }
2458            reply->writeInt32(channelCount);
2459        }
2460        return OK;
2461    default:
2462        {
2463            return ERROR_UNSUPPORTED;
2464        }
2465    }
2466}
2467
2468status_t AwesomePlayer::getTrackInfo(Parcel *reply) const {
2469    Mutex::Autolock autoLock(mLock);
2470    size_t trackCount = mExtractor->countTracks();
2471    if (mTextDriver != NULL) {
2472        trackCount += mTextDriver->countExternalTracks();
2473    }
2474
2475    reply->writeInt32(trackCount);
2476    for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
2477        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
2478
2479        const char *_mime;
2480        CHECK(meta->findCString(kKeyMIMEType, &_mime));
2481
2482        String8 mime = String8(_mime);
2483
2484        reply->writeInt32(2); // 2 fields
2485
2486        if (!strncasecmp(mime.string(), "video/", 6)) {
2487            reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO);
2488        } else if (!strncasecmp(mime.string(), "audio/", 6)) {
2489            reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO);
2490        } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
2491            reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
2492        } else {
2493            reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
2494        }
2495
2496        const char *lang;
2497        if (!meta->findCString(kKeyMediaLanguage, &lang)) {
2498            lang = "und";
2499        }
2500        reply->writeString16(String16(lang));
2501    }
2502
2503    if (mTextDriver != NULL) {
2504        mTextDriver->getExternalTrackInfo(reply);
2505    }
2506    return OK;
2507}
2508
2509status_t AwesomePlayer::selectAudioTrack_l(
2510        const sp<MediaSource>& source, size_t trackIndex) {
2511
2512    ALOGI("selectAudioTrack_l: trackIndex=%d, mFlags=0x%x", trackIndex, mFlags);
2513
2514    {
2515        Mutex::Autolock autoLock(mStatsLock);
2516        if ((ssize_t)trackIndex == mActiveAudioTrackIndex) {
2517            ALOGI("Track %d is active. Does nothing.", trackIndex);
2518            return OK;
2519        }
2520        //mStats.mFlags = mFlags;
2521    }
2522
2523    if (mSeeking != NO_SEEK) {
2524        ALOGE("Selecting a track while seeking is not supported");
2525        return ERROR_UNSUPPORTED;
2526    }
2527
2528    if ((mFlags & PREPARED) == 0) {
2529        ALOGE("Data source has not finished preparation");
2530        return ERROR_UNSUPPORTED;
2531    }
2532
2533    CHECK(source != NULL);
2534    bool wasPlaying = (mFlags & PLAYING) != 0;
2535
2536    pause_l();
2537
2538    int64_t curTimeUs;
2539    CHECK_EQ(getPosition(&curTimeUs), (status_t)OK);
2540
2541    if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
2542            && mAudioSource != NULL) {
2543        // If we had an audio player, it would have effectively
2544        // taken possession of the audio source and stopped it when
2545        // _it_ is stopped. Otherwise this is still our responsibility.
2546        mAudioSource->stop();
2547    }
2548    mAudioSource.clear();
2549    mOmxSource.clear();
2550
2551    mTimeSource = NULL;
2552
2553    delete mAudioPlayer;
2554    mAudioPlayer = NULL;
2555
2556    modifyFlags(AUDIOPLAYER_STARTED, CLEAR);
2557
2558    setAudioSource(source);
2559
2560    modifyFlags(AUDIO_AT_EOS, CLEAR);
2561    modifyFlags(AT_EOS, CLEAR);
2562
2563    status_t err;
2564    if ((err = initAudioDecoder()) != OK) {
2565        ALOGE("Failed to init audio decoder: 0x%x", err);
2566        return err;
2567    }
2568
2569    mSeekNotificationSent = true;
2570    seekTo_l(curTimeUs);
2571
2572    if (wasPlaying) {
2573        play_l();
2574    }
2575
2576    mActiveAudioTrackIndex = trackIndex;
2577
2578    return OK;
2579}
2580
2581status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) {
2582    ATRACE_CALL();
2583    ALOGV("selectTrack: trackIndex = %d and select=%d", trackIndex, select);
2584    Mutex::Autolock autoLock(mLock);
2585    size_t trackCount = mExtractor->countTracks();
2586    if (mTextDriver != NULL) {
2587        trackCount += mTextDriver->countExternalTracks();
2588    }
2589    if (trackIndex >= trackCount) {
2590        ALOGE("Track index (%d) is out of range [0, %d)", trackIndex, trackCount);
2591        return ERROR_OUT_OF_RANGE;
2592    }
2593
2594    bool isAudioTrack = false;
2595    if (trackIndex < mExtractor->countTracks()) {
2596        sp<MetaData> meta = mExtractor->getTrackMetaData(trackIndex);
2597        const char *mime;
2598        CHECK(meta->findCString(kKeyMIMEType, &mime));
2599        isAudioTrack = !strncasecmp(mime, "audio/", 6);
2600
2601        if (!isAudioTrack && strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) != 0) {
2602            ALOGE("Track %d is not either audio or timed text", trackIndex);
2603            return ERROR_UNSUPPORTED;
2604        }
2605    }
2606
2607    if (isAudioTrack) {
2608        if (!select) {
2609            ALOGE("Deselect an audio track (%d) is not supported", trackIndex);
2610            return ERROR_UNSUPPORTED;
2611        }
2612        return selectAudioTrack_l(mExtractor->getTrack(trackIndex), trackIndex);
2613    }
2614
2615    // Timed text track handling
2616    if (mTextDriver == NULL) {
2617        return INVALID_OPERATION;
2618    }
2619
2620    status_t err = OK;
2621    if (select) {
2622        err = mTextDriver->selectTrack(trackIndex);
2623        if (err == OK) {
2624            modifyFlags(TEXTPLAYER_INITIALIZED, SET);
2625            if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) {
2626                mTextDriver->start();
2627                modifyFlags(TEXT_RUNNING, SET);
2628            }
2629        }
2630    } else {
2631        err = mTextDriver->unselectTrack(trackIndex);
2632        if (err == OK) {
2633            modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
2634            modifyFlags(TEXT_RUNNING, CLEAR);
2635        }
2636    }
2637    return err;
2638}
2639
2640size_t AwesomePlayer::countTracks() const {
2641    return mExtractor->countTracks() + mTextDriver->countExternalTracks();
2642}
2643
2644status_t AwesomePlayer::setVideoScalingMode(int32_t mode) {
2645    Mutex::Autolock lock(mLock);
2646    return setVideoScalingMode_l(mode);
2647}
2648
2649status_t AwesomePlayer::setVideoScalingMode_l(int32_t mode) {
2650    mVideoScalingMode = mode;
2651    if (mNativeWindow != NULL) {
2652        status_t err = native_window_set_scaling_mode(
2653                mNativeWindow.get(), mVideoScalingMode);
2654        if (err != OK) {
2655            ALOGW("Failed to set scaling mode: %d", err);
2656        }
2657        return err;
2658    }
2659    return OK;
2660}
2661
2662status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) {
2663    ATRACE_CALL();
2664    if (NULL == reply) {
2665        return android::BAD_VALUE;
2666    }
2667    int32_t methodId;
2668    status_t ret = request.readInt32(&methodId);
2669    if (ret != android::OK) {
2670        return ret;
2671    }
2672    switch(methodId) {
2673        case INVOKE_ID_SET_VIDEO_SCALING_MODE:
2674        {
2675            int mode = request.readInt32();
2676            return setVideoScalingMode(mode);
2677        }
2678
2679        case INVOKE_ID_GET_TRACK_INFO:
2680        {
2681            return getTrackInfo(reply);
2682        }
2683        case INVOKE_ID_ADD_EXTERNAL_SOURCE:
2684        {
2685            Mutex::Autolock autoLock(mLock);
2686            if (mTextDriver == NULL) {
2687                mTextDriver = new TimedTextDriver(mListener);
2688            }
2689            // String values written in Parcel are UTF-16 values.
2690            String8 uri(request.readString16());
2691            String8 mimeType(request.readString16());
2692            size_t nTracks = countTracks();
2693            return mTextDriver->addOutOfBandTextSource(nTracks, uri, mimeType);
2694        }
2695        case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD:
2696        {
2697            Mutex::Autolock autoLock(mLock);
2698            if (mTextDriver == NULL) {
2699                mTextDriver = new TimedTextDriver(mListener);
2700            }
2701            int fd         = request.readFileDescriptor();
2702            off64_t offset = request.readInt64();
2703            off64_t length  = request.readInt64();
2704            String8 mimeType(request.readString16());
2705            size_t nTracks = countTracks();
2706            return mTextDriver->addOutOfBandTextSource(
2707                    nTracks, fd, offset, length, mimeType);
2708        }
2709        case INVOKE_ID_SELECT_TRACK:
2710        {
2711            int trackIndex = request.readInt32();
2712            return selectTrack(trackIndex, true /* select */);
2713        }
2714        case INVOKE_ID_UNSELECT_TRACK:
2715        {
2716            int trackIndex = request.readInt32();
2717            return selectTrack(trackIndex, false /* select */);
2718        }
2719        default:
2720        {
2721            return ERROR_UNSUPPORTED;
2722        }
2723    }
2724    // It will not reach here.
2725    return OK;
2726}
2727
2728bool AwesomePlayer::isStreamingHTTP() const {
2729    return mCachedSource != NULL || mWVMExtractor != NULL;
2730}
2731
2732status_t AwesomePlayer::dump(int fd, const Vector<String16> &args) const {
2733    Mutex::Autolock autoLock(mStatsLock);
2734
2735    FILE *out = fdopen(dup(fd), "w");
2736
2737    fprintf(out, " AwesomePlayer\n");
2738    if (mStats.mFd < 0) {
2739        fprintf(out, "  URI(suppressed)");
2740    } else {
2741        fprintf(out, "  fd(%d)", mStats.mFd);
2742    }
2743
2744    fprintf(out, ", flags(0x%08x)", mStats.mFlags);
2745
2746    if (mStats.mBitrate >= 0) {
2747        fprintf(out, ", bitrate(%lld bps)", mStats.mBitrate);
2748    }
2749
2750    fprintf(out, "\n");
2751
2752    for (size_t i = 0; i < mStats.mTracks.size(); ++i) {
2753        const TrackStat &stat = mStats.mTracks.itemAt(i);
2754
2755        fprintf(out, "  Track %d\n", i + 1);
2756        fprintf(out, "   MIME(%s)", stat.mMIME.string());
2757
2758        if (!stat.mDecoderName.isEmpty()) {
2759            fprintf(out, ", decoder(%s)", stat.mDecoderName.string());
2760        }
2761
2762        fprintf(out, "\n");
2763
2764        if ((ssize_t)i == mStats.mVideoTrackIndex) {
2765            fprintf(out,
2766                    "   videoDimensions(%d x %d), "
2767                    "numVideoFramesDecoded(%lld), "
2768                    "numVideoFramesDropped(%lld)\n",
2769                    mStats.mVideoWidth,
2770                    mStats.mVideoHeight,
2771                    mStats.mNumVideoFramesDecoded,
2772                    mStats.mNumVideoFramesDropped);
2773        }
2774    }
2775
2776    fclose(out);
2777    out = NULL;
2778
2779    return OK;
2780}
2781
2782void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) {
2783    switch (mode) {
2784        case SET:
2785            mFlags |= value;
2786            break;
2787        case CLEAR:
2788            if ((value & CACHE_UNDERRUN) && (mFlags & CACHE_UNDERRUN)) {
2789                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
2790            }
2791            mFlags &= ~value;
2792            break;
2793        case ASSIGN:
2794            mFlags = value;
2795            break;
2796        default:
2797            TRESPASS();
2798    }
2799
2800    {
2801        Mutex::Autolock autoLock(mStatsLock);
2802        mStats.mFlags = mFlags;
2803    }
2804}
2805
2806void AwesomePlayer::onAudioTearDownEvent() {
2807
2808    Mutex::Autolock autoLock(mLock);
2809    if (!mAudioTearDownEventPending) {
2810        return;
2811    }
2812    mAudioTearDownEventPending = false;
2813
2814    ALOGV("onAudioTearDownEvent");
2815
2816    // stream info is cleared by reset_l() so copy what we need
2817    mAudioTearDownWasPlaying = (mFlags & PLAYING);
2818    KeyedVector<String8, String8> uriHeaders(mUriHeaders);
2819    sp<DataSource> fileSource(mFileSource);
2820
2821    mStatsLock.lock();
2822    String8 uri(mStats.mURI);
2823    mStatsLock.unlock();
2824
2825    // get current position so we can start recreated stream from here
2826    getPosition(&mAudioTearDownPosition);
2827
2828    // Reset and recreate
2829    reset_l();
2830
2831    status_t err;
2832
2833    if (fileSource != NULL) {
2834        mFileSource = fileSource;
2835        err = setDataSource_l(fileSource);
2836    } else {
2837        err = setDataSource_l(uri, &uriHeaders);
2838    }
2839
2840    mFlags |= PREPARING;
2841    if ( err != OK ) {
2842        // This will force beingPrepareAsync_l() to notify
2843        // a MEDIA_ERROR to the client and abort the prepare
2844        mFlags |= PREPARE_CANCELLED;
2845    }
2846
2847    mAudioTearDown = true;
2848    mIsAsyncPrepare = true;
2849
2850    // Call prepare for the host decoding
2851    beginPrepareAsync_l();
2852}
2853
2854}  // namespace android
2855