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