AwesomePlayer.cpp revision b33d2ac90cfce0fe6db8c3e979e7ae2bbfc28163
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#include <utils/Log.h>
22
23#include <dlfcn.h>
24
25#include "include/ARTSPController.h"
26#include "include/AwesomePlayer.h"
27#include "include/DRMExtractor.h"
28#include "include/SoftwareRenderer.h"
29#include "include/NuCachedSource2.h"
30#include "include/ThrottledSource.h"
31#include "include/MPEG2TSExtractor.h"
32#include "include/WVMExtractor.h"
33
34#include "timedtext/TimedTextPlayer.h"
35
36#include <binder/IPCThreadState.h>
37#include <binder/IServiceManager.h>
38#include <media/IMediaPlayerService.h>
39#include <media/stagefright/foundation/hexdump.h>
40#include <media/stagefright/foundation/ADebug.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
51#include <surfaceflinger/Surface.h>
52#include <gui/ISurfaceTexture.h>
53#include <gui/SurfaceTextureClient.h>
54#include <surfaceflinger/ISurfaceComposer.h>
55
56#include <media/stagefright/foundation/ALooper.h>
57#include <media/stagefright/foundation/AMessage.h>
58
59#include <cutils/properties.h>
60
61#define USE_SURFACE_ALLOC 1
62
63namespace android {
64
65static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
66static int64_t kHighWaterMarkUs = 10000000ll;  // 10secs
67static int64_t kHighWaterMarkRTSPUs = 4000000ll;  // 4secs
68static const size_t kLowWaterMarkBytes = 40000;
69static const size_t kHighWaterMarkBytes = 200000;
70
71struct AwesomeEvent : public TimedEventQueue::Event {
72    AwesomeEvent(
73            AwesomePlayer *player,
74            void (AwesomePlayer::*method)())
75        : mPlayer(player),
76          mMethod(method) {
77    }
78
79protected:
80    virtual ~AwesomeEvent() {}
81
82    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
83        (mPlayer->*mMethod)();
84    }
85
86private:
87    AwesomePlayer *mPlayer;
88    void (AwesomePlayer::*mMethod)();
89
90    AwesomeEvent(const AwesomeEvent &);
91    AwesomeEvent &operator=(const AwesomeEvent &);
92};
93
94struct AwesomeLocalRenderer : public AwesomeRenderer {
95    AwesomeLocalRenderer(
96            const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
97        : mTarget(new SoftwareRenderer(nativeWindow, meta)) {
98    }
99
100    virtual void render(MediaBuffer *buffer) {
101        render((const uint8_t *)buffer->data() + buffer->range_offset(),
102               buffer->range_length());
103    }
104
105    void render(const void *data, size_t size) {
106        mTarget->render(data, size, NULL);
107    }
108
109protected:
110    virtual ~AwesomeLocalRenderer() {
111        delete mTarget;
112        mTarget = NULL;
113    }
114
115private:
116    SoftwareRenderer *mTarget;
117
118    AwesomeLocalRenderer(const AwesomeLocalRenderer &);
119    AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
120};
121
122struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
123    AwesomeNativeWindowRenderer(
124            const sp<ANativeWindow> &nativeWindow,
125            int32_t rotationDegrees)
126        : mNativeWindow(nativeWindow) {
127        applyRotation(rotationDegrees);
128    }
129
130    virtual void render(MediaBuffer *buffer) {
131        status_t err = mNativeWindow->queueBuffer(
132                mNativeWindow.get(), buffer->graphicBuffer().get());
133        if (err != 0) {
134            LOGE("queueBuffer failed with error %s (%d)", strerror(-err),
135                    -err);
136            return;
137        }
138
139        sp<MetaData> metaData = buffer->meta_data();
140        metaData->setInt32(kKeyRendered, 1);
141    }
142
143protected:
144    virtual ~AwesomeNativeWindowRenderer() {}
145
146private:
147    sp<ANativeWindow> mNativeWindow;
148
149    void applyRotation(int32_t rotationDegrees) {
150        uint32_t transform;
151        switch (rotationDegrees) {
152            case 0: transform = 0; break;
153            case 90: transform = HAL_TRANSFORM_ROT_90; break;
154            case 180: transform = HAL_TRANSFORM_ROT_180; break;
155            case 270: transform = HAL_TRANSFORM_ROT_270; break;
156            default: transform = 0; break;
157        }
158
159        if (transform) {
160            CHECK_EQ(0, native_window_set_buffers_transform(
161                        mNativeWindow.get(), transform));
162        }
163    }
164
165    AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
166    AwesomeNativeWindowRenderer &operator=(
167            const AwesomeNativeWindowRenderer &);
168};
169
170// To collect the decoder usage
171void addBatteryData(uint32_t params) {
172    sp<IBinder> binder =
173        defaultServiceManager()->getService(String16("media.player"));
174    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
175    CHECK(service.get() != NULL);
176
177    service->addBatteryData(params);
178}
179
180////////////////////////////////////////////////////////////////////////////////
181AwesomePlayer::AwesomePlayer()
182    : mQueueStarted(false),
183      mTimeSource(NULL),
184      mVideoRendererIsPreview(false),
185      mAudioPlayer(NULL),
186      mDisplayWidth(0),
187      mDisplayHeight(0),
188      mFlags(0),
189      mExtractorFlags(0),
190      mVideoBuffer(NULL),
191      mDecryptHandle(NULL),
192      mLastVideoTimeUs(-1),
193      mTextPlayer(NULL) {
194    CHECK_EQ(mClient.connect(), (status_t)OK);
195
196    DataSource::RegisterDefaultSniffers();
197
198    mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
199    mVideoEventPending = false;
200    mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
201    mStreamDoneEventPending = false;
202    mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
203    mBufferingEventPending = false;
204    mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);
205    mVideoEventPending = false;
206
207    mCheckAudioStatusEvent = new AwesomeEvent(
208            this, &AwesomePlayer::onCheckAudioStatus);
209
210    mAudioStatusEventPending = false;
211
212    reset();
213}
214
215AwesomePlayer::~AwesomePlayer() {
216    if (mQueueStarted) {
217        mQueue.stop();
218    }
219
220    reset();
221
222    mClient.disconnect();
223}
224
225void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
226    mQueue.cancelEvent(mVideoEvent->eventID());
227    mVideoEventPending = false;
228    mQueue.cancelEvent(mStreamDoneEvent->eventID());
229    mStreamDoneEventPending = false;
230    mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
231    mAudioStatusEventPending = false;
232    mQueue.cancelEvent(mVideoLagEvent->eventID());
233    mVideoLagEventPending = false;
234
235    if (!keepBufferingGoing) {
236        mQueue.cancelEvent(mBufferingEvent->eventID());
237        mBufferingEventPending = false;
238    }
239}
240
241void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
242    Mutex::Autolock autoLock(mLock);
243    mListener = listener;
244}
245
246status_t AwesomePlayer::setDataSource(
247        const char *uri, const KeyedVector<String8, String8> *headers) {
248    Mutex::Autolock autoLock(mLock);
249    return setDataSource_l(uri, headers);
250}
251
252status_t AwesomePlayer::setDataSource_l(
253        const char *uri, const KeyedVector<String8, String8> *headers) {
254    reset_l();
255
256    mUri = uri;
257
258    if (headers) {
259        mUriHeaders = *headers;
260
261        ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
262        if (index >= 0) {
263            // Browser is in "incognito" mode, suppress logging URLs.
264
265            // This isn't something that should be passed to the server.
266            mUriHeaders.removeItemsAt(index);
267
268            mFlags |= INCOGNITO;
269        }
270    }
271
272    if (!(mFlags & INCOGNITO)) {
273        LOGI("setDataSource_l('%s')", mUri.string());
274    } else {
275        LOGI("setDataSource_l(URL suppressed)");
276    }
277
278    // The actual work will be done during preparation in the call to
279    // ::finishSetDataSource_l to avoid blocking the calling thread in
280    // setDataSource for any significant time.
281
282    return OK;
283}
284
285status_t AwesomePlayer::setDataSource(
286        int fd, int64_t offset, int64_t length) {
287    Mutex::Autolock autoLock(mLock);
288
289    reset_l();
290
291    sp<DataSource> dataSource = new FileSource(fd, offset, length);
292
293    status_t err = dataSource->initCheck();
294
295    if (err != OK) {
296        return err;
297    }
298
299    mFileSource = dataSource;
300
301    return setDataSource_l(dataSource);
302}
303
304status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source) {
305    return INVALID_OPERATION;
306}
307
308status_t AwesomePlayer::setDataSource_l(
309        const sp<DataSource> &dataSource) {
310    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
311
312    if (extractor == NULL) {
313        return UNKNOWN_ERROR;
314    }
315
316    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
317    if (mDecryptHandle != NULL) {
318        CHECK(mDrmManagerClient);
319        if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
320            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
321        }
322    }
323
324    return setDataSource_l(extractor);
325}
326
327status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
328    // Attempt to approximate overall stream bitrate by summing all
329    // tracks' individual bitrates, if not all of them advertise bitrate,
330    // we have to fail.
331
332    int64_t totalBitRate = 0;
333
334    for (size_t i = 0; i < extractor->countTracks(); ++i) {
335        sp<MetaData> meta = extractor->getTrackMetaData(i);
336
337        int32_t bitrate;
338        if (!meta->findInt32(kKeyBitRate, &bitrate)) {
339            totalBitRate = -1;
340            break;
341        }
342
343        totalBitRate += bitrate;
344    }
345
346    mBitrate = totalBitRate;
347
348    LOGV("mBitrate = %lld bits/sec", mBitrate);
349
350    bool haveAudio = false;
351    bool haveVideo = false;
352    for (size_t i = 0; i < extractor->countTracks(); ++i) {
353        sp<MetaData> meta = extractor->getTrackMetaData(i);
354
355        const char *mime;
356        CHECK(meta->findCString(kKeyMIMEType, &mime));
357
358        if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
359            setVideoSource(extractor->getTrack(i));
360            haveVideo = true;
361
362            // Set the presentation/display size
363            int32_t displayWidth, displayHeight;
364            bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
365            if (success) {
366                success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
367            }
368            if (success) {
369                mDisplayWidth = displayWidth;
370                mDisplayHeight = displayHeight;
371            }
372
373        } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
374            setAudioSource(extractor->getTrack(i));
375            haveAudio = true;
376
377            if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
378                // Only do this for vorbis audio, none of the other audio
379                // formats even support this ringtone specific hack and
380                // retrieving the metadata on some extractors may turn out
381                // to be very expensive.
382                sp<MetaData> fileMeta = extractor->getMetaData();
383                int32_t loop;
384                if (fileMeta != NULL
385                        && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
386                    mFlags |= AUTO_LOOPING;
387                }
388            }
389        } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
390            addTextSource(extractor->getTrack(i));
391        }
392    }
393
394    if (!haveAudio && !haveVideo) {
395        return UNKNOWN_ERROR;
396    }
397
398    mExtractorFlags = extractor->flags();
399
400    return OK;
401}
402
403void AwesomePlayer::reset() {
404    LOGI("reset");
405    Mutex::Autolock autoLock(mLock);
406    reset_l();
407}
408
409void AwesomePlayer::reset_l() {
410    mDisplayWidth = 0;
411    mDisplayHeight = 0;
412
413    if (mDecryptHandle != NULL) {
414            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
415                    Playback::STOP, 0);
416            mDecryptHandle = NULL;
417            mDrmManagerClient = NULL;
418            LOGI("DRM manager client stopped");
419    }
420
421
422    if (mFlags & PLAYING) {
423        uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
424        if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
425            params |= IMediaPlayerService::kBatteryDataTrackAudio;
426        }
427        if (mVideoSource != NULL) {
428            params |= IMediaPlayerService::kBatteryDataTrackVideo;
429        }
430        addBatteryData(params);
431    }
432
433    if (mFlags & PREPARING) {
434        mFlags |= PREPARE_CANCELLED;
435        if (mConnectingDataSource != NULL) {
436            LOGI("interrupting the connection process");
437            mConnectingDataSource->disconnect();
438        } else if (mConnectingRTSPController != NULL) {
439            LOGI("interrupting the connection process");
440            mConnectingRTSPController->disconnect();
441        }
442
443        if (mFlags & PREPARING_CONNECTED) {
444            // We are basically done preparing, we're just buffering
445            // enough data to start playback, we can safely interrupt that.
446            finishAsyncPrepare_l();
447        }
448    }
449
450    while (mFlags & PREPARING) {
451        mPreparedCondition.wait(mLock);
452    }
453
454    LOGI("cancel player events");
455    cancelPlayerEvents();
456
457    mWVMExtractor.clear();
458    mCachedSource.clear();
459    mAudioTrack.clear();
460    mVideoTrack.clear();
461
462    // Shutdown audio first, so that the respone to the reset request
463    // appears to happen instantaneously as far as the user is concerned
464    // If we did this later, audio would continue playing while we
465    // shutdown the video-related resources and the player appear to
466    // not be as responsive to a reset request.
467    if (mAudioPlayer == NULL && mAudioSource != NULL) {
468        // If we had an audio player, it would have effectively
469        // taken possession of the audio source and stopped it when
470        // _it_ is stopped. Otherwise this is still our responsibility.
471        mAudioSource->stop();
472    }
473    mAudioSource.clear();
474
475    mTimeSource = NULL;
476
477    delete mAudioPlayer;
478    mAudioPlayer = NULL;
479
480    if (mTextPlayer != NULL) {
481        delete mTextPlayer;
482        mTextPlayer = NULL;
483    }
484
485    mVideoRenderer.clear();
486
487    if (mRTSPController != NULL) {
488        mRTSPController->disconnect();
489        mRTSPController.clear();
490    }
491
492    if (mVideoSource != NULL) {
493        shutdownVideoDecoder_l();
494    }
495
496    mDurationUs = -1;
497    mFlags = 0;
498    mExtractorFlags = 0;
499    mTimeSourceDeltaUs = 0;
500    mVideoTimeUs = 0;
501
502    mSeeking = NO_SEEK;
503    mSeekNotificationSent = false;
504    mSeekTimeUs = 0;
505
506    mUri.setTo("");
507    mUriHeaders.clear();
508
509    mFileSource.clear();
510
511    mBitrate = -1;
512    mLastVideoTimeUs = -1;
513}
514
515void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
516    if (mListener != NULL) {
517        sp<MediaPlayerBase> listener = mListener.promote();
518
519        if (listener != NULL) {
520            listener->sendEvent(msg, ext1, ext2);
521        }
522    }
523}
524
525bool AwesomePlayer::getBitrate(int64_t *bitrate) {
526    off64_t size;
527    if (mDurationUs >= 0 && mCachedSource != NULL
528            && mCachedSource->getSize(&size) == OK) {
529        *bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
530        return true;
531    }
532
533    if (mBitrate >= 0) {
534        *bitrate = mBitrate;
535        return true;
536    }
537
538    *bitrate = 0;
539
540    return false;
541}
542
543// Returns true iff cached duration is available/applicable.
544bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
545    int64_t bitrate;
546
547    if (mRTSPController != NULL) {
548        *durationUs = mRTSPController->getQueueDurationUs(eos);
549        return true;
550    } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
551        status_t finalStatus;
552        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
553        *durationUs = cachedDataRemaining * 8000000ll / bitrate;
554        *eos = (finalStatus != OK);
555        return true;
556    } else if (mWVMExtractor != NULL) {
557        status_t finalStatus;
558        *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus);
559        *eos = (finalStatus != OK);
560        return true;
561    }
562
563    return false;
564}
565
566void AwesomePlayer::ensureCacheIsFetching_l() {
567    if (mCachedSource != NULL) {
568        mCachedSource->resumeFetchingIfNecessary();
569    }
570}
571
572void AwesomePlayer::onVideoLagUpdate() {
573    Mutex::Autolock autoLock(mLock);
574    if (!mVideoLagEventPending) {
575        return;
576    }
577    mVideoLagEventPending = false;
578
579    int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs();
580    int64_t videoLateByUs = audioTimeUs - mVideoTimeUs;
581
582    if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) {
583        LOGV("video late by %lld ms.", videoLateByUs / 1000ll);
584
585        notifyListener_l(
586                MEDIA_INFO,
587                MEDIA_INFO_VIDEO_TRACK_LAGGING,
588                videoLateByUs / 1000ll);
589    }
590
591    postVideoLagEvent_l();
592}
593
594void AwesomePlayer::onBufferingUpdate() {
595    Mutex::Autolock autoLock(mLock);
596    if (!mBufferingEventPending) {
597        return;
598    }
599    mBufferingEventPending = false;
600
601    if (mCachedSource != NULL) {
602        status_t finalStatus;
603        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
604        bool eos = (finalStatus != OK);
605
606        if (eos) {
607            if (finalStatus == ERROR_END_OF_STREAM) {
608                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
609            }
610            if (mFlags & PREPARING) {
611                LOGV("cache has reached EOS, prepare is done.");
612                finishAsyncPrepare_l();
613            }
614        } else {
615            int64_t bitrate;
616            if (getBitrate(&bitrate)) {
617                size_t cachedSize = mCachedSource->cachedSize();
618                int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
619
620                int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
621                if (percentage > 100) {
622                    percentage = 100;
623                }
624
625                notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
626            } else {
627                // We don't know the bitrate of the stream, use absolute size
628                // limits to maintain the cache.
629
630                if ((mFlags & PLAYING) && !eos
631                        && (cachedDataRemaining < kLowWaterMarkBytes)) {
632                    LOGI("cache is running low (< %d) , pausing.",
633                         kLowWaterMarkBytes);
634                    mFlags |= CACHE_UNDERRUN;
635                    pause_l();
636                    ensureCacheIsFetching_l();
637                    sendCacheStats();
638                    notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
639                } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
640                    if (mFlags & CACHE_UNDERRUN) {
641                        LOGI("cache has filled up (> %d), resuming.",
642                             kHighWaterMarkBytes);
643                        mFlags &= ~CACHE_UNDERRUN;
644                        play_l();
645                        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
646                    } else if (mFlags & PREPARING) {
647                        LOGV("cache has filled up (> %d), prepare is done",
648                             kHighWaterMarkBytes);
649                        finishAsyncPrepare_l();
650                    }
651                }
652            }
653        }
654    } else if (mWVMExtractor != NULL) {
655        status_t finalStatus;
656
657        int64_t cachedDurationUs
658            = mWVMExtractor->getCachedDurationUs(&finalStatus);
659
660        bool eos = (finalStatus != OK);
661
662        if (eos) {
663            if (finalStatus == ERROR_END_OF_STREAM) {
664                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
665            }
666            if (mFlags & PREPARING) {
667                LOGV("cache has reached EOS, prepare is done.");
668                finishAsyncPrepare_l();
669            }
670        } else {
671            int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
672            if (percentage > 100) {
673                percentage = 100;
674            }
675
676            notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
677        }
678    }
679
680    int64_t cachedDurationUs;
681    bool eos;
682    if (getCachedDuration_l(&cachedDurationUs, &eos)) {
683        LOGV("cachedDurationUs = %.2f secs, eos=%d",
684             cachedDurationUs / 1E6, eos);
685
686        int64_t highWaterMarkUs =
687            (mRTSPController != NULL) ? kHighWaterMarkRTSPUs : kHighWaterMarkUs;
688
689        if ((mFlags & PLAYING) && !eos
690                && (cachedDurationUs < kLowWaterMarkUs)) {
691            LOGI("cache is running low (%.2f secs) , pausing.",
692                 cachedDurationUs / 1E6);
693            mFlags |= CACHE_UNDERRUN;
694            pause_l();
695            ensureCacheIsFetching_l();
696            sendCacheStats();
697            notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
698        } else if (eos || cachedDurationUs > highWaterMarkUs) {
699            if (mFlags & CACHE_UNDERRUN) {
700                LOGI("cache has filled up (%.2f secs), resuming.",
701                     cachedDurationUs / 1E6);
702                mFlags &= ~CACHE_UNDERRUN;
703                play_l();
704                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
705            } else if (mFlags & PREPARING) {
706                LOGV("cache has filled up (%.2f secs), prepare is done",
707                     cachedDurationUs / 1E6);
708                finishAsyncPrepare_l();
709            }
710        }
711    }
712
713    postBufferingEvent_l();
714}
715
716void AwesomePlayer::sendCacheStats() {
717    sp<MediaPlayerBase> listener = mListener.promote();
718    if (listener != NULL && mCachedSource != NULL) {
719        int32_t kbps = 0;
720        status_t err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
721        if (err == OK) {
722            listener->sendEvent(
723                MEDIA_INFO, MEDIA_INFO_NETWORK_BANDWIDTH, kbps);
724        }
725    }
726}
727
728void AwesomePlayer::onStreamDone() {
729    // Posted whenever any stream finishes playing.
730
731    Mutex::Autolock autoLock(mLock);
732    if (!mStreamDoneEventPending) {
733        return;
734    }
735    mStreamDoneEventPending = false;
736
737    if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
738        LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
739
740        notifyListener_l(
741                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
742
743        pause_l(true /* at eos */);
744
745        mFlags |= AT_EOS;
746        return;
747    }
748
749    const bool allDone =
750        (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
751            && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
752
753    if (!allDone) {
754        return;
755    }
756
757    if (mFlags & (LOOPING | AUTO_LOOPING)) {
758        seekTo_l(0);
759
760        if (mVideoSource != NULL) {
761            postVideoEvent_l();
762        }
763    } else {
764        LOGV("MEDIA_PLAYBACK_COMPLETE");
765        notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
766
767        pause_l(true /* at eos */);
768
769        mFlags |= AT_EOS;
770    }
771}
772
773status_t AwesomePlayer::play() {
774    Mutex::Autolock autoLock(mLock);
775
776    mFlags &= ~CACHE_UNDERRUN;
777
778    return play_l();
779}
780
781status_t AwesomePlayer::play_l() {
782    mFlags &= ~SEEK_PREVIEW;
783
784    if (mFlags & PLAYING) {
785        return OK;
786    }
787
788    if (!(mFlags & PREPARED)) {
789        status_t err = prepare_l();
790
791        if (err != OK) {
792            return err;
793        }
794    }
795
796    mFlags |= PLAYING;
797    mFlags |= FIRST_FRAME;
798
799    if (mDecryptHandle != NULL) {
800        int64_t position;
801        getPosition(&position);
802        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
803                Playback::START, position / 1000);
804    }
805
806    if (mAudioSource != NULL) {
807        if (mAudioPlayer == NULL) {
808            if (mAudioSink != NULL) {
809                mAudioPlayer = new AudioPlayer(mAudioSink, this);
810                mAudioPlayer->setSource(mAudioSource);
811
812                mTimeSource = mAudioPlayer;
813
814                // If there was a seek request before we ever started,
815                // honor the request now.
816                // Make sure to do this before starting the audio player
817                // to avoid a race condition.
818                seekAudioIfNecessary_l();
819            }
820        }
821
822        CHECK(!(mFlags & AUDIO_RUNNING));
823
824        if (mVideoSource == NULL) {
825            status_t err = startAudioPlayer_l();
826
827            if (err != OK) {
828                delete mAudioPlayer;
829                mAudioPlayer = NULL;
830
831                mFlags &= ~(PLAYING | FIRST_FRAME);
832
833                if (mDecryptHandle != NULL) {
834                    mDrmManagerClient->setPlaybackStatus(
835                            mDecryptHandle, Playback::STOP, 0);
836                }
837
838                return err;
839            }
840        }
841    }
842
843    if (mTimeSource == NULL && mAudioPlayer == NULL) {
844        mTimeSource = &mSystemTimeSource;
845    }
846
847    if (mVideoSource != NULL) {
848        // Kick off video playback
849        postVideoEvent_l();
850
851        if (mAudioSource != NULL && mVideoSource != NULL) {
852            postVideoLagEvent_l();
853        }
854    }
855
856    if (mFlags & AT_EOS) {
857        // Legacy behaviour, if a stream finishes playing and then
858        // is started again, we play from the start...
859        seekTo_l(0);
860    }
861
862    uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted
863        | IMediaPlayerService::kBatteryDataTrackDecoder;
864    if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
865        params |= IMediaPlayerService::kBatteryDataTrackAudio;
866    }
867    if (mVideoSource != NULL) {
868        params |= IMediaPlayerService::kBatteryDataTrackVideo;
869    }
870    addBatteryData(params);
871
872    return OK;
873}
874
875status_t AwesomePlayer::startAudioPlayer_l() {
876    CHECK(!(mFlags & AUDIO_RUNNING));
877
878    if (mAudioSource == NULL || mAudioPlayer == NULL) {
879        return OK;
880    }
881
882    if (!(mFlags & AUDIOPLAYER_STARTED)) {
883        mFlags |= AUDIOPLAYER_STARTED;
884
885        bool wasSeeking = mAudioPlayer->isSeeking();
886
887        // We've already started the MediaSource in order to enable
888        // the prefetcher to read its data.
889        status_t err = mAudioPlayer->start(
890                true /* sourceAlreadyStarted */);
891
892        if (err != OK) {
893            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
894            return err;
895        }
896
897        if (wasSeeking) {
898            CHECK(!mAudioPlayer->isSeeking());
899
900            // We will have finished the seek while starting the audio player.
901            postAudioSeekComplete_l();
902        }
903    } else {
904        mAudioPlayer->resume();
905    }
906
907    mFlags |= AUDIO_RUNNING;
908
909    mWatchForAudioEOS = true;
910
911    return OK;
912}
913
914void AwesomePlayer::notifyVideoSize_l() {
915    sp<MetaData> meta = mVideoSource->getFormat();
916
917    int32_t cropLeft, cropTop, cropRight, cropBottom;
918    if (!meta->findRect(
919                kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
920        int32_t width, height;
921        CHECK(meta->findInt32(kKeyWidth, &width));
922        CHECK(meta->findInt32(kKeyHeight, &height));
923
924        cropLeft = cropTop = 0;
925        cropRight = width - 1;
926        cropBottom = height - 1;
927
928        LOGV("got dimensions only %d x %d", width, height);
929    } else {
930        LOGV("got crop rect %d, %d, %d, %d",
931             cropLeft, cropTop, cropRight, cropBottom);
932    }
933
934    int32_t displayWidth;
935    if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
936        LOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
937        mDisplayWidth = displayWidth;
938    }
939    int32_t displayHeight;
940    if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
941        LOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight);
942        mDisplayHeight = displayHeight;
943    }
944
945    int32_t usableWidth = cropRight - cropLeft + 1;
946    int32_t usableHeight = cropBottom - cropTop + 1;
947    if (mDisplayWidth != 0) {
948        usableWidth = mDisplayWidth;
949    }
950    if (mDisplayHeight != 0) {
951        usableHeight = mDisplayHeight;
952    }
953
954    int32_t rotationDegrees;
955    if (!mVideoTrack->getFormat()->findInt32(
956                kKeyRotation, &rotationDegrees)) {
957        rotationDegrees = 0;
958    }
959
960    if (rotationDegrees == 90 || rotationDegrees == 270) {
961        notifyListener_l(
962                MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
963    } else {
964        notifyListener_l(
965                MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
966    }
967}
968
969void AwesomePlayer::initRenderer_l() {
970    if (mNativeWindow == NULL) {
971        return;
972    }
973
974    sp<MetaData> meta = mVideoSource->getFormat();
975
976    int32_t format;
977    const char *component;
978    int32_t decodedWidth, decodedHeight;
979    CHECK(meta->findInt32(kKeyColorFormat, &format));
980    CHECK(meta->findCString(kKeyDecoderComponent, &component));
981    CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
982    CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
983
984    int32_t rotationDegrees;
985    if (!mVideoTrack->getFormat()->findInt32(
986                kKeyRotation, &rotationDegrees)) {
987        rotationDegrees = 0;
988    }
989
990    mVideoRenderer.clear();
991
992    // Must ensure that mVideoRenderer's destructor is actually executed
993    // before creating a new one.
994    IPCThreadState::self()->flushCommands();
995
996    if (USE_SURFACE_ALLOC
997            && !strncmp(component, "OMX.", 4)
998            && strncmp(component, "OMX.google.", 11)) {
999        // Hardware decoders avoid the CPU color conversion by decoding
1000        // directly to ANativeBuffers, so we must use a renderer that
1001        // just pushes those buffers to the ANativeWindow.
1002        mVideoRenderer =
1003            new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);
1004    } else {
1005        // Other decoders are instantiated locally and as a consequence
1006        // allocate their buffers in local address space.  This renderer
1007        // then performs a color conversion and copy to get the data
1008        // into the ANativeBuffer.
1009        mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta);
1010    }
1011}
1012
1013status_t AwesomePlayer::pause() {
1014    Mutex::Autolock autoLock(mLock);
1015
1016    mFlags &= ~CACHE_UNDERRUN;
1017
1018    return pause_l();
1019}
1020
1021status_t AwesomePlayer::pause_l(bool at_eos) {
1022    if (!(mFlags & PLAYING)) {
1023        return OK;
1024    }
1025
1026    cancelPlayerEvents(true /* keepBufferingGoing */);
1027
1028    if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
1029        if (at_eos) {
1030            // If we played the audio stream to completion we
1031            // want to make sure that all samples remaining in the audio
1032            // track's queue are played out.
1033            mAudioPlayer->pause(true /* playPendingSamples */);
1034        } else {
1035            mAudioPlayer->pause();
1036        }
1037
1038        mFlags &= ~AUDIO_RUNNING;
1039    }
1040
1041    if (mFlags & TEXTPLAYER_STARTED) {
1042        mTextPlayer->pause();
1043        mFlags &= ~TEXT_RUNNING;
1044    }
1045
1046    mFlags &= ~PLAYING;
1047
1048    if (mDecryptHandle != NULL) {
1049        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1050                Playback::PAUSE, 0);
1051    }
1052
1053    uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
1054    if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
1055        params |= IMediaPlayerService::kBatteryDataTrackAudio;
1056    }
1057    if (mVideoSource != NULL) {
1058        params |= IMediaPlayerService::kBatteryDataTrackVideo;
1059    }
1060
1061    addBatteryData(params);
1062
1063    return OK;
1064}
1065
1066bool AwesomePlayer::isPlaying() const {
1067    return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
1068}
1069
1070void AwesomePlayer::setSurface(const sp<Surface> &surface) {
1071    Mutex::Autolock autoLock(mLock);
1072
1073    mSurface = surface;
1074    setNativeWindow_l(surface);
1075}
1076
1077void AwesomePlayer::setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
1078    Mutex::Autolock autoLock(mLock);
1079
1080    mSurface.clear();
1081    if (surfaceTexture != NULL) {
1082        setNativeWindow_l(new SurfaceTextureClient(surfaceTexture));
1083    }
1084}
1085
1086void AwesomePlayer::shutdownVideoDecoder_l() {
1087    if (mVideoBuffer) {
1088        mVideoBuffer->release();
1089        mVideoBuffer = NULL;
1090    }
1091
1092    mVideoSource->stop();
1093
1094    // The following hack is necessary to ensure that the OMX
1095    // component is completely released by the time we may try
1096    // to instantiate it again.
1097    wp<MediaSource> tmp = mVideoSource;
1098    mVideoSource.clear();
1099    while (tmp.promote() != NULL) {
1100        usleep(1000);
1101    }
1102    IPCThreadState::self()->flushCommands();
1103    LOGI("video decoder shutdown completed");
1104}
1105
1106void AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
1107    mNativeWindow = native;
1108
1109    if (mVideoSource == NULL) {
1110        return;
1111    }
1112
1113    LOGI("attempting to reconfigure to use new surface");
1114
1115    bool wasPlaying = (mFlags & PLAYING) != 0;
1116
1117    pause_l();
1118    mVideoRenderer.clear();
1119
1120    shutdownVideoDecoder_l();
1121
1122    CHECK_EQ(initVideoDecoder(), (status_t)OK);
1123
1124    if (mLastVideoTimeUs >= 0) {
1125        mSeeking = SEEK;
1126        mSeekNotificationSent = true;
1127        mSeekTimeUs = mLastVideoTimeUs;
1128        mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
1129    }
1130
1131    if (wasPlaying) {
1132        play_l();
1133    }
1134}
1135
1136void AwesomePlayer::setAudioSink(
1137        const sp<MediaPlayerBase::AudioSink> &audioSink) {
1138    Mutex::Autolock autoLock(mLock);
1139
1140    mAudioSink = audioSink;
1141}
1142
1143status_t AwesomePlayer::setLooping(bool shouldLoop) {
1144    Mutex::Autolock autoLock(mLock);
1145
1146    mFlags = mFlags & ~LOOPING;
1147
1148    if (shouldLoop) {
1149        mFlags |= LOOPING;
1150    }
1151
1152    return OK;
1153}
1154
1155status_t AwesomePlayer::getDuration(int64_t *durationUs) {
1156    Mutex::Autolock autoLock(mMiscStateLock);
1157
1158    if (mDurationUs < 0) {
1159        return UNKNOWN_ERROR;
1160    }
1161
1162    *durationUs = mDurationUs;
1163
1164    return OK;
1165}
1166
1167status_t AwesomePlayer::getPosition(int64_t *positionUs) {
1168    if (mRTSPController != NULL) {
1169        *positionUs = mRTSPController->getNormalPlayTimeUs();
1170    }
1171    else if (mSeeking != NO_SEEK) {
1172        *positionUs = mSeekTimeUs;
1173    } else if (mVideoSource != NULL
1174            && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
1175        Mutex::Autolock autoLock(mMiscStateLock);
1176        *positionUs = mVideoTimeUs;
1177    } else if (mAudioPlayer != NULL) {
1178        *positionUs = mAudioPlayer->getMediaTimeUs();
1179    } else {
1180        *positionUs = 0;
1181    }
1182
1183    return OK;
1184}
1185
1186status_t AwesomePlayer::seekTo(int64_t timeUs) {
1187    if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
1188        Mutex::Autolock autoLock(mLock);
1189        return seekTo_l(timeUs);
1190    }
1191
1192    return OK;
1193}
1194
1195status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) {
1196    if (mTextPlayer != NULL) {
1197        if (index >= 0) { // to turn on a text track
1198            status_t err = mTextPlayer->setTimedTextTrackIndex(index);
1199            if (err != OK) {
1200                return err;
1201            }
1202
1203            mFlags |= TEXT_RUNNING;
1204            mFlags |= TEXTPLAYER_STARTED;
1205            return OK;
1206        } else { // to turn off the text track display
1207            if (mFlags  & TEXT_RUNNING) {
1208                mFlags &= ~TEXT_RUNNING;
1209            }
1210            if (mFlags  & TEXTPLAYER_STARTED) {
1211                mFlags &= ~TEXTPLAYER_STARTED;
1212            }
1213
1214            return mTextPlayer->setTimedTextTrackIndex(index);
1215        }
1216    } else {
1217        return INVALID_OPERATION;
1218    }
1219}
1220
1221// static
1222void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
1223    static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
1224}
1225
1226void AwesomePlayer::onRTSPSeekDone() {
1227    notifyListener_l(MEDIA_SEEK_COMPLETE);
1228    mSeekNotificationSent = true;
1229}
1230
1231status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
1232    if (mRTSPController != NULL) {
1233        mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
1234        return OK;
1235    }
1236
1237    if (mFlags & CACHE_UNDERRUN) {
1238        mFlags &= ~CACHE_UNDERRUN;
1239        play_l();
1240    }
1241
1242    if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) {
1243        // Video playback completed before, there's no pending
1244        // video event right now. In order for this new seek
1245        // to be honored, we need to post one.
1246
1247        postVideoEvent_l();
1248    }
1249
1250    mSeeking = SEEK;
1251    mSeekNotificationSent = false;
1252    mSeekTimeUs = timeUs;
1253    mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
1254
1255    seekAudioIfNecessary_l();
1256
1257    if (mFlags & TEXTPLAYER_STARTED) {
1258        mTextPlayer->seekTo(mSeekTimeUs);
1259    }
1260
1261    if (!(mFlags & PLAYING)) {
1262        LOGV("seeking while paused, sending SEEK_COMPLETE notification"
1263             " immediately.");
1264
1265        notifyListener_l(MEDIA_SEEK_COMPLETE);
1266        mSeekNotificationSent = true;
1267
1268        if ((mFlags & PREPARED) && mVideoSource != NULL) {
1269            mFlags |= SEEK_PREVIEW;
1270            postVideoEvent_l();
1271        }
1272    }
1273
1274    return OK;
1275}
1276
1277void AwesomePlayer::seekAudioIfNecessary_l() {
1278    if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) {
1279        mAudioPlayer->seekTo(mSeekTimeUs);
1280
1281        mWatchForAudioSeekComplete = true;
1282        mWatchForAudioEOS = true;
1283
1284        if (mDecryptHandle != NULL) {
1285            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1286                    Playback::PAUSE, 0);
1287            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1288                    Playback::START, mSeekTimeUs / 1000);
1289        }
1290    }
1291}
1292
1293void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
1294    CHECK(source != NULL);
1295
1296    mAudioTrack = source;
1297}
1298
1299void AwesomePlayer::addTextSource(sp<MediaSource> source) {
1300    Mutex::Autolock autoLock(mTimedTextLock);
1301    CHECK(source != NULL);
1302
1303    if (mTextPlayer == NULL) {
1304        mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
1305    }
1306
1307    mTextPlayer->addTextSource(source);
1308}
1309
1310status_t AwesomePlayer::initAudioDecoder() {
1311    sp<MetaData> meta = mAudioTrack->getFormat();
1312
1313    const char *mime;
1314    CHECK(meta->findCString(kKeyMIMEType, &mime));
1315
1316    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
1317        mAudioSource = mAudioTrack;
1318    } else {
1319        mAudioSource = OMXCodec::Create(
1320                mClient.interface(), mAudioTrack->getFormat(),
1321                false, // createEncoder
1322                mAudioTrack);
1323    }
1324
1325    if (mAudioSource != NULL) {
1326        int64_t durationUs;
1327        if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1328            Mutex::Autolock autoLock(mMiscStateLock);
1329            if (mDurationUs < 0 || durationUs > mDurationUs) {
1330                mDurationUs = durationUs;
1331            }
1332        }
1333
1334        status_t err = mAudioSource->start();
1335
1336        if (err != OK) {
1337            mAudioSource.clear();
1338            return err;
1339        }
1340    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1341        // For legacy reasons we're simply going to ignore the absence
1342        // of an audio decoder for QCELP instead of aborting playback
1343        // altogether.
1344        return OK;
1345    }
1346
1347    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1348}
1349
1350void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1351    CHECK(source != NULL);
1352
1353    mVideoTrack = source;
1354}
1355
1356status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
1357
1358    // Either the application or the DRM system can independently say
1359    // that there must be a hardware-protected path to an external video sink.
1360    // For now we always require a hardware-protected path to external video sink
1361    // if content is DRMed, but eventually this could be optional per DRM agent.
1362    // When the application wants protection, then
1363    //   (USE_SURFACE_ALLOC && (mSurface != 0) &&
1364    //   (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp))
1365    // will be true, but that part is already handled by SurfaceFlinger.
1366
1367#ifdef DEBUG_HDCP
1368    // For debugging, we allow a system property to control the protected usage.
1369    // In case of uninitialized or unexpected property, we default to "DRM only".
1370    bool setProtectionBit = false;
1371    char value[PROPERTY_VALUE_MAX];
1372    if (property_get("persist.sys.hdcp_checking", value, NULL)) {
1373        if (!strcmp(value, "never")) {
1374            // nop
1375        } else if (!strcmp(value, "always")) {
1376            setProtectionBit = true;
1377        } else if (!strcmp(value, "drm-only")) {
1378            if (mDecryptHandle != NULL) {
1379                setProtectionBit = true;
1380            }
1381        // property value is empty, or unexpected value
1382        } else {
1383            if (mDecryptHandle != NULL) {
1384                setProtectionBit = true;
1385            }
1386        }
1387    // can' read property value
1388    } else {
1389        if (mDecryptHandle != NULL) {
1390            setProtectionBit = true;
1391        }
1392    }
1393    // note that usage bit is already cleared, so no need to clear it in the "else" case
1394    if (setProtectionBit) {
1395        flags |= OMXCodec::kEnableGrallocUsageProtected;
1396    }
1397#else
1398    if (mDecryptHandle != NULL) {
1399        flags |= OMXCodec::kEnableGrallocUsageProtected;
1400    }
1401#endif
1402    LOGV("initVideoDecoder flags=0x%x", flags);
1403    mVideoSource = OMXCodec::Create(
1404            mClient.interface(), mVideoTrack->getFormat(),
1405            false, // createEncoder
1406            mVideoTrack,
1407            NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
1408
1409    if (mVideoSource != NULL) {
1410        int64_t durationUs;
1411        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1412            Mutex::Autolock autoLock(mMiscStateLock);
1413            if (mDurationUs < 0 || durationUs > mDurationUs) {
1414                mDurationUs = durationUs;
1415            }
1416        }
1417
1418        status_t err = mVideoSource->start();
1419
1420        if (err != OK) {
1421            mVideoSource.clear();
1422            return err;
1423        }
1424    }
1425
1426    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1427}
1428
1429void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1430    if (mSeeking == SEEK_VIDEO_ONLY) {
1431        mSeeking = NO_SEEK;
1432        return;
1433    }
1434
1435    if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) {
1436        return;
1437    }
1438
1439    if (mAudioPlayer != NULL) {
1440        LOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
1441
1442        // If we don't have a video time, seek audio to the originally
1443        // requested seek time instead.
1444
1445        mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1446        mWatchForAudioSeekComplete = true;
1447        mWatchForAudioEOS = true;
1448    } else if (!mSeekNotificationSent) {
1449        // If we're playing video only, report seek complete now,
1450        // otherwise audio player will notify us later.
1451        notifyListener_l(MEDIA_SEEK_COMPLETE);
1452        mSeekNotificationSent = true;
1453    }
1454
1455    mFlags |= FIRST_FRAME;
1456    mSeeking = NO_SEEK;
1457
1458    if (mDecryptHandle != NULL) {
1459        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1460                Playback::PAUSE, 0);
1461        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1462                Playback::START, videoTimeUs / 1000);
1463    }
1464}
1465
1466void AwesomePlayer::onVideoEvent() {
1467    Mutex::Autolock autoLock(mLock);
1468    if (!mVideoEventPending) {
1469        // The event has been cancelled in reset_l() but had already
1470        // been scheduled for execution at that time.
1471        return;
1472    }
1473    mVideoEventPending = false;
1474
1475    if (mSeeking != NO_SEEK) {
1476        if (mVideoBuffer) {
1477            mVideoBuffer->release();
1478            mVideoBuffer = NULL;
1479        }
1480
1481        if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL
1482                && !(mFlags & SEEK_PREVIEW)) {
1483            // We're going to seek the video source first, followed by
1484            // the audio source.
1485            // In order to avoid jumps in the DataSource offset caused by
1486            // the audio codec prefetching data from the old locations
1487            // while the video codec is already reading data from the new
1488            // locations, we'll "pause" the audio source, causing it to
1489            // stop reading input data until a subsequent seek.
1490
1491            if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
1492                mAudioPlayer->pause();
1493
1494                mFlags &= ~AUDIO_RUNNING;
1495            }
1496            mAudioSource->pause();
1497        }
1498    }
1499
1500    if (!mVideoBuffer) {
1501        MediaSource::ReadOptions options;
1502        if (mSeeking != NO_SEEK) {
1503            LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1504
1505            options.setSeekTo(
1506                    mSeekTimeUs,
1507                    mSeeking == SEEK_VIDEO_ONLY
1508                        ? MediaSource::ReadOptions::SEEK_NEXT_SYNC
1509                        : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
1510        }
1511        for (;;) {
1512            status_t err = mVideoSource->read(&mVideoBuffer, &options);
1513            options.clearSeekTo();
1514
1515            if (err != OK) {
1516                CHECK(mVideoBuffer == NULL);
1517
1518                if (err == INFO_FORMAT_CHANGED) {
1519                    LOGV("VideoSource signalled format change.");
1520
1521                    notifyVideoSize_l();
1522
1523                    if (mVideoRenderer != NULL) {
1524                        mVideoRendererIsPreview = false;
1525                        initRenderer_l();
1526                    }
1527                    continue;
1528                }
1529
1530                // So video playback is complete, but we may still have
1531                // a seek request pending that needs to be applied
1532                // to the audio track.
1533                if (mSeeking != NO_SEEK) {
1534                    LOGV("video stream ended while seeking!");
1535                }
1536                finishSeekIfNecessary(-1);
1537
1538                if (mAudioPlayer != NULL
1539                        && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1540                    startAudioPlayer_l();
1541                }
1542
1543                mFlags |= VIDEO_AT_EOS;
1544                postStreamDoneEvent_l(err);
1545                return;
1546            }
1547
1548            if (mVideoBuffer->range_length() == 0) {
1549                // Some decoders, notably the PV AVC software decoder
1550                // return spurious empty buffers that we just want to ignore.
1551
1552                mVideoBuffer->release();
1553                mVideoBuffer = NULL;
1554                continue;
1555            }
1556
1557            break;
1558        }
1559    }
1560
1561    int64_t timeUs;
1562    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1563
1564    mLastVideoTimeUs = timeUs;
1565
1566    if (mSeeking == SEEK_VIDEO_ONLY) {
1567        if (mSeekTimeUs > timeUs) {
1568            LOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us",
1569                 mSeekTimeUs, timeUs);
1570        }
1571    }
1572
1573    {
1574        Mutex::Autolock autoLock(mMiscStateLock);
1575        mVideoTimeUs = timeUs;
1576    }
1577
1578    SeekType wasSeeking = mSeeking;
1579    finishSeekIfNecessary(timeUs);
1580
1581    if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1582        status_t err = startAudioPlayer_l();
1583        if (err != OK) {
1584            LOGE("Startung the audio player failed w/ err %d", err);
1585            return;
1586        }
1587    }
1588
1589    if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
1590        mTextPlayer->resume();
1591        mFlags |= TEXT_RUNNING;
1592    }
1593
1594    TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1595
1596    if (mFlags & FIRST_FRAME) {
1597        mFlags &= ~FIRST_FRAME;
1598        mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
1599    }
1600
1601    int64_t realTimeUs, mediaTimeUs;
1602    if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
1603        && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1604        mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1605    }
1606
1607    if (wasSeeking == SEEK_VIDEO_ONLY) {
1608        int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1609
1610        int64_t latenessUs = nowUs - timeUs;
1611
1612        if (latenessUs > 0) {
1613            LOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6);
1614        }
1615    }
1616
1617    if (wasSeeking == NO_SEEK) {
1618        // Let's display the first frame after seeking right away.
1619
1620        int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1621
1622        int64_t latenessUs = nowUs - timeUs;
1623
1624        if (latenessUs > 500000ll
1625                && mRTSPController == NULL
1626                && mAudioPlayer != NULL
1627                && mAudioPlayer->getMediaTimeMapping(
1628                    &realTimeUs, &mediaTimeUs)) {
1629            LOGI("we're much too late (%.2f secs), video skipping ahead",
1630                 latenessUs / 1E6);
1631
1632            mVideoBuffer->release();
1633            mVideoBuffer = NULL;
1634
1635            mSeeking = SEEK_VIDEO_ONLY;
1636            mSeekTimeUs = mediaTimeUs;
1637
1638            postVideoEvent_l();
1639            return;
1640        }
1641
1642        if (latenessUs > 40000) {
1643            // We're more than 40ms late.
1644            LOGV("we're late by %lld us (%.2f secs), dropping frame",
1645                 latenessUs, latenessUs / 1E6);
1646            mVideoBuffer->release();
1647            mVideoBuffer = NULL;
1648
1649            postVideoEvent_l();
1650            return;
1651        }
1652
1653        if (latenessUs < -10000) {
1654            // We're more than 10ms early.
1655
1656            postVideoEvent_l(10000);
1657            return;
1658        }
1659    }
1660
1661    if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1662        mVideoRendererIsPreview = false;
1663
1664        initRenderer_l();
1665    }
1666
1667    if (mVideoRenderer != NULL) {
1668        mVideoRenderer->render(mVideoBuffer);
1669    }
1670
1671    mVideoBuffer->release();
1672    mVideoBuffer = NULL;
1673
1674    if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) {
1675        mFlags &= ~SEEK_PREVIEW;
1676        return;
1677    }
1678
1679    postVideoEvent_l();
1680}
1681
1682void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1683    if (mVideoEventPending) {
1684        return;
1685    }
1686
1687    mVideoEventPending = true;
1688    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1689}
1690
1691void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
1692    if (mStreamDoneEventPending) {
1693        return;
1694    }
1695    mStreamDoneEventPending = true;
1696
1697    mStreamDoneStatus = status;
1698    mQueue.postEvent(mStreamDoneEvent);
1699}
1700
1701void AwesomePlayer::postBufferingEvent_l() {
1702    if (mBufferingEventPending) {
1703        return;
1704    }
1705    mBufferingEventPending = true;
1706    mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1707}
1708
1709void AwesomePlayer::postVideoLagEvent_l() {
1710    if (mVideoLagEventPending) {
1711        return;
1712    }
1713    mVideoLagEventPending = true;
1714    mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
1715}
1716
1717void AwesomePlayer::postCheckAudioStatusEvent_l(int64_t delayUs) {
1718    if (mAudioStatusEventPending) {
1719        return;
1720    }
1721    mAudioStatusEventPending = true;
1722    mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs);
1723}
1724
1725void AwesomePlayer::onCheckAudioStatus() {
1726    Mutex::Autolock autoLock(mLock);
1727    if (!mAudioStatusEventPending) {
1728        // Event was dispatched and while we were blocking on the mutex,
1729        // has already been cancelled.
1730        return;
1731    }
1732
1733    mAudioStatusEventPending = false;
1734
1735    if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1736        mWatchForAudioSeekComplete = false;
1737
1738        if (!mSeekNotificationSent) {
1739            notifyListener_l(MEDIA_SEEK_COMPLETE);
1740            mSeekNotificationSent = true;
1741        }
1742
1743        mSeeking = NO_SEEK;
1744    }
1745
1746    status_t finalStatus;
1747    if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
1748        mWatchForAudioEOS = false;
1749        mFlags |= AUDIO_AT_EOS;
1750        mFlags |= FIRST_FRAME;
1751        postStreamDoneEvent_l(finalStatus);
1752    }
1753}
1754
1755status_t AwesomePlayer::prepare() {
1756    Mutex::Autolock autoLock(mLock);
1757    return prepare_l();
1758}
1759
1760status_t AwesomePlayer::prepare_l() {
1761    if (mFlags & PREPARED) {
1762        return OK;
1763    }
1764
1765    if (mFlags & PREPARING) {
1766        return UNKNOWN_ERROR;
1767    }
1768
1769    mIsAsyncPrepare = false;
1770    status_t err = prepareAsync_l();
1771
1772    if (err != OK) {
1773        return err;
1774    }
1775
1776    while (mFlags & PREPARING) {
1777        mPreparedCondition.wait(mLock);
1778    }
1779
1780    return mPrepareResult;
1781}
1782
1783status_t AwesomePlayer::prepareAsync() {
1784    Mutex::Autolock autoLock(mLock);
1785
1786    if (mFlags & PREPARING) {
1787        return UNKNOWN_ERROR;  // async prepare already pending
1788    }
1789
1790    mIsAsyncPrepare = true;
1791    return prepareAsync_l();
1792}
1793
1794status_t AwesomePlayer::prepareAsync_l() {
1795    if (mFlags & PREPARING) {
1796        return UNKNOWN_ERROR;  // async prepare already pending
1797    }
1798
1799    if (!mQueueStarted) {
1800        mQueue.start();
1801        mQueueStarted = true;
1802    }
1803
1804    mFlags |= PREPARING;
1805    mAsyncPrepareEvent = new AwesomeEvent(
1806            this, &AwesomePlayer::onPrepareAsyncEvent);
1807
1808    mQueue.postEvent(mAsyncPrepareEvent);
1809
1810    return OK;
1811}
1812
1813status_t AwesomePlayer::finishSetDataSource_l() {
1814    sp<DataSource> dataSource;
1815
1816    bool isWidevineStreaming = false;
1817    if (!strncasecmp("widevine://", mUri.string(), 11)) {
1818        isWidevineStreaming = true;
1819
1820        String8 newURI = String8("http://");
1821        newURI.append(mUri.string() + 11);
1822
1823        mUri = newURI;
1824    }
1825
1826    if (!strncasecmp("http://", mUri.string(), 7)
1827            || !strncasecmp("https://", mUri.string(), 8)
1828            || isWidevineStreaming) {
1829        mConnectingDataSource = HTTPBase::Create(
1830                (mFlags & INCOGNITO)
1831                    ? HTTPBase::kFlagIncognito
1832                    : 0);
1833
1834        mLock.unlock();
1835        status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
1836        mLock.lock();
1837
1838        if (err != OK) {
1839            mConnectingDataSource.clear();
1840
1841            LOGI("mConnectingDataSource->connect() returned %d", err);
1842            return err;
1843        }
1844
1845        if (!isWidevineStreaming) {
1846            // The widevine extractor does its own caching.
1847
1848#if 0
1849            mCachedSource = new NuCachedSource2(
1850                    new ThrottledSource(
1851                        mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1852#else
1853            mCachedSource = new NuCachedSource2(mConnectingDataSource);
1854#endif
1855
1856            dataSource = mCachedSource;
1857        } else {
1858            dataSource = mConnectingDataSource;
1859        }
1860
1861        mConnectingDataSource.clear();
1862
1863
1864        String8 contentType = dataSource->getMIMEType();
1865
1866        if (strncasecmp(contentType.string(), "audio/", 6)) {
1867            // We're not doing this for streams that appear to be audio-only
1868            // streams to ensure that even low bandwidth streams start
1869            // playing back fairly instantly.
1870
1871            // We're going to prefill the cache before trying to instantiate
1872            // the extractor below, as the latter is an operation that otherwise
1873            // could block on the datasource for a significant amount of time.
1874            // During that time we'd be unable to abort the preparation phase
1875            // without this prefill.
1876            if (mCachedSource != NULL) {
1877                // We're going to prefill the cache before trying to instantiate
1878                // the extractor below, as the latter is an operation that otherwise
1879                // could block on the datasource for a significant amount of time.
1880                // During that time we'd be unable to abort the preparation phase
1881                // without this prefill.
1882
1883                mLock.unlock();
1884
1885                for (;;) {
1886                    status_t finalStatus;
1887                    size_t cachedDataRemaining =
1888                        mCachedSource->approxDataRemaining(&finalStatus);
1889
1890                    if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
1891                            || (mFlags & PREPARE_CANCELLED)) {
1892                        break;
1893                    }
1894
1895                    usleep(200000);
1896                }
1897
1898                mLock.lock();
1899            }
1900
1901            if (mFlags & PREPARE_CANCELLED) {
1902                LOGI("Prepare cancelled while waiting for initial cache fill.");
1903                return UNKNOWN_ERROR;
1904            }
1905        }
1906    } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1907        if (mLooper == NULL) {
1908            mLooper = new ALooper;
1909            mLooper->setName("rtsp");
1910            mLooper->start();
1911        }
1912        mRTSPController = new ARTSPController(mLooper);
1913        mConnectingRTSPController = mRTSPController;
1914
1915        mLock.unlock();
1916        status_t err = mRTSPController->connect(mUri.string());
1917        mLock.lock();
1918
1919        mConnectingRTSPController.clear();
1920
1921        LOGI("ARTSPController::connect returned %d", err);
1922
1923        if (err != OK) {
1924            mRTSPController.clear();
1925            return err;
1926        }
1927
1928        sp<MediaExtractor> extractor = mRTSPController.get();
1929        return setDataSource_l(extractor);
1930    } else {
1931        dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1932    }
1933
1934    if (dataSource == NULL) {
1935        return UNKNOWN_ERROR;
1936    }
1937
1938    sp<MediaExtractor> extractor;
1939
1940    if (isWidevineStreaming) {
1941        String8 mimeType;
1942        float confidence;
1943        sp<AMessage> dummy;
1944        bool success = SniffDRM(dataSource, &mimeType, &confidence, &dummy);
1945
1946        if (!success
1947                || strcasecmp(
1948                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
1949            return ERROR_UNSUPPORTED;
1950        }
1951
1952        mWVMExtractor = new WVMExtractor(dataSource);
1953        mWVMExtractor->setAdaptiveStreamingMode(true);
1954        extractor = mWVMExtractor;
1955    } else {
1956        extractor = MediaExtractor::Create(dataSource);
1957
1958        if (extractor == NULL) {
1959            return UNKNOWN_ERROR;
1960        }
1961    }
1962
1963    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
1964
1965    if (mDecryptHandle != NULL) {
1966        CHECK(mDrmManagerClient);
1967        if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
1968            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
1969        }
1970    }
1971
1972    status_t err = setDataSource_l(extractor);
1973
1974    if (err != OK) {
1975        mWVMExtractor.clear();
1976
1977        return err;
1978    }
1979
1980    return OK;
1981}
1982
1983void AwesomePlayer::abortPrepare(status_t err) {
1984    CHECK(err != OK);
1985
1986    if (mIsAsyncPrepare) {
1987        notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1988    }
1989
1990    mPrepareResult = err;
1991    mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
1992    mAsyncPrepareEvent = NULL;
1993    mPreparedCondition.broadcast();
1994}
1995
1996// static
1997bool AwesomePlayer::ContinuePreparation(void *cookie) {
1998    AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1999
2000    return (me->mFlags & PREPARE_CANCELLED) == 0;
2001}
2002
2003void AwesomePlayer::onPrepareAsyncEvent() {
2004    Mutex::Autolock autoLock(mLock);
2005
2006    if (mFlags & PREPARE_CANCELLED) {
2007        LOGI("prepare was cancelled before doing anything");
2008        abortPrepare(UNKNOWN_ERROR);
2009        return;
2010    }
2011
2012    if (mUri.size() > 0) {
2013        status_t err = finishSetDataSource_l();
2014
2015        if (err != OK) {
2016            abortPrepare(err);
2017            return;
2018        }
2019    }
2020
2021    if (mVideoTrack != NULL && mVideoSource == NULL) {
2022        status_t err = initVideoDecoder();
2023
2024        if (err != OK) {
2025            abortPrepare(err);
2026            return;
2027        }
2028    }
2029
2030    if (mAudioTrack != NULL && mAudioSource == NULL) {
2031        status_t err = initAudioDecoder();
2032
2033        if (err != OK) {
2034            abortPrepare(err);
2035            return;
2036        }
2037    }
2038
2039    mFlags |= PREPARING_CONNECTED;
2040
2041    if (isStreamingHTTP() || mRTSPController != NULL) {
2042        postBufferingEvent_l();
2043    } else {
2044        finishAsyncPrepare_l();
2045    }
2046}
2047
2048void AwesomePlayer::finishAsyncPrepare_l() {
2049    if (mIsAsyncPrepare) {
2050        if (mVideoSource == NULL) {
2051            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
2052        } else {
2053            notifyVideoSize_l();
2054        }
2055
2056        notifyListener_l(MEDIA_PREPARED);
2057    }
2058
2059    mPrepareResult = OK;
2060    mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
2061    mFlags |= PREPARED;
2062    mAsyncPrepareEvent = NULL;
2063    mPreparedCondition.broadcast();
2064}
2065
2066uint32_t AwesomePlayer::flags() const {
2067    return mExtractorFlags;
2068}
2069
2070void AwesomePlayer::postAudioEOS(int64_t delayUs) {
2071    Mutex::Autolock autoLock(mLock);
2072    postCheckAudioStatusEvent_l(delayUs);
2073}
2074
2075void AwesomePlayer::postAudioSeekComplete() {
2076    Mutex::Autolock autoLock(mLock);
2077    postAudioSeekComplete_l();
2078}
2079
2080void AwesomePlayer::postAudioSeekComplete_l() {
2081    postCheckAudioStatusEvent_l(0 /* delayUs */);
2082}
2083
2084status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
2085    switch (key) {
2086        case KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX:
2087        {
2088            Mutex::Autolock autoLock(mTimedTextLock);
2089            return setTimedTextTrackIndex(request.readInt32());
2090        }
2091        case KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE:
2092        {
2093            Mutex::Autolock autoLock(mTimedTextLock);
2094            if (mTextPlayer == NULL) {
2095                mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
2096            }
2097
2098            return mTextPlayer->setParameter(key, request);
2099        }
2100        case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS:
2101        {
2102            return setCacheStatCollectFreq(request);
2103        }
2104        default:
2105        {
2106            return ERROR_UNSUPPORTED;
2107        }
2108    }
2109}
2110
2111status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) {
2112    if (mCachedSource != NULL) {
2113        int32_t freqMs = request.readInt32();
2114        LOGD("Request to keep cache stats in the past %d ms",
2115            freqMs);
2116        return mCachedSource->setCacheStatCollectFreq(freqMs);
2117    }
2118    return ERROR_UNSUPPORTED;
2119}
2120
2121status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
2122    return OK;
2123}
2124
2125bool AwesomePlayer::isStreamingHTTP() const {
2126    return mCachedSource != NULL || mWVMExtractor != NULL;
2127}
2128
2129}  // namespace android
2130