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