AwesomePlayer.cpp revision 22f03209ceed3bcdf8c6558fcf02dc7699dde259
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                delete mAudioPlayer;
931                mAudioPlayer = NULL;
932                // if the player was started it will take care of stopping the source when destroyed
933                if (!(mFlags & AUDIOPLAYER_STARTED)) {
934                    mAudioSource->stop();
935                }
936                modifyFlags((AUDIO_RUNNING | AUDIOPLAYER_STARTED), CLEAR);
937                mOffloadAudio = false;
938                mAudioSource = mOmxSource;
939                if (mAudioSource != NULL) {
940                    err = mAudioSource->start();
941
942                    if (err != OK) {
943                        mAudioSource.clear();
944                    } else {
945                        createAudioPlayer_l();
946                        err = startAudioPlayer_l(false);
947                    }
948                }
949            }
950
951            if (err != OK) {
952                delete mAudioPlayer;
953                mAudioPlayer = NULL;
954
955                modifyFlags((PLAYING | FIRST_FRAME), CLEAR);
956
957                if (mDecryptHandle != NULL) {
958                    mDrmManagerClient->setPlaybackStatus(
959                            mDecryptHandle, Playback::STOP, 0);
960                }
961
962                return err;
963            }
964        }
965    }
966
967    if (mTimeSource == NULL && mAudioPlayer == NULL) {
968        mTimeSource = &mSystemTimeSource;
969    }
970
971    if (mVideoSource != NULL) {
972        // Kick off video playback
973        postVideoEvent_l();
974
975        if (mAudioSource != NULL && mVideoSource != NULL) {
976            postVideoLagEvent_l();
977        }
978    }
979
980    if (mFlags & AT_EOS) {
981        // Legacy behaviour, if a stream finishes playing and then
982        // is started again, we play from the start...
983        seekTo_l(0);
984    }
985
986    uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted
987        | IMediaPlayerService::kBatteryDataTrackDecoder;
988    if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
989        params |= IMediaPlayerService::kBatteryDataTrackAudio;
990    }
991    if (mVideoSource != NULL) {
992        params |= IMediaPlayerService::kBatteryDataTrackVideo;
993    }
994    addBatteryData(params);
995
996    return OK;
997}
998
999void AwesomePlayer::createAudioPlayer_l()
1000{
1001    uint32_t flags = 0;
1002    int64_t cachedDurationUs;
1003    bool eos;
1004
1005    if (mOffloadAudio) {
1006        flags |= AudioPlayer::USE_OFFLOAD;
1007    } else if (mVideoSource == NULL
1008            && (mDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US ||
1009            (getCachedDuration_l(&cachedDurationUs, &eos) &&
1010            cachedDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US))) {
1011        flags |= AudioPlayer::ALLOW_DEEP_BUFFERING;
1012    }
1013    if (isStreamingHTTP()) {
1014        flags |= AudioPlayer::IS_STREAMING;
1015    }
1016    if (mVideoSource != NULL) {
1017        flags |= AudioPlayer::HAS_VIDEO;
1018    }
1019
1020    mAudioPlayer = new AudioPlayer(mAudioSink, flags, this);
1021    mAudioPlayer->setSource(mAudioSource);
1022
1023    mTimeSource = mAudioPlayer;
1024
1025    // If there was a seek request before we ever started,
1026    // honor the request now.
1027    // Make sure to do this before starting the audio player
1028    // to avoid a race condition.
1029    seekAudioIfNecessary_l();
1030}
1031
1032void AwesomePlayer::notifyIfMediaStarted_l() {
1033    if (mMediaRenderingStartGeneration == mStartGeneration) {
1034        mMediaRenderingStartGeneration = -1;
1035        notifyListener_l(MEDIA_STARTED);
1036    }
1037}
1038
1039status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) {
1040    CHECK(!(mFlags & AUDIO_RUNNING));
1041    status_t err = OK;
1042
1043    if (mAudioSource == NULL || mAudioPlayer == NULL) {
1044        return OK;
1045    }
1046
1047    if (mOffloadAudio) {
1048        mQueue.cancelEvent(mAudioTearDownEvent->eventID());
1049        mAudioTearDownEventPending = false;
1050    }
1051
1052    if (!(mFlags & AUDIOPLAYER_STARTED)) {
1053        bool wasSeeking = mAudioPlayer->isSeeking();
1054
1055        // We've already started the MediaSource in order to enable
1056        // the prefetcher to read its data.
1057        err = mAudioPlayer->start(
1058                true /* sourceAlreadyStarted */);
1059
1060        if (err != OK) {
1061            if (sendErrorNotification) {
1062                notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1063            }
1064
1065            return err;
1066        }
1067
1068        modifyFlags(AUDIOPLAYER_STARTED, SET);
1069
1070        if (wasSeeking) {
1071            CHECK(!mAudioPlayer->isSeeking());
1072
1073            // We will have finished the seek while starting the audio player.
1074            postAudioSeekComplete();
1075        } else {
1076            notifyIfMediaStarted_l();
1077        }
1078    } else {
1079        err = mAudioPlayer->resume();
1080    }
1081
1082    if (err == OK) {
1083        modifyFlags(AUDIO_RUNNING, SET);
1084
1085        mWatchForAudioEOS = true;
1086    }
1087
1088    return err;
1089}
1090
1091void AwesomePlayer::notifyVideoSize_l() {
1092    ATRACE_CALL();
1093    sp<MetaData> meta = mVideoSource->getFormat();
1094
1095    int32_t cropLeft, cropTop, cropRight, cropBottom;
1096    if (!meta->findRect(
1097                kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
1098        int32_t width, height;
1099        CHECK(meta->findInt32(kKeyWidth, &width));
1100        CHECK(meta->findInt32(kKeyHeight, &height));
1101
1102        cropLeft = cropTop = 0;
1103        cropRight = width - 1;
1104        cropBottom = height - 1;
1105
1106        ALOGV("got dimensions only %d x %d", width, height);
1107    } else {
1108        ALOGV("got crop rect %d, %d, %d, %d",
1109             cropLeft, cropTop, cropRight, cropBottom);
1110    }
1111
1112    int32_t displayWidth;
1113    if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
1114        ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
1115        mDisplayWidth = displayWidth;
1116    }
1117    int32_t displayHeight;
1118    if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
1119        ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight);
1120        mDisplayHeight = displayHeight;
1121    }
1122
1123    int32_t usableWidth = cropRight - cropLeft + 1;
1124    int32_t usableHeight = cropBottom - cropTop + 1;
1125    if (mDisplayWidth != 0) {
1126        usableWidth = mDisplayWidth;
1127    }
1128    if (mDisplayHeight != 0) {
1129        usableHeight = mDisplayHeight;
1130    }
1131
1132    {
1133        Mutex::Autolock autoLock(mStatsLock);
1134        mStats.mVideoWidth = usableWidth;
1135        mStats.mVideoHeight = usableHeight;
1136    }
1137
1138    int32_t rotationDegrees;
1139    if (!mVideoTrack->getFormat()->findInt32(
1140                kKeyRotation, &rotationDegrees)) {
1141        rotationDegrees = 0;
1142    }
1143
1144    if (rotationDegrees == 90 || rotationDegrees == 270) {
1145        notifyListener_l(
1146                MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
1147    } else {
1148        notifyListener_l(
1149                MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
1150    }
1151}
1152
1153void AwesomePlayer::initRenderer_l() {
1154    ATRACE_CALL();
1155
1156    if (mNativeWindow == NULL) {
1157        return;
1158    }
1159
1160    sp<MetaData> meta = mVideoSource->getFormat();
1161
1162    int32_t format;
1163    const char *component;
1164    int32_t decodedWidth, decodedHeight;
1165    CHECK(meta->findInt32(kKeyColorFormat, &format));
1166    CHECK(meta->findCString(kKeyDecoderComponent, &component));
1167    CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
1168    CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
1169
1170    int32_t rotationDegrees;
1171    if (!mVideoTrack->getFormat()->findInt32(
1172                kKeyRotation, &rotationDegrees)) {
1173        rotationDegrees = 0;
1174    }
1175
1176    mVideoRenderer.clear();
1177
1178    // Must ensure that mVideoRenderer's destructor is actually executed
1179    // before creating a new one.
1180    IPCThreadState::self()->flushCommands();
1181
1182    // Even if set scaling mode fails, we will continue anyway
1183    setVideoScalingMode_l(mVideoScalingMode);
1184    if (USE_SURFACE_ALLOC
1185            && !strncmp(component, "OMX.", 4)
1186            && strncmp(component, "OMX.google.", 11)
1187            && strcmp(component, "OMX.Nvidia.mpeg2v.decode")) {
1188        // Hardware decoders avoid the CPU color conversion by decoding
1189        // directly to ANativeBuffers, so we must use a renderer that
1190        // just pushes those buffers to the ANativeWindow.
1191        mVideoRenderer =
1192            new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);
1193    } else {
1194        // Other decoders are instantiated locally and as a consequence
1195        // allocate their buffers in local address space.  This renderer
1196        // then performs a color conversion and copy to get the data
1197        // into the ANativeBuffer.
1198        mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta);
1199    }
1200}
1201
1202status_t AwesomePlayer::pause() {
1203    ATRACE_CALL();
1204
1205    Mutex::Autolock autoLock(mLock);
1206
1207    modifyFlags(CACHE_UNDERRUN, CLEAR);
1208
1209    return pause_l();
1210}
1211
1212status_t AwesomePlayer::pause_l(bool at_eos) {
1213    if (!(mFlags & PLAYING)) {
1214        return OK;
1215    }
1216
1217    notifyListener_l(MEDIA_PAUSED);
1218    mMediaRenderingStartGeneration = ++mStartGeneration;
1219
1220    cancelPlayerEvents(true /* keepNotifications */);
1221
1222    if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
1223        // If we played the audio stream to completion we
1224        // want to make sure that all samples remaining in the audio
1225        // track's queue are played out.
1226        mAudioPlayer->pause(at_eos /* playPendingSamples */);
1227        // send us a reminder to tear down the AudioPlayer if paused for too long.
1228        if (mOffloadAudio) {
1229            postAudioTearDownEvent(kOffloadPauseMaxUs);
1230        }
1231        modifyFlags(AUDIO_RUNNING, CLEAR);
1232    }
1233
1234    if (mFlags & TEXTPLAYER_INITIALIZED) {
1235        mTextDriver->pause();
1236        modifyFlags(TEXT_RUNNING, CLEAR);
1237    }
1238
1239    modifyFlags(PLAYING, CLEAR);
1240
1241    if (mDecryptHandle != NULL) {
1242        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1243                Playback::PAUSE, 0);
1244    }
1245
1246    uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
1247    if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
1248        params |= IMediaPlayerService::kBatteryDataTrackAudio;
1249    }
1250    if (mVideoSource != NULL) {
1251        params |= IMediaPlayerService::kBatteryDataTrackVideo;
1252    }
1253
1254    addBatteryData(params);
1255
1256    return OK;
1257}
1258
1259bool AwesomePlayer::isPlaying() const {
1260    return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
1261}
1262
1263status_t AwesomePlayer::setSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer) {
1264    Mutex::Autolock autoLock(mLock);
1265
1266    status_t err;
1267    if (bufferProducer != NULL) {
1268        err = setNativeWindow_l(new Surface(bufferProducer));
1269    } else {
1270        err = setNativeWindow_l(NULL);
1271    }
1272
1273    return err;
1274}
1275
1276void AwesomePlayer::shutdownVideoDecoder_l() {
1277    if (mVideoBuffer) {
1278        mVideoBuffer->release();
1279        mVideoBuffer = NULL;
1280    }
1281
1282    mVideoSource->stop();
1283
1284    // The following hack is necessary to ensure that the OMX
1285    // component is completely released by the time we may try
1286    // to instantiate it again.
1287    wp<MediaSource> tmp = mVideoSource;
1288    mVideoSource.clear();
1289    while (tmp.promote() != NULL) {
1290        usleep(1000);
1291    }
1292    IPCThreadState::self()->flushCommands();
1293    ALOGV("video decoder shutdown completed");
1294}
1295
1296status_t AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
1297    mNativeWindow = native;
1298
1299    if (mVideoSource == NULL) {
1300        return OK;
1301    }
1302
1303    ALOGV("attempting to reconfigure to use new surface");
1304
1305    bool wasPlaying = (mFlags & PLAYING) != 0;
1306
1307    pause_l();
1308    mVideoRenderer.clear();
1309
1310    shutdownVideoDecoder_l();
1311
1312    status_t err = initVideoDecoder();
1313
1314    if (err != OK) {
1315        ALOGE("failed to reinstantiate video decoder after surface change.");
1316        return err;
1317    }
1318
1319    if (mLastVideoTimeUs >= 0) {
1320        mSeeking = SEEK;
1321        mSeekTimeUs = mLastVideoTimeUs;
1322        modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
1323    }
1324
1325    if (wasPlaying) {
1326        play_l();
1327    }
1328
1329    return OK;
1330}
1331
1332void AwesomePlayer::setAudioSink(
1333        const sp<MediaPlayerBase::AudioSink> &audioSink) {
1334    Mutex::Autolock autoLock(mLock);
1335
1336    mAudioSink = audioSink;
1337}
1338
1339status_t AwesomePlayer::setLooping(bool shouldLoop) {
1340    Mutex::Autolock autoLock(mLock);
1341
1342    modifyFlags(LOOPING, CLEAR);
1343
1344    if (shouldLoop) {
1345        modifyFlags(LOOPING, SET);
1346    }
1347
1348    return OK;
1349}
1350
1351status_t AwesomePlayer::getDuration(int64_t *durationUs) {
1352    Mutex::Autolock autoLock(mMiscStateLock);
1353
1354    if (mDurationUs < 0) {
1355        return UNKNOWN_ERROR;
1356    }
1357
1358    *durationUs = mDurationUs;
1359
1360    return OK;
1361}
1362
1363status_t AwesomePlayer::getPosition(int64_t *positionUs) {
1364    if (mSeeking != NO_SEEK) {
1365        *positionUs = mSeekTimeUs;
1366    } else if (mVideoSource != NULL
1367            && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
1368        Mutex::Autolock autoLock(mMiscStateLock);
1369        *positionUs = mVideoTimeUs;
1370    } else if (mAudioPlayer != NULL) {
1371        *positionUs = mAudioPlayer->getMediaTimeUs();
1372    } else {
1373        *positionUs = 0;
1374    }
1375    return OK;
1376}
1377
1378status_t AwesomePlayer::seekTo(int64_t timeUs) {
1379    ATRACE_CALL();
1380
1381    if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
1382        Mutex::Autolock autoLock(mLock);
1383        return seekTo_l(timeUs);
1384    }
1385
1386    return OK;
1387}
1388
1389status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
1390    if (mFlags & CACHE_UNDERRUN) {
1391        modifyFlags(CACHE_UNDERRUN, CLEAR);
1392        play_l();
1393    }
1394
1395    if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) {
1396        // Video playback completed before, there's no pending
1397        // video event right now. In order for this new seek
1398        // to be honored, we need to post one.
1399
1400        postVideoEvent_l();
1401    }
1402
1403    mSeeking = SEEK;
1404    mSeekNotificationSent = false;
1405    mSeekTimeUs = timeUs;
1406    modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
1407
1408    notifyListener_l(MEDIA_PAUSED);
1409    mMediaRenderingStartGeneration = ++mStartGeneration;
1410
1411    seekAudioIfNecessary_l();
1412
1413    if (mFlags & TEXTPLAYER_INITIALIZED) {
1414        mTextDriver->seekToAsync(mSeekTimeUs);
1415    }
1416
1417    if (!(mFlags & PLAYING)) {
1418        ALOGV("seeking while paused, sending SEEK_COMPLETE notification"
1419             " immediately.");
1420
1421        notifyListener_l(MEDIA_SEEK_COMPLETE);
1422        mSeekNotificationSent = true;
1423
1424        if ((mFlags & PREPARED) && mVideoSource != NULL) {
1425            modifyFlags(SEEK_PREVIEW, SET);
1426            postVideoEvent_l();
1427        }
1428    }
1429
1430    return OK;
1431}
1432
1433void AwesomePlayer::seekAudioIfNecessary_l() {
1434    if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) {
1435        mAudioPlayer->seekTo(mSeekTimeUs);
1436
1437        mWatchForAudioSeekComplete = true;
1438        mWatchForAudioEOS = true;
1439
1440        if (mDecryptHandle != NULL) {
1441            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1442                    Playback::PAUSE, 0);
1443            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1444                    Playback::START, mSeekTimeUs / 1000);
1445        }
1446    }
1447}
1448
1449void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
1450    CHECK(source != NULL);
1451
1452    mAudioTrack = source;
1453}
1454
1455void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp<MediaSource>& source) {
1456    CHECK(source != NULL);
1457
1458    if (mTextDriver == NULL) {
1459        mTextDriver = new TimedTextDriver(mListener);
1460    }
1461
1462    mTextDriver->addInBandTextSource(trackIndex, source);
1463}
1464
1465status_t AwesomePlayer::initAudioDecoder() {
1466    ATRACE_CALL();
1467
1468    sp<MetaData> meta = mAudioTrack->getFormat();
1469
1470    const char *mime;
1471    CHECK(meta->findCString(kKeyMIMEType, &mime));
1472    // Check whether there is a hardware codec for this stream
1473    // This doesn't guarantee that the hardware has a free stream
1474    // but it avoids us attempting to open (and re-open) an offload
1475    // stream to hardware that doesn't have the necessary codec
1476    mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL), isStreamingHTTP());
1477
1478    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
1479        ALOGV("createAudioPlayer: bypass OMX (raw)");
1480        mAudioSource = mAudioTrack;
1481    } else {
1482        // If offloading we still create a OMX decoder as a fall-back
1483        // but we don't start it
1484        mOmxSource = OMXCodec::Create(
1485                mClient.interface(), mAudioTrack->getFormat(),
1486                false, // createEncoder
1487                mAudioTrack);
1488
1489        if (mOffloadAudio) {
1490            ALOGV("createAudioPlayer: bypass OMX (offload)");
1491            mAudioSource = mAudioTrack;
1492        } else {
1493            mAudioSource = mOmxSource;
1494        }
1495    }
1496
1497    if (mAudioSource != NULL) {
1498        int64_t durationUs;
1499        if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1500            Mutex::Autolock autoLock(mMiscStateLock);
1501            if (mDurationUs < 0 || durationUs > mDurationUs) {
1502                mDurationUs = durationUs;
1503            }
1504        }
1505
1506        status_t err = mAudioSource->start();
1507
1508        if (err != OK) {
1509            mAudioSource.clear();
1510            mOmxSource.clear();
1511            return err;
1512        }
1513    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1514        // For legacy reasons we're simply going to ignore the absence
1515        // of an audio decoder for QCELP instead of aborting playback
1516        // altogether.
1517        return OK;
1518    }
1519
1520    if (mAudioSource != NULL) {
1521        Mutex::Autolock autoLock(mStatsLock);
1522        TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
1523        const char *component;
1524        if (!mAudioSource->getFormat()
1525                ->findCString(kKeyDecoderComponent, &component)) {
1526            component = "none";
1527        }
1528
1529        stat->mDecoderName = component;
1530    }
1531
1532    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1533}
1534
1535void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1536    CHECK(source != NULL);
1537
1538    mVideoTrack = source;
1539}
1540
1541status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
1542    ATRACE_CALL();
1543
1544    // Either the application or the DRM system can independently say
1545    // that there must be a hardware-protected path to an external video sink.
1546    // For now we always require a hardware-protected path to external video sink
1547    // if content is DRMed, but eventually this could be optional per DRM agent.
1548    // When the application wants protection, then
1549    //   (USE_SURFACE_ALLOC && (mSurface != 0) &&
1550    //   (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp))
1551    // will be true, but that part is already handled by SurfaceFlinger.
1552
1553#ifdef DEBUG_HDCP
1554    // For debugging, we allow a system property to control the protected usage.
1555    // In case of uninitialized or unexpected property, we default to "DRM only".
1556    bool setProtectionBit = false;
1557    char value[PROPERTY_VALUE_MAX];
1558    if (property_get("persist.sys.hdcp_checking", value, NULL)) {
1559        if (!strcmp(value, "never")) {
1560            // nop
1561        } else if (!strcmp(value, "always")) {
1562            setProtectionBit = true;
1563        } else if (!strcmp(value, "drm-only")) {
1564            if (mDecryptHandle != NULL) {
1565                setProtectionBit = true;
1566            }
1567        // property value is empty, or unexpected value
1568        } else {
1569            if (mDecryptHandle != NULL) {
1570                setProtectionBit = true;
1571            }
1572        }
1573    // can' read property value
1574    } else {
1575        if (mDecryptHandle != NULL) {
1576            setProtectionBit = true;
1577        }
1578    }
1579    // note that usage bit is already cleared, so no need to clear it in the "else" case
1580    if (setProtectionBit) {
1581        flags |= OMXCodec::kEnableGrallocUsageProtected;
1582    }
1583#else
1584    if (mDecryptHandle != NULL) {
1585        flags |= OMXCodec::kEnableGrallocUsageProtected;
1586    }
1587#endif
1588    ALOGV("initVideoDecoder flags=0x%x", flags);
1589    mVideoSource = OMXCodec::Create(
1590            mClient.interface(), mVideoTrack->getFormat(),
1591            false, // createEncoder
1592            mVideoTrack,
1593            NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
1594
1595    if (mVideoSource != NULL) {
1596        int64_t durationUs;
1597        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1598            Mutex::Autolock autoLock(mMiscStateLock);
1599            if (mDurationUs < 0 || durationUs > mDurationUs) {
1600                mDurationUs = durationUs;
1601            }
1602        }
1603
1604        status_t err = mVideoSource->start();
1605
1606        if (err != OK) {
1607            ALOGE("failed to start video source");
1608            mVideoSource.clear();
1609            return err;
1610        }
1611    }
1612
1613    if (mVideoSource != NULL) {
1614        const char *componentName;
1615        CHECK(mVideoSource->getFormat()
1616                ->findCString(kKeyDecoderComponent, &componentName));
1617
1618        {
1619            Mutex::Autolock autoLock(mStatsLock);
1620            TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
1621
1622            stat->mDecoderName = componentName;
1623        }
1624
1625        static const char *kPrefix = "OMX.Nvidia.";
1626        static const char *kSuffix = ".decode";
1627        static const size_t kSuffixLength = strlen(kSuffix);
1628
1629        size_t componentNameLength = strlen(componentName);
1630
1631        if (!strncmp(componentName, kPrefix, strlen(kPrefix))
1632                && componentNameLength >= kSuffixLength
1633                && !strcmp(&componentName[
1634                    componentNameLength - kSuffixLength], kSuffix)) {
1635            modifyFlags(SLOW_DECODER_HACK, SET);
1636        }
1637    }
1638
1639    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1640}
1641
1642void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1643    ATRACE_CALL();
1644
1645    if (mSeeking == SEEK_VIDEO_ONLY) {
1646        mSeeking = NO_SEEK;
1647        return;
1648    }
1649
1650    if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) {
1651        return;
1652    }
1653
1654    if (mAudioPlayer != NULL) {
1655        ALOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
1656
1657        // If we don't have a video time, seek audio to the originally
1658        // requested seek time instead.
1659
1660        mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1661        mWatchForAudioSeekComplete = true;
1662        mWatchForAudioEOS = true;
1663    } else if (!mSeekNotificationSent) {
1664        // If we're playing video only, report seek complete now,
1665        // otherwise audio player will notify us later.
1666        notifyListener_l(MEDIA_SEEK_COMPLETE);
1667        mSeekNotificationSent = true;
1668    }
1669
1670    modifyFlags(FIRST_FRAME, SET);
1671    mSeeking = NO_SEEK;
1672
1673    if (mDecryptHandle != NULL) {
1674        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1675                Playback::PAUSE, 0);
1676        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1677                Playback::START, videoTimeUs / 1000);
1678    }
1679}
1680
1681void AwesomePlayer::onVideoEvent() {
1682    ATRACE_CALL();
1683    Mutex::Autolock autoLock(mLock);
1684    if (!mVideoEventPending) {
1685        // The event has been cancelled in reset_l() but had already
1686        // been scheduled for execution at that time.
1687        return;
1688    }
1689    mVideoEventPending = false;
1690
1691    if (mSeeking != NO_SEEK) {
1692        if (mVideoBuffer) {
1693            mVideoBuffer->release();
1694            mVideoBuffer = NULL;
1695        }
1696
1697        if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL
1698                && !(mFlags & SEEK_PREVIEW)) {
1699            // We're going to seek the video source first, followed by
1700            // the audio source.
1701            // In order to avoid jumps in the DataSource offset caused by
1702            // the audio codec prefetching data from the old locations
1703            // while the video codec is already reading data from the new
1704            // locations, we'll "pause" the audio source, causing it to
1705            // stop reading input data until a subsequent seek.
1706
1707            if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
1708                mAudioPlayer->pause();
1709
1710                modifyFlags(AUDIO_RUNNING, CLEAR);
1711            }
1712            mAudioSource->pause();
1713        }
1714    }
1715
1716    if (!mVideoBuffer) {
1717        MediaSource::ReadOptions options;
1718        if (mSeeking != NO_SEEK) {
1719            ALOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1720
1721            options.setSeekTo(
1722                    mSeekTimeUs,
1723                    mSeeking == SEEK_VIDEO_ONLY
1724                        ? MediaSource::ReadOptions::SEEK_NEXT_SYNC
1725                        : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
1726        }
1727        for (;;) {
1728            status_t err = mVideoSource->read(&mVideoBuffer, &options);
1729            options.clearSeekTo();
1730
1731            if (err != OK) {
1732                CHECK(mVideoBuffer == NULL);
1733
1734                if (err == INFO_FORMAT_CHANGED) {
1735                    ALOGV("VideoSource signalled format change.");
1736
1737                    notifyVideoSize_l();
1738
1739                    if (mVideoRenderer != NULL) {
1740                        mVideoRendererIsPreview = false;
1741                        initRenderer_l();
1742                    }
1743                    continue;
1744                }
1745
1746                // So video playback is complete, but we may still have
1747                // a seek request pending that needs to be applied
1748                // to the audio track.
1749                if (mSeeking != NO_SEEK) {
1750                    ALOGV("video stream ended while seeking!");
1751                }
1752                finishSeekIfNecessary(-1);
1753
1754                if (mAudioPlayer != NULL
1755                        && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1756                    startAudioPlayer_l();
1757                }
1758
1759                modifyFlags(VIDEO_AT_EOS, SET);
1760                postStreamDoneEvent_l(err);
1761                return;
1762            }
1763
1764            if (mVideoBuffer->range_length() == 0) {
1765                // Some decoders, notably the PV AVC software decoder
1766                // return spurious empty buffers that we just want to ignore.
1767
1768                mVideoBuffer->release();
1769                mVideoBuffer = NULL;
1770                continue;
1771            }
1772
1773            break;
1774        }
1775
1776        {
1777            Mutex::Autolock autoLock(mStatsLock);
1778            ++mStats.mNumVideoFramesDecoded;
1779        }
1780    }
1781
1782    int64_t timeUs;
1783    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1784
1785    mLastVideoTimeUs = timeUs;
1786
1787    if (mSeeking == SEEK_VIDEO_ONLY) {
1788        if (mSeekTimeUs > timeUs) {
1789            ALOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us",
1790                 mSeekTimeUs, timeUs);
1791        }
1792    }
1793
1794    {
1795        Mutex::Autolock autoLock(mMiscStateLock);
1796        mVideoTimeUs = timeUs;
1797    }
1798
1799    SeekType wasSeeking = mSeeking;
1800    finishSeekIfNecessary(timeUs);
1801
1802    if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1803        status_t err = startAudioPlayer_l();
1804        if (err != OK) {
1805            ALOGE("Starting the audio player failed w/ err %d", err);
1806            return;
1807        }
1808    }
1809
1810    if ((mFlags & TEXTPLAYER_INITIALIZED)
1811            && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
1812        mTextDriver->start();
1813        modifyFlags(TEXT_RUNNING, SET);
1814    }
1815
1816    TimeSource *ts =
1817        ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED))
1818            ? &mSystemTimeSource : mTimeSource;
1819
1820    if (mFlags & FIRST_FRAME) {
1821        modifyFlags(FIRST_FRAME, CLEAR);
1822        mSinceLastDropped = 0;
1823        mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
1824    }
1825
1826    int64_t realTimeUs, mediaTimeUs;
1827    if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
1828        && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1829        mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1830    }
1831
1832    if (wasSeeking == SEEK_VIDEO_ONLY) {
1833        int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1834
1835        int64_t latenessUs = nowUs - timeUs;
1836
1837        ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
1838
1839        if (latenessUs > 0) {
1840            ALOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6);
1841        }
1842    }
1843
1844    if (wasSeeking == NO_SEEK) {
1845        // Let's display the first frame after seeking right away.
1846
1847        int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1848
1849        int64_t latenessUs = nowUs - timeUs;
1850
1851        ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
1852
1853        if (latenessUs > 500000ll
1854                && mAudioPlayer != NULL
1855                && mAudioPlayer->getMediaTimeMapping(
1856                    &realTimeUs, &mediaTimeUs)) {
1857            if (mWVMExtractor == NULL) {
1858                ALOGI("we're much too late (%.2f secs), video skipping ahead",
1859                     latenessUs / 1E6);
1860
1861                mVideoBuffer->release();
1862                mVideoBuffer = NULL;
1863
1864                mSeeking = SEEK_VIDEO_ONLY;
1865                mSeekTimeUs = mediaTimeUs;
1866
1867                postVideoEvent_l();
1868                return;
1869            } else {
1870                // The widevine extractor doesn't deal well with seeking
1871                // audio and video independently. We'll just have to wait
1872                // until the decoder catches up, which won't be long at all.
1873                ALOGI("we're very late (%.2f secs)", latenessUs / 1E6);
1874            }
1875        }
1876
1877        if (latenessUs > 40000) {
1878            // We're more than 40ms late.
1879            ALOGV("we're late by %lld us (%.2f secs)",
1880                 latenessUs, latenessUs / 1E6);
1881
1882            if (!(mFlags & SLOW_DECODER_HACK)
1883                    || mSinceLastDropped > FRAME_DROP_FREQ)
1884            {
1885                ALOGV("we're late by %lld us (%.2f secs) dropping "
1886                     "one after %d frames",
1887                     latenessUs, latenessUs / 1E6, mSinceLastDropped);
1888
1889                mSinceLastDropped = 0;
1890                mVideoBuffer->release();
1891                mVideoBuffer = NULL;
1892
1893                {
1894                    Mutex::Autolock autoLock(mStatsLock);
1895                    ++mStats.mNumVideoFramesDropped;
1896                }
1897
1898                postVideoEvent_l();
1899                return;
1900            }
1901        }
1902
1903        if (latenessUs < -10000) {
1904            // We're more than 10ms early.
1905            postVideoEvent_l(10000);
1906            return;
1907        }
1908    }
1909
1910    if ((mNativeWindow != NULL)
1911            && (mVideoRendererIsPreview || mVideoRenderer == NULL)) {
1912        mVideoRendererIsPreview = false;
1913
1914        initRenderer_l();
1915    }
1916
1917    if (mVideoRenderer != NULL) {
1918        mSinceLastDropped++;
1919        mVideoRenderer->render(mVideoBuffer);
1920        if (!mVideoRenderingStarted) {
1921            mVideoRenderingStarted = true;
1922            notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START);
1923        }
1924
1925        notifyIfMediaStarted_l();
1926    }
1927
1928    mVideoBuffer->release();
1929    mVideoBuffer = NULL;
1930
1931    if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) {
1932        modifyFlags(SEEK_PREVIEW, CLEAR);
1933        return;
1934    }
1935
1936    postVideoEvent_l();
1937}
1938
1939void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1940    ATRACE_CALL();
1941
1942    if (mVideoEventPending) {
1943        return;
1944    }
1945
1946    mVideoEventPending = true;
1947    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1948}
1949
1950void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
1951    if (mStreamDoneEventPending) {
1952        return;
1953    }
1954    mStreamDoneEventPending = true;
1955
1956    mStreamDoneStatus = status;
1957    mQueue.postEvent(mStreamDoneEvent);
1958}
1959
1960void AwesomePlayer::postBufferingEvent_l() {
1961    if (mBufferingEventPending) {
1962        return;
1963    }
1964    mBufferingEventPending = true;
1965    mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1966}
1967
1968void AwesomePlayer::postVideoLagEvent_l() {
1969    if (mVideoLagEventPending) {
1970        return;
1971    }
1972    mVideoLagEventPending = true;
1973    mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
1974}
1975
1976void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) {
1977    Mutex::Autolock autoLock(mAudioLock);
1978    if (mAudioStatusEventPending) {
1979        return;
1980    }
1981    mAudioStatusEventPending = true;
1982    // Do not honor delay when looping in order to limit audio gap
1983    if (mFlags & (LOOPING | AUTO_LOOPING)) {
1984        delayUs = 0;
1985    }
1986    mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs);
1987}
1988
1989void AwesomePlayer::postAudioTearDownEvent(int64_t delayUs) {
1990    Mutex::Autolock autoLock(mAudioLock);
1991    if (mAudioTearDownEventPending) {
1992        return;
1993    }
1994    mAudioTearDownEventPending = true;
1995    mQueue.postEventWithDelay(mAudioTearDownEvent, delayUs);
1996}
1997
1998void AwesomePlayer::onCheckAudioStatus() {
1999    {
2000        Mutex::Autolock autoLock(mAudioLock);
2001        if (!mAudioStatusEventPending) {
2002            // Event was dispatched and while we were blocking on the mutex,
2003            // has already been cancelled.
2004            return;
2005        }
2006
2007        mAudioStatusEventPending = false;
2008    }
2009
2010    Mutex::Autolock autoLock(mLock);
2011
2012    if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
2013        mWatchForAudioSeekComplete = false;
2014
2015        if (!mSeekNotificationSent) {
2016            notifyListener_l(MEDIA_SEEK_COMPLETE);
2017            mSeekNotificationSent = true;
2018        }
2019
2020        mSeeking = NO_SEEK;
2021
2022        notifyIfMediaStarted_l();
2023    }
2024
2025    status_t finalStatus;
2026    if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
2027        mWatchForAudioEOS = false;
2028        modifyFlags(AUDIO_AT_EOS, SET);
2029        modifyFlags(FIRST_FRAME, SET);
2030        postStreamDoneEvent_l(finalStatus);
2031    }
2032}
2033
2034status_t AwesomePlayer::prepare() {
2035    ATRACE_CALL();
2036    Mutex::Autolock autoLock(mLock);
2037    return prepare_l();
2038}
2039
2040status_t AwesomePlayer::prepare_l() {
2041    if (mFlags & PREPARED) {
2042        return OK;
2043    }
2044
2045    if (mFlags & PREPARING) {
2046        return UNKNOWN_ERROR;
2047    }
2048
2049    mIsAsyncPrepare = false;
2050    status_t err = prepareAsync_l();
2051
2052    if (err != OK) {
2053        return err;
2054    }
2055
2056    while (mFlags & PREPARING) {
2057        mPreparedCondition.wait(mLock);
2058    }
2059
2060    return mPrepareResult;
2061}
2062
2063status_t AwesomePlayer::prepareAsync() {
2064    ATRACE_CALL();
2065    Mutex::Autolock autoLock(mLock);
2066
2067    if (mFlags & PREPARING) {
2068        return UNKNOWN_ERROR;  // async prepare already pending
2069    }
2070
2071    mIsAsyncPrepare = true;
2072    return prepareAsync_l();
2073}
2074
2075status_t AwesomePlayer::prepareAsync_l() {
2076    if (mFlags & PREPARING) {
2077        return UNKNOWN_ERROR;  // async prepare already pending
2078    }
2079
2080    if (!mQueueStarted) {
2081        mQueue.start();
2082        mQueueStarted = true;
2083    }
2084
2085    modifyFlags(PREPARING, SET);
2086    mAsyncPrepareEvent = new AwesomeEvent(
2087            this, &AwesomePlayer::onPrepareAsyncEvent);
2088
2089    mQueue.postEvent(mAsyncPrepareEvent);
2090
2091    return OK;
2092}
2093
2094status_t AwesomePlayer::finishSetDataSource_l() {
2095    ATRACE_CALL();
2096    sp<DataSource> dataSource;
2097
2098    bool isWidevineStreaming = false;
2099    if (!strncasecmp("widevine://", mUri.string(), 11)) {
2100        isWidevineStreaming = true;
2101
2102        String8 newURI = String8("http://");
2103        newURI.append(mUri.string() + 11);
2104
2105        mUri = newURI;
2106    }
2107
2108    AString sniffedMIME;
2109
2110    if (!strncasecmp("http://", mUri.string(), 7)
2111            || !strncasecmp("https://", mUri.string(), 8)
2112            || isWidevineStreaming) {
2113        mConnectingDataSource = HTTPBase::Create(
2114                (mFlags & INCOGNITO)
2115                    ? HTTPBase::kFlagIncognito
2116                    : 0);
2117
2118        if (mUIDValid) {
2119            mConnectingDataSource->setUID(mUID);
2120        }
2121
2122        String8 cacheConfig;
2123        bool disconnectAtHighwatermark;
2124        NuCachedSource2::RemoveCacheSpecificHeaders(
2125                &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark);
2126
2127        mLock.unlock();
2128        status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
2129        mLock.lock();
2130
2131        if (err != OK) {
2132            mConnectingDataSource.clear();
2133
2134            ALOGI("mConnectingDataSource->connect() returned %d", err);
2135            return err;
2136        }
2137
2138        if (!isWidevineStreaming) {
2139            // The widevine extractor does its own caching.
2140
2141#if 0
2142            mCachedSource = new NuCachedSource2(
2143                    new ThrottledSource(
2144                        mConnectingDataSource, 50 * 1024 /* bytes/sec */));
2145#else
2146            mCachedSource = new NuCachedSource2(
2147                    mConnectingDataSource,
2148                    cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
2149                    disconnectAtHighwatermark);
2150#endif
2151
2152            dataSource = mCachedSource;
2153        } else {
2154            dataSource = mConnectingDataSource;
2155        }
2156
2157        mConnectingDataSource.clear();
2158
2159        String8 contentType = dataSource->getMIMEType();
2160
2161        if (strncasecmp(contentType.string(), "audio/", 6)) {
2162            // We're not doing this for streams that appear to be audio-only
2163            // streams to ensure that even low bandwidth streams start
2164            // playing back fairly instantly.
2165
2166            // We're going to prefill the cache before trying to instantiate
2167            // the extractor below, as the latter is an operation that otherwise
2168            // could block on the datasource for a significant amount of time.
2169            // During that time we'd be unable to abort the preparation phase
2170            // without this prefill.
2171            if (mCachedSource != NULL) {
2172                // We're going to prefill the cache before trying to instantiate
2173                // the extractor below, as the latter is an operation that otherwise
2174                // could block on the datasource for a significant amount of time.
2175                // During that time we'd be unable to abort the preparation phase
2176                // without this prefill.
2177
2178                mLock.unlock();
2179
2180                // Initially make sure we have at least 192 KB for the sniff
2181                // to complete without blocking.
2182                static const size_t kMinBytesForSniffing = 192 * 1024;
2183
2184                off64_t metaDataSize = -1ll;
2185                for (;;) {
2186                    status_t finalStatus;
2187                    size_t cachedDataRemaining =
2188                        mCachedSource->approxDataRemaining(&finalStatus);
2189
2190                    if (finalStatus != OK
2191                            || (metaDataSize >= 0
2192                                && cachedDataRemaining >= metaDataSize)
2193                            || (mFlags & PREPARE_CANCELLED)) {
2194                        break;
2195                    }
2196
2197                    ALOGV("now cached %d bytes of data", cachedDataRemaining);
2198
2199                    if (metaDataSize < 0
2200                            && cachedDataRemaining >= kMinBytesForSniffing) {
2201                        String8 tmp;
2202                        float confidence;
2203                        sp<AMessage> meta;
2204                        if (!dataSource->sniff(&tmp, &confidence, &meta)) {
2205                            mLock.lock();
2206                            return UNKNOWN_ERROR;
2207                        }
2208
2209                        // We successfully identified the file's extractor to
2210                        // be, remember this mime type so we don't have to
2211                        // sniff it again when we call MediaExtractor::Create()
2212                        // below.
2213                        sniffedMIME = tmp.string();
2214
2215                        if (meta == NULL
2216                                || !meta->findInt64(
2217                                    "meta-data-size", &metaDataSize)) {
2218                            metaDataSize = kHighWaterMarkBytes;
2219                        }
2220
2221                        CHECK_GE(metaDataSize, 0ll);
2222                        ALOGV("metaDataSize = %lld bytes", metaDataSize);
2223                    }
2224
2225                    usleep(200000);
2226                }
2227
2228                mLock.lock();
2229            }
2230
2231            if (mFlags & PREPARE_CANCELLED) {
2232                ALOGI("Prepare cancelled while waiting for initial cache fill.");
2233                return UNKNOWN_ERROR;
2234            }
2235        }
2236    } else {
2237        dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
2238    }
2239
2240    if (dataSource == NULL) {
2241        return UNKNOWN_ERROR;
2242    }
2243
2244    sp<MediaExtractor> extractor;
2245
2246    if (isWidevineStreaming) {
2247        String8 mimeType;
2248        float confidence;
2249        sp<AMessage> dummy;
2250        bool success;
2251
2252        // SniffWVM is potentially blocking since it may require network access.
2253        // Do not call it with mLock held.
2254        mLock.unlock();
2255        success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
2256        mLock.lock();
2257
2258        if (!success
2259                || strcasecmp(
2260                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
2261            return ERROR_UNSUPPORTED;
2262        }
2263
2264        mWVMExtractor = new WVMExtractor(dataSource);
2265        mWVMExtractor->setAdaptiveStreamingMode(true);
2266        if (mUIDValid)
2267            mWVMExtractor->setUID(mUID);
2268        extractor = mWVMExtractor;
2269    } else {
2270        extractor = MediaExtractor::Create(
2271                dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
2272
2273        if (extractor == NULL) {
2274            return UNKNOWN_ERROR;
2275        }
2276    }
2277
2278    if (extractor->getDrmFlag()) {
2279        checkDrmStatus(dataSource);
2280    }
2281
2282    status_t err = setDataSource_l(extractor);
2283
2284    if (err != OK) {
2285        mWVMExtractor.clear();
2286
2287        return err;
2288    }
2289
2290    return OK;
2291}
2292
2293void AwesomePlayer::abortPrepare(status_t err) {
2294    CHECK(err != OK);
2295
2296    if (mIsAsyncPrepare) {
2297        notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
2298    }
2299
2300    mPrepareResult = err;
2301    modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
2302    mAsyncPrepareEvent = NULL;
2303    mPreparedCondition.broadcast();
2304}
2305
2306// static
2307bool AwesomePlayer::ContinuePreparation(void *cookie) {
2308    AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
2309
2310    return (me->mFlags & PREPARE_CANCELLED) == 0;
2311}
2312
2313void AwesomePlayer::onPrepareAsyncEvent() {
2314    Mutex::Autolock autoLock(mLock);
2315    beginPrepareAsync_l();
2316}
2317
2318void AwesomePlayer::beginPrepareAsync_l() {
2319    if (mFlags & PREPARE_CANCELLED) {
2320        ALOGI("prepare was cancelled before doing anything");
2321        abortPrepare(UNKNOWN_ERROR);
2322        return;
2323    }
2324
2325    if (mUri.size() > 0) {
2326        status_t err = finishSetDataSource_l();
2327
2328        if (err != OK) {
2329            abortPrepare(err);
2330            return;
2331        }
2332    }
2333
2334    if (mVideoTrack != NULL && mVideoSource == NULL) {
2335        status_t err = initVideoDecoder();
2336
2337        if (err != OK) {
2338            abortPrepare(err);
2339            return;
2340        }
2341    }
2342
2343    if (mAudioTrack != NULL && mAudioSource == NULL) {
2344        status_t err = initAudioDecoder();
2345
2346        if (err != OK) {
2347            abortPrepare(err);
2348            return;
2349        }
2350    }
2351
2352    modifyFlags(PREPARING_CONNECTED, SET);
2353
2354    if (isStreamingHTTP()) {
2355        postBufferingEvent_l();
2356    } else {
2357        finishAsyncPrepare_l();
2358    }
2359}
2360
2361void AwesomePlayer::finishAsyncPrepare_l() {
2362    if (mIsAsyncPrepare) {
2363        if (mVideoSource == NULL) {
2364            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
2365        } else {
2366            notifyVideoSize_l();
2367        }
2368
2369        notifyListener_l(MEDIA_PREPARED);
2370    }
2371
2372    mPrepareResult = OK;
2373    modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
2374    modifyFlags(PREPARED, SET);
2375    mAsyncPrepareEvent = NULL;
2376    mPreparedCondition.broadcast();
2377}
2378
2379uint32_t AwesomePlayer::flags() const {
2380    return mExtractorFlags;
2381}
2382
2383void AwesomePlayer::postAudioEOS(int64_t delayUs) {
2384    postCheckAudioStatusEvent(delayUs);
2385}
2386
2387void AwesomePlayer::postAudioSeekComplete() {
2388    postCheckAudioStatusEvent(0);
2389}
2390
2391void AwesomePlayer::postAudioTearDown() {
2392    postAudioTearDownEvent(0);
2393}
2394
2395status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
2396    switch (key) {
2397        case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS:
2398        {
2399            return setCacheStatCollectFreq(request);
2400        }
2401        case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE:
2402        {
2403            if (mAudioPlayer != NULL) {
2404                return mAudioPlayer->setPlaybackRatePermille(request.readInt32());
2405            } else {
2406                return NO_INIT;
2407            }
2408        }
2409        default:
2410        {
2411            return ERROR_UNSUPPORTED;
2412        }
2413    }
2414}
2415
2416status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) {
2417    if (mCachedSource != NULL) {
2418        int32_t freqMs = request.readInt32();
2419        ALOGD("Request to keep cache stats in the past %d ms",
2420            freqMs);
2421        return mCachedSource->setCacheStatCollectFreq(freqMs);
2422    }
2423    return ERROR_UNSUPPORTED;
2424}
2425
2426status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
2427    switch (key) {
2428    case KEY_PARAMETER_AUDIO_CHANNEL_COUNT:
2429        {
2430            int32_t channelCount;
2431            if (mAudioTrack == 0 ||
2432                    !mAudioTrack->getFormat()->findInt32(kKeyChannelCount, &channelCount)) {
2433                channelCount = 0;
2434            }
2435            reply->writeInt32(channelCount);
2436        }
2437        return OK;
2438    default:
2439        {
2440            return ERROR_UNSUPPORTED;
2441        }
2442    }
2443}
2444
2445status_t AwesomePlayer::getTrackInfo(Parcel *reply) const {
2446    Mutex::Autolock autoLock(mLock);
2447    size_t trackCount = mExtractor->countTracks();
2448    if (mTextDriver != NULL) {
2449        trackCount += mTextDriver->countExternalTracks();
2450    }
2451
2452    reply->writeInt32(trackCount);
2453    for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
2454        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
2455
2456        const char *_mime;
2457        CHECK(meta->findCString(kKeyMIMEType, &_mime));
2458
2459        String8 mime = String8(_mime);
2460
2461        reply->writeInt32(2); // 2 fields
2462
2463        if (!strncasecmp(mime.string(), "video/", 6)) {
2464            reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO);
2465        } else if (!strncasecmp(mime.string(), "audio/", 6)) {
2466            reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO);
2467        } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
2468            reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
2469        } else {
2470            reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
2471        }
2472
2473        const char *lang;
2474        if (!meta->findCString(kKeyMediaLanguage, &lang)) {
2475            lang = "und";
2476        }
2477        reply->writeString16(String16(lang));
2478    }
2479
2480    if (mTextDriver != NULL) {
2481        mTextDriver->getExternalTrackInfo(reply);
2482    }
2483    return OK;
2484}
2485
2486status_t AwesomePlayer::selectAudioTrack_l(
2487        const sp<MediaSource>& source, size_t trackIndex) {
2488
2489    ALOGI("selectAudioTrack_l: trackIndex=%d, mFlags=0x%x", trackIndex, mFlags);
2490
2491    {
2492        Mutex::Autolock autoLock(mStatsLock);
2493        if ((ssize_t)trackIndex == mActiveAudioTrackIndex) {
2494            ALOGI("Track %d is active. Does nothing.", trackIndex);
2495            return OK;
2496        }
2497        //mStats.mFlags = mFlags;
2498    }
2499
2500    if (mSeeking != NO_SEEK) {
2501        ALOGE("Selecting a track while seeking is not supported");
2502        return ERROR_UNSUPPORTED;
2503    }
2504
2505    if ((mFlags & PREPARED) == 0) {
2506        ALOGE("Data source has not finished preparation");
2507        return ERROR_UNSUPPORTED;
2508    }
2509
2510    CHECK(source != NULL);
2511    bool wasPlaying = (mFlags & PLAYING) != 0;
2512
2513    pause_l();
2514
2515    int64_t curTimeUs;
2516    CHECK_EQ(getPosition(&curTimeUs), (status_t)OK);
2517
2518    if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
2519            && mAudioSource != NULL) {
2520        // If we had an audio player, it would have effectively
2521        // taken possession of the audio source and stopped it when
2522        // _it_ is stopped. Otherwise this is still our responsibility.
2523        mAudioSource->stop();
2524    }
2525    mAudioSource.clear();
2526    mOmxSource.clear();
2527
2528    mTimeSource = NULL;
2529
2530    delete mAudioPlayer;
2531    mAudioPlayer = NULL;
2532
2533    modifyFlags(AUDIOPLAYER_STARTED, CLEAR);
2534
2535    setAudioSource(source);
2536
2537    modifyFlags(AUDIO_AT_EOS, CLEAR);
2538    modifyFlags(AT_EOS, CLEAR);
2539
2540    status_t err;
2541    if ((err = initAudioDecoder()) != OK) {
2542        ALOGE("Failed to init audio decoder: 0x%x", err);
2543        return err;
2544    }
2545
2546    mSeekNotificationSent = true;
2547    seekTo_l(curTimeUs);
2548
2549    if (wasPlaying) {
2550        play_l();
2551    }
2552
2553    mActiveAudioTrackIndex = trackIndex;
2554
2555    return OK;
2556}
2557
2558status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) {
2559    ATRACE_CALL();
2560    ALOGV("selectTrack: trackIndex = %d and select=%d", trackIndex, select);
2561    Mutex::Autolock autoLock(mLock);
2562    size_t trackCount = mExtractor->countTracks();
2563    if (mTextDriver != NULL) {
2564        trackCount += mTextDriver->countExternalTracks();
2565    }
2566    if (trackIndex >= trackCount) {
2567        ALOGE("Track index (%d) is out of range [0, %d)", trackIndex, trackCount);
2568        return ERROR_OUT_OF_RANGE;
2569    }
2570
2571    bool isAudioTrack = false;
2572    if (trackIndex < mExtractor->countTracks()) {
2573        sp<MetaData> meta = mExtractor->getTrackMetaData(trackIndex);
2574        const char *mime;
2575        CHECK(meta->findCString(kKeyMIMEType, &mime));
2576        isAudioTrack = !strncasecmp(mime, "audio/", 6);
2577
2578        if (!isAudioTrack && strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) != 0) {
2579            ALOGE("Track %d is not either audio or timed text", trackIndex);
2580            return ERROR_UNSUPPORTED;
2581        }
2582    }
2583
2584    if (isAudioTrack) {
2585        if (!select) {
2586            ALOGE("Deselect an audio track (%d) is not supported", trackIndex);
2587            return ERROR_UNSUPPORTED;
2588        }
2589        return selectAudioTrack_l(mExtractor->getTrack(trackIndex), trackIndex);
2590    }
2591
2592    // Timed text track handling
2593    if (mTextDriver == NULL) {
2594        return INVALID_OPERATION;
2595    }
2596
2597    status_t err = OK;
2598    if (select) {
2599        err = mTextDriver->selectTrack(trackIndex);
2600        if (err == OK) {
2601            modifyFlags(TEXTPLAYER_INITIALIZED, SET);
2602            if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) {
2603                mTextDriver->start();
2604                modifyFlags(TEXT_RUNNING, SET);
2605            }
2606        }
2607    } else {
2608        err = mTextDriver->unselectTrack(trackIndex);
2609        if (err == OK) {
2610            modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
2611            modifyFlags(TEXT_RUNNING, CLEAR);
2612        }
2613    }
2614    return err;
2615}
2616
2617size_t AwesomePlayer::countTracks() const {
2618    return mExtractor->countTracks() + mTextDriver->countExternalTracks();
2619}
2620
2621status_t AwesomePlayer::setVideoScalingMode(int32_t mode) {
2622    Mutex::Autolock lock(mLock);
2623    return setVideoScalingMode_l(mode);
2624}
2625
2626status_t AwesomePlayer::setVideoScalingMode_l(int32_t mode) {
2627    mVideoScalingMode = mode;
2628    if (mNativeWindow != NULL) {
2629        status_t err = native_window_set_scaling_mode(
2630                mNativeWindow.get(), mVideoScalingMode);
2631        if (err != OK) {
2632            ALOGW("Failed to set scaling mode: %d", err);
2633        }
2634        return err;
2635    }
2636    return OK;
2637}
2638
2639status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) {
2640    ATRACE_CALL();
2641    if (NULL == reply) {
2642        return android::BAD_VALUE;
2643    }
2644    int32_t methodId;
2645    status_t ret = request.readInt32(&methodId);
2646    if (ret != android::OK) {
2647        return ret;
2648    }
2649    switch(methodId) {
2650        case INVOKE_ID_SET_VIDEO_SCALING_MODE:
2651        {
2652            int mode = request.readInt32();
2653            return setVideoScalingMode(mode);
2654        }
2655
2656        case INVOKE_ID_GET_TRACK_INFO:
2657        {
2658            return getTrackInfo(reply);
2659        }
2660        case INVOKE_ID_ADD_EXTERNAL_SOURCE:
2661        {
2662            Mutex::Autolock autoLock(mLock);
2663            if (mTextDriver == NULL) {
2664                mTextDriver = new TimedTextDriver(mListener);
2665            }
2666            // String values written in Parcel are UTF-16 values.
2667            String8 uri(request.readString16());
2668            String8 mimeType(request.readString16());
2669            size_t nTracks = countTracks();
2670            return mTextDriver->addOutOfBandTextSource(nTracks, uri, mimeType);
2671        }
2672        case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD:
2673        {
2674            Mutex::Autolock autoLock(mLock);
2675            if (mTextDriver == NULL) {
2676                mTextDriver = new TimedTextDriver(mListener);
2677            }
2678            int fd         = request.readFileDescriptor();
2679            off64_t offset = request.readInt64();
2680            off64_t length  = request.readInt64();
2681            String8 mimeType(request.readString16());
2682            size_t nTracks = countTracks();
2683            return mTextDriver->addOutOfBandTextSource(
2684                    nTracks, fd, offset, length, mimeType);
2685        }
2686        case INVOKE_ID_SELECT_TRACK:
2687        {
2688            int trackIndex = request.readInt32();
2689            return selectTrack(trackIndex, true /* select */);
2690        }
2691        case INVOKE_ID_UNSELECT_TRACK:
2692        {
2693            int trackIndex = request.readInt32();
2694            return selectTrack(trackIndex, false /* select */);
2695        }
2696        default:
2697        {
2698            return ERROR_UNSUPPORTED;
2699        }
2700    }
2701    // It will not reach here.
2702    return OK;
2703}
2704
2705bool AwesomePlayer::isStreamingHTTP() const {
2706    return mCachedSource != NULL || mWVMExtractor != NULL;
2707}
2708
2709status_t AwesomePlayer::dump(int fd, const Vector<String16> &args) const {
2710    Mutex::Autolock autoLock(mStatsLock);
2711
2712    FILE *out = fdopen(dup(fd), "w");
2713
2714    fprintf(out, " AwesomePlayer\n");
2715    if (mStats.mFd < 0) {
2716        fprintf(out, "  URI(suppressed)");
2717    } else {
2718        fprintf(out, "  fd(%d)", mStats.mFd);
2719    }
2720
2721    fprintf(out, ", flags(0x%08x)", mStats.mFlags);
2722
2723    if (mStats.mBitrate >= 0) {
2724        fprintf(out, ", bitrate(%lld bps)", mStats.mBitrate);
2725    }
2726
2727    fprintf(out, "\n");
2728
2729    for (size_t i = 0; i < mStats.mTracks.size(); ++i) {
2730        const TrackStat &stat = mStats.mTracks.itemAt(i);
2731
2732        fprintf(out, "  Track %d\n", i + 1);
2733        fprintf(out, "   MIME(%s)", stat.mMIME.string());
2734
2735        if (!stat.mDecoderName.isEmpty()) {
2736            fprintf(out, ", decoder(%s)", stat.mDecoderName.string());
2737        }
2738
2739        fprintf(out, "\n");
2740
2741        if ((ssize_t)i == mStats.mVideoTrackIndex) {
2742            fprintf(out,
2743                    "   videoDimensions(%d x %d), "
2744                    "numVideoFramesDecoded(%lld), "
2745                    "numVideoFramesDropped(%lld)\n",
2746                    mStats.mVideoWidth,
2747                    mStats.mVideoHeight,
2748                    mStats.mNumVideoFramesDecoded,
2749                    mStats.mNumVideoFramesDropped);
2750        }
2751    }
2752
2753    fclose(out);
2754    out = NULL;
2755
2756    return OK;
2757}
2758
2759void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) {
2760    switch (mode) {
2761        case SET:
2762            mFlags |= value;
2763            break;
2764        case CLEAR:
2765            if ((value & CACHE_UNDERRUN) && (mFlags & CACHE_UNDERRUN)) {
2766                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
2767            }
2768            mFlags &= ~value;
2769            break;
2770        case ASSIGN:
2771            mFlags = value;
2772            break;
2773        default:
2774            TRESPASS();
2775    }
2776
2777    {
2778        Mutex::Autolock autoLock(mStatsLock);
2779        mStats.mFlags = mFlags;
2780    }
2781}
2782
2783void AwesomePlayer::onAudioTearDownEvent() {
2784
2785    Mutex::Autolock autoLock(mLock);
2786    if (!mAudioTearDownEventPending) {
2787        return;
2788    }
2789    mAudioTearDownEventPending = false;
2790
2791    ALOGV("onAudioTearDownEvent");
2792
2793    // stream info is cleared by reset_l() so copy what we need
2794    const bool wasPlaying = (mFlags & PLAYING);
2795    KeyedVector<String8, String8> uriHeaders(mUriHeaders);
2796    sp<DataSource> fileSource(mFileSource);
2797
2798    mStatsLock.lock();
2799    String8 uri(mStats.mURI);
2800    mStatsLock.unlock();
2801
2802    // get current position so we can start recreated stream from here
2803    int64_t position = 0;
2804    getPosition(&position);
2805
2806    // Reset and recreate
2807    reset_l();
2808
2809    status_t err;
2810
2811    if (fileSource != NULL) {
2812        mFileSource = fileSource;
2813        err = setDataSource_l(fileSource);
2814    } else {
2815        err = setDataSource_l(uri, &uriHeaders);
2816    }
2817
2818    mFlags |= PREPARING;
2819    if ( err != OK ) {
2820        // This will force beingPrepareAsync_l() to notify
2821        // a MEDIA_ERROR to the client and abort the prepare
2822        mFlags |= PREPARE_CANCELLED;
2823    }
2824
2825    mAudioTearDown = true;
2826    mIsAsyncPrepare = true;
2827
2828    // Call parepare for the host decoding
2829    beginPrepareAsync_l();
2830
2831    if (mPrepareResult == OK) {
2832        if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
2833            seekTo_l(position);
2834        }
2835
2836        if (wasPlaying) {
2837            modifyFlags(CACHE_UNDERRUN, CLEAR);
2838            play_l();
2839        }
2840    }
2841
2842    mAudioTearDown = false;
2843}
2844
2845}  // namespace android
2846