AwesomePlayer.cpp revision 145e68fc778275963189b02a1adcbe27cce4d769
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//#define LOG_NDEBUG 0
18#define LOG_TAG "AwesomePlayer"
19#include <utils/Log.h>
20
21#include <dlfcn.h>
22
23#include "include/ARTSPController.h"
24#include "include/AwesomePlayer.h"
25#include "include/SoftwareRenderer.h"
26#include "include/NuCachedSource2.h"
27#include "include/ThrottledSource.h"
28#include "include/MPEG2TSExtractor.h"
29
30#include "ARTPSession.h"
31#include "APacketSource.h"
32#include "ASessionDescription.h"
33#include "UDPPusher.h"
34
35#include <binder/IPCThreadState.h>
36#include <media/stagefright/foundation/hexdump.h>
37#include <media/stagefright/foundation/ADebug.h>
38#include <media/stagefright/AudioPlayer.h>
39#include <media/stagefright/DataSource.h>
40#include <media/stagefright/FileSource.h>
41#include <media/stagefright/MediaBuffer.h>
42#include <media/stagefright/MediaDefs.h>
43#include <media/stagefright/MediaExtractor.h>
44#include <media/stagefright/MediaSource.h>
45#include <media/stagefright/MetaData.h>
46#include <media/stagefright/OMXCodec.h>
47
48#include <surfaceflinger/Surface.h>
49
50#include <media/stagefright/foundation/ALooper.h>
51#include <media/stagefright/foundation/AMessage.h>
52#include "include/LiveSession.h"
53
54#define USE_SURFACE_ALLOC 1
55#define FRAME_DROP_FREQ 7
56
57namespace android {
58
59static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
60static int64_t kHighWaterMarkUs = 10000000ll;  // 10secs
61
62struct AwesomeEvent : public TimedEventQueue::Event {
63    AwesomeEvent(
64            AwesomePlayer *player,
65            void (AwesomePlayer::*method)())
66        : mPlayer(player),
67          mMethod(method) {
68    }
69
70protected:
71    virtual ~AwesomeEvent() {}
72
73    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
74        (mPlayer->*mMethod)();
75    }
76
77private:
78    AwesomePlayer *mPlayer;
79    void (AwesomePlayer::*mMethod)();
80
81    AwesomeEvent(const AwesomeEvent &);
82    AwesomeEvent &operator=(const AwesomeEvent &);
83};
84
85struct AwesomeLocalRenderer : public AwesomeRenderer {
86    AwesomeLocalRenderer(
87            const sp<Surface> &surface, const sp<MetaData> &meta)
88        : mTarget(new SoftwareRenderer(surface, meta)) {
89    }
90
91    virtual void render(MediaBuffer *buffer) {
92        render((const uint8_t *)buffer->data() + buffer->range_offset(),
93               buffer->range_length());
94    }
95
96    void render(const void *data, size_t size) {
97        mTarget->render(data, size, NULL);
98    }
99
100protected:
101    virtual ~AwesomeLocalRenderer() {
102        delete mTarget;
103        mTarget = NULL;
104    }
105
106private:
107    SoftwareRenderer *mTarget;
108
109    AwesomeLocalRenderer(const AwesomeLocalRenderer &);
110    AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
111};
112
113struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
114    AwesomeNativeWindowRenderer(
115            const sp<ANativeWindow> &nativeWindow,
116            int32_t rotationDegrees)
117        : mNativeWindow(nativeWindow) {
118        applyRotation(rotationDegrees);
119    }
120
121    virtual void render(MediaBuffer *buffer) {
122        status_t err = mNativeWindow->queueBuffer(
123                mNativeWindow.get(), buffer->graphicBuffer().get());
124        if (err != 0) {
125            LOGE("queueBuffer failed with error %s (%d)", strerror(-err),
126                    -err);
127            return;
128        }
129
130        sp<MetaData> metaData = buffer->meta_data();
131        metaData->setInt32(kKeyRendered, 1);
132    }
133
134protected:
135    virtual ~AwesomeNativeWindowRenderer() {}
136
137private:
138    sp<ANativeWindow> mNativeWindow;
139
140    void applyRotation(int32_t rotationDegrees) {
141        uint32_t transform;
142        switch (rotationDegrees) {
143            case 0: transform = 0; break;
144            case 90: transform = HAL_TRANSFORM_ROT_90; break;
145            case 180: transform = HAL_TRANSFORM_ROT_180; break;
146            case 270: transform = HAL_TRANSFORM_ROT_270; break;
147            default: transform = 0; break;
148        }
149
150        if (transform) {
151            CHECK_EQ(0, native_window_set_buffers_transform(
152                        mNativeWindow.get(), transform));
153        }
154    }
155
156    AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
157    AwesomeNativeWindowRenderer &operator=(
158            const AwesomeNativeWindowRenderer &);
159};
160
161////////////////////////////////////////////////////////////////////////////////
162
163AwesomePlayer::AwesomePlayer()
164    : mQueueStarted(false),
165      mTimeSource(NULL),
166      mVideoRendererIsPreview(false),
167      mAudioPlayer(NULL),
168      mFlags(0),
169      mExtractorFlags(0),
170      mVideoBuffer(NULL),
171      mDecryptHandle(NULL) {
172    CHECK_EQ(mClient.connect(), (status_t)OK);
173
174    DataSource::RegisterDefaultSniffers();
175
176    mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
177    mVideoEventPending = false;
178    mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
179    mStreamDoneEventPending = false;
180    mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
181    mBufferingEventPending = false;
182    mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);
183    mVideoEventPending = false;
184
185    mCheckAudioStatusEvent = new AwesomeEvent(
186            this, &AwesomePlayer::onCheckAudioStatus);
187
188    mAudioStatusEventPending = false;
189
190    reset();
191}
192
193AwesomePlayer::~AwesomePlayer() {
194    if (mQueueStarted) {
195        mQueue.stop();
196    }
197
198    reset();
199
200    mClient.disconnect();
201}
202
203void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
204    mQueue.cancelEvent(mVideoEvent->eventID());
205    mVideoEventPending = false;
206    mQueue.cancelEvent(mStreamDoneEvent->eventID());
207    mStreamDoneEventPending = false;
208    mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
209    mAudioStatusEventPending = false;
210    mQueue.cancelEvent(mVideoLagEvent->eventID());
211    mVideoLagEventPending = false;
212
213    if (!keepBufferingGoing) {
214        mQueue.cancelEvent(mBufferingEvent->eventID());
215        mBufferingEventPending = false;
216    }
217}
218
219void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
220    Mutex::Autolock autoLock(mLock);
221    mListener = listener;
222}
223
224status_t AwesomePlayer::setDataSource(
225        const char *uri, const KeyedVector<String8, String8> *headers) {
226    Mutex::Autolock autoLock(mLock);
227    return setDataSource_l(uri, headers);
228}
229
230status_t AwesomePlayer::setDataSource_l(
231        const char *uri, const KeyedVector<String8, String8> *headers) {
232    reset_l();
233
234    mUri = uri;
235
236    if (!strncmp("http://", uri, 7)) {
237        // Hack to support http live.
238
239        size_t len = strlen(uri);
240        if (!strcasecmp(&uri[len - 5], ".m3u8")
241                || strstr(&uri[7], "m3u8") != NULL) {
242            mUri = "httplive://";
243            mUri.append(&uri[7]);
244        }
245    }
246
247    if (headers) {
248        mUriHeaders = *headers;
249    }
250
251    // The actual work will be done during preparation in the call to
252    // ::finishSetDataSource_l to avoid blocking the calling thread in
253    // setDataSource for any significant time.
254
255    return OK;
256}
257
258status_t AwesomePlayer::setDataSource(
259        int fd, int64_t offset, int64_t length) {
260    Mutex::Autolock autoLock(mLock);
261
262    reset_l();
263
264    sp<DataSource> dataSource = new FileSource(fd, offset, length);
265
266    status_t err = dataSource->initCheck();
267
268    if (err != OK) {
269        return err;
270    }
271
272    mFileSource = dataSource;
273
274    return setDataSource_l(dataSource);
275}
276
277status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source) {
278    return INVALID_OPERATION;
279}
280
281status_t AwesomePlayer::setDataSource_l(
282        const sp<DataSource> &dataSource) {
283    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
284
285    if (extractor == NULL) {
286        return UNKNOWN_ERROR;
287    }
288
289    dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
290    if (mDecryptHandle != NULL
291            && RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
292        notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
293    }
294
295    return setDataSource_l(extractor);
296}
297
298status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
299    // Attempt to approximate overall stream bitrate by summing all
300    // tracks' individual bitrates, if not all of them advertise bitrate,
301    // we have to fail.
302
303    int64_t totalBitRate = 0;
304
305    for (size_t i = 0; i < extractor->countTracks(); ++i) {
306        sp<MetaData> meta = extractor->getTrackMetaData(i);
307
308        int32_t bitrate;
309        if (!meta->findInt32(kKeyBitRate, &bitrate)) {
310            totalBitRate = -1;
311            break;
312        }
313
314        totalBitRate += bitrate;
315    }
316
317    mBitrate = totalBitRate;
318
319    LOGV("mBitrate = %lld bits/sec", mBitrate);
320
321    bool haveAudio = false;
322    bool haveVideo = false;
323    for (size_t i = 0; i < extractor->countTracks(); ++i) {
324        sp<MetaData> meta = extractor->getTrackMetaData(i);
325
326        const char *mime;
327        CHECK(meta->findCString(kKeyMIMEType, &mime));
328
329        if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
330            setVideoSource(extractor->getTrack(i));
331            haveVideo = true;
332        } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
333            setAudioSource(extractor->getTrack(i));
334            haveAudio = true;
335
336            if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
337                // Only do this for vorbis audio, none of the other audio
338                // formats even support this ringtone specific hack and
339                // retrieving the metadata on some extractors may turn out
340                // to be very expensive.
341                sp<MetaData> fileMeta = extractor->getMetaData();
342                int32_t loop;
343                if (fileMeta != NULL
344                        && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
345                    mFlags |= AUTO_LOOPING;
346                }
347            }
348        }
349
350        if (haveAudio && haveVideo) {
351            break;
352        }
353    }
354
355    if (!haveAudio && !haveVideo) {
356        return UNKNOWN_ERROR;
357    }
358
359    mExtractorFlags = extractor->flags();
360
361    return OK;
362}
363
364void AwesomePlayer::reset() {
365    LOGI("reset");
366
367    Mutex::Autolock autoLock(mLock);
368    reset_l();
369}
370
371void AwesomePlayer::reset_l() {
372    LOGI("reset_l");
373
374    if (mDecryptHandle != NULL) {
375            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
376                    Playback::STOP, 0);
377            mDrmManagerClient->closeDecryptSession(mDecryptHandle);
378            mDecryptHandle = NULL;
379            mDrmManagerClient = NULL;
380    }
381
382    if (mFlags & PREPARING) {
383        mFlags |= PREPARE_CANCELLED;
384        if (mConnectingDataSource != NULL) {
385            LOGI("interrupting the connection process");
386            mConnectingDataSource->disconnect();
387        }
388
389        if (mFlags & PREPARING_CONNECTED) {
390            // We are basically done preparing, we're just buffering
391            // enough data to start playback, we can safely interrupt that.
392            finishAsyncPrepare_l();
393        }
394    }
395
396    if (mFlags & PREPARING) {
397        LOGI("waiting until preparation is completes.");
398    }
399
400    while (mFlags & PREPARING) {
401        mPreparedCondition.wait(mLock);
402    }
403
404    cancelPlayerEvents();
405
406    mCachedSource.clear();
407    mAudioTrack.clear();
408    mVideoTrack.clear();
409
410    // Shutdown audio first, so that the respone to the reset request
411    // appears to happen instantaneously as far as the user is concerned
412    // If we did this later, audio would continue playing while we
413    // shutdown the video-related resources and the player appear to
414    // not be as responsive to a reset request.
415    if (mAudioPlayer == NULL && mAudioSource != NULL) {
416        // If we had an audio player, it would have effectively
417        // taken possession of the audio source and stopped it when
418        // _it_ is stopped. Otherwise this is still our responsibility.
419        mAudioSource->stop();
420    }
421    mAudioSource.clear();
422
423    LOGI("audio source cleared");
424
425    mTimeSource = NULL;
426
427    delete mAudioPlayer;
428    mAudioPlayer = NULL;
429
430    mVideoRenderer.clear();
431
432    if (mVideoBuffer) {
433        mVideoBuffer->release();
434        mVideoBuffer = NULL;
435    }
436
437    if (mRTSPController != NULL) {
438        mRTSPController->disconnect();
439        mRTSPController.clear();
440    }
441
442    if (mLiveSession != NULL) {
443        mLiveSession->disconnect();
444        mLiveSession.clear();
445    }
446
447    mRTPPusher.clear();
448    mRTCPPusher.clear();
449    mRTPSession.clear();
450
451    if (mVideoSource != NULL) {
452        mVideoSource->stop();
453
454        // The following hack is necessary to ensure that the OMX
455        // component is completely released by the time we may try
456        // to instantiate it again.
457        wp<MediaSource> tmp = mVideoSource;
458        mVideoSource.clear();
459        while (tmp.promote() != NULL) {
460            usleep(1000);
461        }
462        IPCThreadState::self()->flushCommands();
463    }
464
465    LOGI("video source cleared");
466
467    mDurationUs = -1;
468    mFlags = 0;
469    mExtractorFlags = 0;
470    mTimeSourceDeltaUs = 0;
471    mVideoTimeUs = 0;
472
473    mSeeking = false;
474    mSeekNotificationSent = false;
475    mSeekTimeUs = 0;
476
477    mUri.setTo("");
478    mUriHeaders.clear();
479
480    mFileSource.clear();
481
482    mBitrate = -1;
483
484    LOGI("reset_l completed");
485}
486
487void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
488    if (mListener != NULL) {
489        sp<MediaPlayerBase> listener = mListener.promote();
490
491        if (listener != NULL) {
492            listener->sendEvent(msg, ext1, ext2);
493        }
494    }
495}
496
497bool AwesomePlayer::getBitrate(int64_t *bitrate) {
498    off64_t size;
499    if (mDurationUs >= 0 && mCachedSource != NULL
500            && mCachedSource->getSize(&size) == OK) {
501        *bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
502        return true;
503    }
504
505    if (mBitrate >= 0) {
506        *bitrate = mBitrate;
507        return true;
508    }
509
510    *bitrate = 0;
511
512    return false;
513}
514
515// Returns true iff cached duration is available/applicable.
516bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
517    int64_t bitrate;
518
519    if (mRTSPController != NULL) {
520        *durationUs = mRTSPController->getQueueDurationUs(eos);
521        return true;
522    } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
523        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
524        *durationUs = cachedDataRemaining * 8000000ll / bitrate;
525        return true;
526    }
527
528    return false;
529}
530
531void AwesomePlayer::ensureCacheIsFetching_l() {
532    if (mCachedSource != NULL) {
533        mCachedSource->resumeFetchingIfNecessary();
534    }
535}
536
537void AwesomePlayer::onVideoLagUpdate() {
538    Mutex::Autolock autoLock(mLock);
539    if (!mVideoLagEventPending) {
540        return;
541    }
542    mVideoLagEventPending = false;
543
544    int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs();
545    int64_t videoLateByUs = audioTimeUs - mVideoTimeUs;
546
547    if (videoLateByUs > 300000ll) {
548        LOGV("video late by %lld ms.", videoLateByUs / 1000ll);
549
550        notifyListener_l(
551                MEDIA_INFO,
552                MEDIA_INFO_VIDEO_TRACK_LAGGING,
553                videoLateByUs / 1000ll);
554    }
555
556    postVideoLagEvent_l();
557}
558
559void AwesomePlayer::onBufferingUpdate() {
560    Mutex::Autolock autoLock(mLock);
561    if (!mBufferingEventPending) {
562        return;
563    }
564    mBufferingEventPending = false;
565
566    if (mCachedSource != NULL) {
567        bool eos;
568        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
569
570        if (eos) {
571            notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
572            if (mFlags & PREPARING) {
573                LOGV("cache has reached EOS, prepare is done.");
574                finishAsyncPrepare_l();
575            }
576        } else {
577            int64_t bitrate;
578            if (getBitrate(&bitrate)) {
579                size_t cachedSize = mCachedSource->cachedSize();
580                int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
581
582                int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
583                if (percentage > 100) {
584                    percentage = 100;
585                }
586
587                notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
588            } else {
589                // We don't know the bitrate of the stream, use absolute size
590                // limits to maintain the cache.
591
592                const size_t kLowWaterMarkBytes = 40000;
593                const size_t kHighWaterMarkBytes = 200000;
594
595                if ((mFlags & PLAYING) && !eos
596                        && (cachedDataRemaining < kLowWaterMarkBytes)) {
597                    LOGI("cache is running low (< %d) , pausing.",
598                         kLowWaterMarkBytes);
599                    mFlags |= CACHE_UNDERRUN;
600                    pause_l();
601                    ensureCacheIsFetching_l();
602                    notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
603                } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
604                    if (mFlags & CACHE_UNDERRUN) {
605                        LOGI("cache has filled up (> %d), resuming.",
606                             kHighWaterMarkBytes);
607                        mFlags &= ~CACHE_UNDERRUN;
608                        play_l();
609                        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
610                    } else if (mFlags & PREPARING) {
611                        LOGV("cache has filled up (> %d), prepare is done",
612                             kHighWaterMarkBytes);
613                        finishAsyncPrepare_l();
614                    }
615                }
616            }
617        }
618    }
619
620    int64_t cachedDurationUs;
621    bool eos;
622    if (getCachedDuration_l(&cachedDurationUs, &eos)) {
623        LOGV("cachedDurationUs = %.2f secs, eos=%d",
624             cachedDurationUs / 1E6, eos);
625
626        if ((mFlags & PLAYING) && !eos
627                && (cachedDurationUs < kLowWaterMarkUs)) {
628            LOGI("cache is running low (%.2f secs) , pausing.",
629                 cachedDurationUs / 1E6);
630            mFlags |= CACHE_UNDERRUN;
631            pause_l();
632            ensureCacheIsFetching_l();
633            notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
634        } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
635            if (mFlags & CACHE_UNDERRUN) {
636                LOGI("cache has filled up (%.2f secs), resuming.",
637                     cachedDurationUs / 1E6);
638                mFlags &= ~CACHE_UNDERRUN;
639                play_l();
640                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
641            } else if (mFlags & PREPARING) {
642                LOGV("cache has filled up (%.2f secs), prepare is done",
643                     cachedDurationUs / 1E6);
644                finishAsyncPrepare_l();
645            }
646        }
647    }
648
649    postBufferingEvent_l();
650}
651
652void AwesomePlayer::partial_reset_l() {
653    // Only reset the video renderer and shut down the video decoder.
654    // Then instantiate a new video decoder and resume video playback.
655
656    mVideoRenderer.clear();
657
658    if (mVideoBuffer) {
659        mVideoBuffer->release();
660        mVideoBuffer = NULL;
661    }
662
663    {
664        mVideoSource->stop();
665
666        // The following hack is necessary to ensure that the OMX
667        // component is completely released by the time we may try
668        // to instantiate it again.
669        wp<MediaSource> tmp = mVideoSource;
670        mVideoSource.clear();
671        while (tmp.promote() != NULL) {
672            usleep(1000);
673        }
674        IPCThreadState::self()->flushCommands();
675    }
676
677    CHECK_EQ((status_t)OK,
678             initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
679}
680
681void AwesomePlayer::onStreamDone() {
682    // Posted whenever any stream finishes playing.
683
684    Mutex::Autolock autoLock(mLock);
685    if (!mStreamDoneEventPending) {
686        return;
687    }
688    mStreamDoneEventPending = false;
689
690    if (mStreamDoneStatus == INFO_DISCONTINUITY) {
691        // This special status is returned because an http live stream's
692        // video stream switched to a different bandwidth at this point
693        // and future data may have been encoded using different parameters.
694        // This requires us to shutdown the video decoder and reinstantiate
695        // a fresh one.
696
697        LOGV("INFO_DISCONTINUITY");
698
699        CHECK(mVideoSource != NULL);
700
701        partial_reset_l();
702        postVideoEvent_l();
703        return;
704    } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
705        LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
706
707        notifyListener_l(
708                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
709
710        pause_l(true /* at eos */);
711
712        mFlags |= AT_EOS;
713        return;
714    }
715
716    const bool allDone =
717        (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
718            && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
719
720    if (!allDone) {
721        return;
722    }
723
724    if (mFlags & (LOOPING | AUTO_LOOPING)) {
725        seekTo_l(0);
726
727        if (mVideoSource != NULL) {
728            postVideoEvent_l();
729        }
730    } else {
731        LOGV("MEDIA_PLAYBACK_COMPLETE");
732        notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
733
734        pause_l(true /* at eos */);
735
736        mFlags |= AT_EOS;
737    }
738}
739
740status_t AwesomePlayer::play() {
741    Mutex::Autolock autoLock(mLock);
742
743    mFlags &= ~CACHE_UNDERRUN;
744
745    return play_l();
746}
747
748status_t AwesomePlayer::play_l() {
749    if (mFlags & PLAYING) {
750        return OK;
751    }
752
753    if (!(mFlags & PREPARED)) {
754        status_t err = prepare_l();
755
756        if (err != OK) {
757            return err;
758        }
759    }
760
761    mFlags |= PLAYING;
762    mFlags |= FIRST_FRAME;
763
764    bool deferredAudioSeek = false;
765
766    if (mDecryptHandle != NULL) {
767        int64_t position;
768        getPosition(&position);
769        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
770                Playback::START, position / 1000);
771    }
772
773    if (mAudioSource != NULL) {
774        if (mAudioPlayer == NULL) {
775            if (mAudioSink != NULL) {
776                mAudioPlayer = new AudioPlayer(mAudioSink, this);
777                mAudioPlayer->setSource(mAudioSource);
778
779                // We've already started the MediaSource in order to enable
780                // the prefetcher to read its data.
781                status_t err = mAudioPlayer->start(
782                        true /* sourceAlreadyStarted */);
783
784                if (err != OK) {
785                    delete mAudioPlayer;
786                    mAudioPlayer = NULL;
787
788                    mFlags &= ~(PLAYING | FIRST_FRAME);
789
790                    if (mDecryptHandle != NULL) {
791                        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
792                                 Playback::STOP, 0);
793                    }
794
795                    return err;
796                }
797
798                mTimeSource = mAudioPlayer;
799
800                deferredAudioSeek = true;
801
802                mWatchForAudioSeekComplete = false;
803                mWatchForAudioEOS = true;
804            }
805        } else {
806            mAudioPlayer->resume();
807        }
808    }
809
810    if (mTimeSource == NULL && mAudioPlayer == NULL) {
811        mTimeSource = &mSystemTimeSource;
812    }
813
814    if (mVideoSource != NULL) {
815        // Kick off video playback
816        postVideoEvent_l();
817
818        if (mAudioSource != NULL && mVideoSource != NULL) {
819            postVideoLagEvent_l();
820        }
821    }
822
823    if (deferredAudioSeek) {
824        // If there was a seek request while we were paused
825        // and we're just starting up again, honor the request now.
826        seekAudioIfNecessary_l();
827    }
828
829    if (mFlags & AT_EOS) {
830        // Legacy behaviour, if a stream finishes playing and then
831        // is started again, we play from the start...
832        seekTo_l(0);
833    }
834
835    return OK;
836}
837
838void AwesomePlayer::notifyVideoSize_l() {
839    sp<MetaData> meta = mVideoSource->getFormat();
840
841    int32_t cropLeft, cropTop, cropRight, cropBottom;
842    if (!meta->findRect(
843                kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
844        int32_t width, height;
845        CHECK(meta->findInt32(kKeyWidth, &width));
846        CHECK(meta->findInt32(kKeyHeight, &height));
847
848        cropLeft = cropTop = 0;
849        cropRight = width - 1;
850        cropBottom = height - 1;
851
852        LOGV("got dimensions only %d x %d", width, height);
853    } else {
854        LOGV("got crop rect %d, %d, %d, %d",
855             cropLeft, cropTop, cropRight, cropBottom);
856    }
857
858    int32_t usableWidth = cropRight - cropLeft + 1;
859    int32_t usableHeight = cropBottom - cropTop + 1;
860
861    int32_t rotationDegrees;
862    if (!mVideoTrack->getFormat()->findInt32(
863                kKeyRotation, &rotationDegrees)) {
864        rotationDegrees = 0;
865    }
866
867    if (rotationDegrees == 90 || rotationDegrees == 270) {
868        notifyListener_l(
869                MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
870    } else {
871        notifyListener_l(
872                MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
873    }
874}
875
876void AwesomePlayer::initRenderer_l() {
877    if (mSurface == NULL) {
878        return;
879    }
880
881    sp<MetaData> meta = mVideoSource->getFormat();
882
883    int32_t format;
884    const char *component;
885    int32_t decodedWidth, decodedHeight;
886    CHECK(meta->findInt32(kKeyColorFormat, &format));
887    CHECK(meta->findCString(kKeyDecoderComponent, &component));
888    CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
889    CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
890
891    int32_t rotationDegrees;
892    if (!mVideoTrack->getFormat()->findInt32(
893                kKeyRotation, &rotationDegrees)) {
894        rotationDegrees = 0;
895    }
896
897    mVideoRenderer.clear();
898
899    // Must ensure that mVideoRenderer's destructor is actually executed
900    // before creating a new one.
901    IPCThreadState::self()->flushCommands();
902
903    if (USE_SURFACE_ALLOC && strncmp(component, "OMX.", 4) == 0) {
904        // Hardware decoders avoid the CPU color conversion by decoding
905        // directly to ANativeBuffers, so we must use a renderer that
906        // just pushes those buffers to the ANativeWindow.
907        mVideoRenderer =
908            new AwesomeNativeWindowRenderer(mSurface, rotationDegrees);
909    } else {
910        // Other decoders are instantiated locally and as a consequence
911        // allocate their buffers in local address space.  This renderer
912        // then performs a color conversion and copy to get the data
913        // into the ANativeBuffer.
914        mVideoRenderer = new AwesomeLocalRenderer(mSurface, meta);
915    }
916}
917
918status_t AwesomePlayer::pause() {
919    Mutex::Autolock autoLock(mLock);
920
921    mFlags &= ~CACHE_UNDERRUN;
922
923    return pause_l();
924}
925
926status_t AwesomePlayer::pause_l(bool at_eos) {
927    if (!(mFlags & PLAYING)) {
928        return OK;
929    }
930
931    cancelPlayerEvents(true /* keepBufferingGoing */);
932
933    if (mAudioPlayer != NULL) {
934        if (at_eos) {
935            // If we played the audio stream to completion we
936            // want to make sure that all samples remaining in the audio
937            // track's queue are played out.
938            mAudioPlayer->pause(true /* playPendingSamples */);
939        } else {
940            mAudioPlayer->pause();
941        }
942    }
943
944    mFlags &= ~PLAYING;
945
946    if (mDecryptHandle != NULL) {
947        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
948                Playback::PAUSE, 0);
949    }
950
951    return OK;
952}
953
954bool AwesomePlayer::isPlaying() const {
955    return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
956}
957
958void AwesomePlayer::setSurface(const sp<Surface> &surface) {
959    Mutex::Autolock autoLock(mLock);
960
961    mSurface = surface;
962}
963
964void AwesomePlayer::setAudioSink(
965        const sp<MediaPlayerBase::AudioSink> &audioSink) {
966    Mutex::Autolock autoLock(mLock);
967
968    mAudioSink = audioSink;
969}
970
971status_t AwesomePlayer::setLooping(bool shouldLoop) {
972    Mutex::Autolock autoLock(mLock);
973
974    mFlags = mFlags & ~LOOPING;
975
976    if (shouldLoop) {
977        mFlags |= LOOPING;
978    }
979
980    return OK;
981}
982
983status_t AwesomePlayer::getDuration(int64_t *durationUs) {
984    Mutex::Autolock autoLock(mMiscStateLock);
985
986    if (mDurationUs < 0) {
987        return UNKNOWN_ERROR;
988    }
989
990    *durationUs = mDurationUs;
991
992    return OK;
993}
994
995status_t AwesomePlayer::getPosition(int64_t *positionUs) {
996    if (mRTSPController != NULL) {
997        *positionUs = mRTSPController->getNormalPlayTimeUs();
998    }
999    else if (mSeeking) {
1000        *positionUs = mSeekTimeUs;
1001    } else if (mVideoSource != NULL) {
1002        Mutex::Autolock autoLock(mMiscStateLock);
1003        *positionUs = mVideoTimeUs;
1004    } else if (mAudioPlayer != NULL) {
1005        *positionUs = mAudioPlayer->getMediaTimeUs();
1006    } else {
1007        *positionUs = 0;
1008    }
1009
1010    return OK;
1011}
1012
1013status_t AwesomePlayer::seekTo(int64_t timeUs) {
1014    if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
1015        Mutex::Autolock autoLock(mLock);
1016        return seekTo_l(timeUs);
1017    }
1018
1019    return OK;
1020}
1021
1022// static
1023void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
1024    static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
1025}
1026
1027void AwesomePlayer::onRTSPSeekDone() {
1028    notifyListener_l(MEDIA_SEEK_COMPLETE);
1029    mSeekNotificationSent = true;
1030}
1031
1032status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
1033    if (mRTSPController != NULL) {
1034        mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
1035        return OK;
1036    }
1037
1038    if (mFlags & CACHE_UNDERRUN) {
1039        mFlags &= ~CACHE_UNDERRUN;
1040        play_l();
1041    }
1042
1043    mSeeking = true;
1044    mSeekNotificationSent = false;
1045    mSeekTimeUs = timeUs;
1046    mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
1047
1048    seekAudioIfNecessary_l();
1049
1050    if (!(mFlags & PLAYING)) {
1051        LOGV("seeking while paused, sending SEEK_COMPLETE notification"
1052             " immediately.");
1053
1054        notifyListener_l(MEDIA_SEEK_COMPLETE);
1055        mSeekNotificationSent = true;
1056    }
1057
1058    return OK;
1059}
1060
1061void AwesomePlayer::seekAudioIfNecessary_l() {
1062    if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
1063        mAudioPlayer->seekTo(mSeekTimeUs);
1064
1065        mWatchForAudioSeekComplete = true;
1066        mWatchForAudioEOS = true;
1067        mSeekNotificationSent = false;
1068
1069        if (mDecryptHandle != NULL) {
1070            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1071                    Playback::PAUSE, 0);
1072            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1073                    Playback::START, mSeekTimeUs / 1000);
1074        }
1075    }
1076}
1077
1078void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
1079    CHECK(source != NULL);
1080
1081    mAudioTrack = source;
1082}
1083
1084status_t AwesomePlayer::initAudioDecoder() {
1085    sp<MetaData> meta = mAudioTrack->getFormat();
1086
1087    const char *mime;
1088    CHECK(meta->findCString(kKeyMIMEType, &mime));
1089
1090    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
1091        mAudioSource = mAudioTrack;
1092    } else {
1093        mAudioSource = OMXCodec::Create(
1094                mClient.interface(), mAudioTrack->getFormat(),
1095                false, // createEncoder
1096                mAudioTrack);
1097    }
1098
1099    if (mAudioSource != NULL) {
1100        int64_t durationUs;
1101        if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1102            Mutex::Autolock autoLock(mMiscStateLock);
1103            if (mDurationUs < 0 || durationUs > mDurationUs) {
1104                mDurationUs = durationUs;
1105            }
1106        }
1107
1108        status_t err = mAudioSource->start();
1109
1110        if (err != OK) {
1111            mAudioSource.clear();
1112            return err;
1113        }
1114    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1115        // For legacy reasons we're simply going to ignore the absence
1116        // of an audio decoder for QCELP instead of aborting playback
1117        // altogether.
1118        return OK;
1119    }
1120
1121    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1122}
1123
1124void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1125    CHECK(source != NULL);
1126
1127    mVideoTrack = source;
1128}
1129
1130status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
1131    mVideoSource = OMXCodec::Create(
1132            mClient.interface(), mVideoTrack->getFormat(),
1133            false, // createEncoder
1134            mVideoTrack,
1135            NULL, flags, USE_SURFACE_ALLOC ? mSurface : NULL);
1136
1137    if (mVideoSource != NULL) {
1138        int64_t durationUs;
1139        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1140            Mutex::Autolock autoLock(mMiscStateLock);
1141            if (mDurationUs < 0 || durationUs > mDurationUs) {
1142                mDurationUs = durationUs;
1143            }
1144        }
1145
1146        status_t err = mVideoSource->start();
1147
1148        if (err != OK) {
1149            mVideoSource.clear();
1150            return err;
1151        }
1152    }
1153
1154    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1155}
1156
1157void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1158    if (!mSeeking) {
1159        return;
1160    }
1161
1162    if (mAudioPlayer != NULL) {
1163        LOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
1164
1165        // If we don't have a video time, seek audio to the originally
1166        // requested seek time instead.
1167
1168        mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1169        mAudioPlayer->resume();
1170        mWatchForAudioSeekComplete = true;
1171        mWatchForAudioEOS = true;
1172    } else if (!mSeekNotificationSent) {
1173        // If we're playing video only, report seek complete now,
1174        // otherwise audio player will notify us later.
1175        notifyListener_l(MEDIA_SEEK_COMPLETE);
1176    }
1177
1178    mFlags |= FIRST_FRAME;
1179    mSeeking = false;
1180    mSeekNotificationSent = false;
1181
1182    if (mDecryptHandle != NULL) {
1183        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1184                Playback::PAUSE, 0);
1185        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1186                Playback::START, videoTimeUs / 1000);
1187    }
1188}
1189
1190void AwesomePlayer::onVideoEvent() {
1191    Mutex::Autolock autoLock(mLock);
1192    if (!mVideoEventPending) {
1193        // The event has been cancelled in reset_l() but had already
1194        // been scheduled for execution at that time.
1195        return;
1196    }
1197    mVideoEventPending = false;
1198
1199    if (mSeeking) {
1200        if (mVideoBuffer) {
1201            mVideoBuffer->release();
1202            mVideoBuffer = NULL;
1203        }
1204
1205        if (mCachedSource != NULL && mAudioSource != NULL) {
1206            // We're going to seek the video source first, followed by
1207            // the audio source.
1208            // In order to avoid jumps in the DataSource offset caused by
1209            // the audio codec prefetching data from the old locations
1210            // while the video codec is already reading data from the new
1211            // locations, we'll "pause" the audio source, causing it to
1212            // stop reading input data until a subsequent seek.
1213
1214            if (mAudioPlayer != NULL) {
1215                mAudioPlayer->pause();
1216            }
1217            mAudioSource->pause();
1218        }
1219    }
1220
1221    if (!mVideoBuffer) {
1222        MediaSource::ReadOptions options;
1223        if (mSeeking) {
1224            LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1225
1226            options.setSeekTo(
1227                    mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
1228        }
1229        for (;;) {
1230            status_t err = mVideoSource->read(&mVideoBuffer, &options);
1231            options.clearSeekTo();
1232
1233            if (err != OK) {
1234                CHECK(mVideoBuffer == NULL);
1235
1236                if (err == INFO_FORMAT_CHANGED) {
1237                    LOGV("VideoSource signalled format change.");
1238
1239                    notifyVideoSize_l();
1240
1241                    if (mVideoRenderer != NULL) {
1242                        mVideoRendererIsPreview = false;
1243                        initRenderer_l();
1244                    }
1245                    continue;
1246                }
1247
1248                // So video playback is complete, but we may still have
1249                // a seek request pending that needs to be applied
1250                // to the audio track.
1251                if (mSeeking) {
1252                    LOGV("video stream ended while seeking!");
1253                }
1254                finishSeekIfNecessary(-1);
1255
1256                mFlags |= VIDEO_AT_EOS;
1257                postStreamDoneEvent_l(err);
1258                return;
1259            }
1260
1261            if (mVideoBuffer->range_length() == 0) {
1262                // Some decoders, notably the PV AVC software decoder
1263                // return spurious empty buffers that we just want to ignore.
1264
1265                mVideoBuffer->release();
1266                mVideoBuffer = NULL;
1267                continue;
1268            }
1269
1270            break;
1271        }
1272    }
1273
1274    int64_t timeUs;
1275    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1276
1277    {
1278        Mutex::Autolock autoLock(mMiscStateLock);
1279        mVideoTimeUs = timeUs;
1280    }
1281
1282    bool wasSeeking = mSeeking;
1283    finishSeekIfNecessary(timeUs);
1284
1285    TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1286
1287    if (mFlags & FIRST_FRAME) {
1288        mFlags &= ~FIRST_FRAME;
1289        mSinceLastDropped = 0;
1290        mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
1291    }
1292
1293    int64_t realTimeUs, mediaTimeUs;
1294    if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
1295        && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1296        mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1297    }
1298
1299    int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1300
1301    int64_t latenessUs = nowUs - timeUs;
1302
1303    if (wasSeeking) {
1304        // Let's display the first frame after seeking right away.
1305        latenessUs = 0;
1306    }
1307
1308    if (mRTPSession != NULL) {
1309        // We'll completely ignore timestamps for gtalk videochat
1310        // and we'll play incoming video as fast as we get it.
1311        latenessUs = 0;
1312    }
1313
1314    if (latenessUs > 40000) {
1315        // We're more than 40ms late.
1316        LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
1317        if ( mSinceLastDropped > FRAME_DROP_FREQ)
1318        {
1319            LOGV("we're late by %lld us (%.2f secs) dropping one after %d frames", latenessUs, latenessUs / 1E6, mSinceLastDropped);
1320            mSinceLastDropped = 0;
1321            mVideoBuffer->release();
1322            mVideoBuffer = NULL;
1323
1324            postVideoEvent_l();
1325            return;
1326        }
1327    }
1328
1329    if (latenessUs < -10000) {
1330        // We're more than 10ms early.
1331
1332        postVideoEvent_l(10000);
1333        return;
1334    }
1335
1336    if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1337        mVideoRendererIsPreview = false;
1338
1339        initRenderer_l();
1340    }
1341
1342    if (mVideoRenderer != NULL) {
1343        mSinceLastDropped++;
1344        mVideoRenderer->render(mVideoBuffer);
1345    }
1346
1347    mVideoBuffer->release();
1348    mVideoBuffer = NULL;
1349
1350    postVideoEvent_l();
1351}
1352
1353void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1354    if (mVideoEventPending) {
1355        return;
1356    }
1357
1358    mVideoEventPending = true;
1359    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1360}
1361
1362void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
1363    if (mStreamDoneEventPending) {
1364        return;
1365    }
1366    mStreamDoneEventPending = true;
1367
1368    mStreamDoneStatus = status;
1369    mQueue.postEvent(mStreamDoneEvent);
1370}
1371
1372void AwesomePlayer::postBufferingEvent_l() {
1373    if (mBufferingEventPending) {
1374        return;
1375    }
1376    mBufferingEventPending = true;
1377    mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1378}
1379
1380void AwesomePlayer::postVideoLagEvent_l() {
1381    if (mVideoLagEventPending) {
1382        return;
1383    }
1384    mVideoLagEventPending = true;
1385    mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
1386}
1387
1388void AwesomePlayer::postCheckAudioStatusEvent_l() {
1389    if (mAudioStatusEventPending) {
1390        return;
1391    }
1392    mAudioStatusEventPending = true;
1393    mQueue.postEvent(mCheckAudioStatusEvent);
1394}
1395
1396void AwesomePlayer::onCheckAudioStatus() {
1397    Mutex::Autolock autoLock(mLock);
1398    if (!mAudioStatusEventPending) {
1399        // Event was dispatched and while we were blocking on the mutex,
1400        // has already been cancelled.
1401        return;
1402    }
1403
1404    mAudioStatusEventPending = false;
1405
1406    if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1407        mWatchForAudioSeekComplete = false;
1408
1409        if (!mSeekNotificationSent) {
1410            notifyListener_l(MEDIA_SEEK_COMPLETE);
1411            mSeekNotificationSent = true;
1412        }
1413
1414        mSeeking = false;
1415    }
1416
1417    status_t finalStatus;
1418    if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
1419        mWatchForAudioEOS = false;
1420        mFlags |= AUDIO_AT_EOS;
1421        mFlags |= FIRST_FRAME;
1422        postStreamDoneEvent_l(finalStatus);
1423    }
1424}
1425
1426status_t AwesomePlayer::prepare() {
1427    Mutex::Autolock autoLock(mLock);
1428    return prepare_l();
1429}
1430
1431status_t AwesomePlayer::prepare_l() {
1432    if (mFlags & PREPARED) {
1433        return OK;
1434    }
1435
1436    if (mFlags & PREPARING) {
1437        return UNKNOWN_ERROR;
1438    }
1439
1440    mIsAsyncPrepare = false;
1441    status_t err = prepareAsync_l();
1442
1443    if (err != OK) {
1444        return err;
1445    }
1446
1447    while (mFlags & PREPARING) {
1448        mPreparedCondition.wait(mLock);
1449    }
1450
1451    return mPrepareResult;
1452}
1453
1454status_t AwesomePlayer::prepareAsync() {
1455    Mutex::Autolock autoLock(mLock);
1456
1457    if (mFlags & PREPARING) {
1458        return UNKNOWN_ERROR;  // async prepare already pending
1459    }
1460
1461    mIsAsyncPrepare = true;
1462    return prepareAsync_l();
1463}
1464
1465status_t AwesomePlayer::prepareAsync_l() {
1466    if (mFlags & PREPARING) {
1467        return UNKNOWN_ERROR;  // async prepare already pending
1468    }
1469
1470    if (!mQueueStarted) {
1471        mQueue.start();
1472        mQueueStarted = true;
1473    }
1474
1475    mFlags |= PREPARING;
1476    mAsyncPrepareEvent = new AwesomeEvent(
1477            this, &AwesomePlayer::onPrepareAsyncEvent);
1478
1479    mQueue.postEvent(mAsyncPrepareEvent);
1480
1481    return OK;
1482}
1483
1484status_t AwesomePlayer::finishSetDataSource_l() {
1485    sp<DataSource> dataSource;
1486
1487    if (!strncasecmp("http://", mUri.string(), 7)) {
1488        mConnectingDataSource = new NuHTTPDataSource;
1489
1490        mLock.unlock();
1491        status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
1492        mLock.lock();
1493
1494        if (err != OK) {
1495            mConnectingDataSource.clear();
1496
1497            LOGI("mConnectingDataSource->connect() returned %d", err);
1498            return err;
1499        }
1500
1501#if 0
1502        mCachedSource = new NuCachedSource2(
1503                new ThrottledSource(
1504                    mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1505#else
1506        mCachedSource = new NuCachedSource2(mConnectingDataSource);
1507#endif
1508        mConnectingDataSource.clear();
1509
1510        dataSource = mCachedSource;
1511    } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1512        String8 uri("http://");
1513        uri.append(mUri.string() + 11);
1514
1515        if (mLooper == NULL) {
1516            mLooper = new ALooper;
1517            mLooper->setName("httplive");
1518            mLooper->start();
1519        }
1520
1521        mLiveSession = new LiveSession;
1522        mLooper->registerHandler(mLiveSession);
1523
1524        mLiveSession->connect(uri.string());
1525        dataSource = mLiveSession->getDataSource();
1526
1527        sp<MediaExtractor> extractor =
1528            MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
1529
1530        static_cast<MPEG2TSExtractor *>(extractor.get())
1531            ->setLiveSession(mLiveSession);
1532
1533        return setDataSource_l(extractor);
1534    } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
1535        if (mLooper == NULL) {
1536            mLooper = new ALooper;
1537            mLooper->setName("gtalk rtp");
1538            mLooper->start(
1539                    false /* runOnCallingThread */,
1540                    false /* canCallJava */,
1541                    PRIORITY_HIGHEST);
1542        }
1543
1544        const char *startOfCodecString = &mUri.string()[13];
1545        const char *startOfSlash1 = strchr(startOfCodecString, '/');
1546        if (startOfSlash1 == NULL) {
1547            return BAD_VALUE;
1548        }
1549        const char *startOfWidthString = &startOfSlash1[1];
1550        const char *startOfSlash2 = strchr(startOfWidthString, '/');
1551        if (startOfSlash2 == NULL) {
1552            return BAD_VALUE;
1553        }
1554        const char *startOfHeightString = &startOfSlash2[1];
1555
1556        String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1557        String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1558        String8 heightString(startOfHeightString);
1559
1560#if 0
1561        mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1562        mLooper->registerHandler(mRTPPusher);
1563
1564        mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1565        mLooper->registerHandler(mRTCPPusher);
1566#endif
1567
1568        mRTPSession = new ARTPSession;
1569        mLooper->registerHandler(mRTPSession);
1570
1571#if 0
1572        // My AMR SDP
1573        static const char *raw =
1574            "v=0\r\n"
1575            "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1576            "s=QuickTime\r\n"
1577            "t=0 0\r\n"
1578            "a=range:npt=0-315\r\n"
1579            "a=isma-compliance:2,2.0,2\r\n"
1580            "m=audio 5434 RTP/AVP 97\r\n"
1581            "c=IN IP4 127.0.0.1\r\n"
1582            "b=AS:30\r\n"
1583            "a=rtpmap:97 AMR/8000/1\r\n"
1584            "a=fmtp:97 octet-align\r\n";
1585#elif 1
1586        String8 sdp;
1587        sdp.appendFormat(
1588            "v=0\r\n"
1589            "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1590            "s=QuickTime\r\n"
1591            "t=0 0\r\n"
1592            "a=range:npt=0-315\r\n"
1593            "a=isma-compliance:2,2.0,2\r\n"
1594            "m=video 5434 RTP/AVP 97\r\n"
1595            "c=IN IP4 127.0.0.1\r\n"
1596            "b=AS:30\r\n"
1597            "a=rtpmap:97 %s/90000\r\n"
1598            "a=cliprect:0,0,%s,%s\r\n"
1599            "a=framesize:97 %s-%s\r\n",
1600
1601            codecString.string(),
1602            heightString.string(), widthString.string(),
1603            widthString.string(), heightString.string()
1604            );
1605        const char *raw = sdp.string();
1606
1607#endif
1608
1609        sp<ASessionDescription> desc = new ASessionDescription;
1610        CHECK(desc->setTo(raw, strlen(raw)));
1611
1612        CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1613
1614        if (mRTPPusher != NULL) {
1615            mRTPPusher->start();
1616        }
1617
1618        if (mRTCPPusher != NULL) {
1619            mRTCPPusher->start();
1620        }
1621
1622        CHECK_EQ(mRTPSession->countTracks(), 1u);
1623        sp<MediaSource> source = mRTPSession->trackAt(0);
1624
1625#if 0
1626        bool eos;
1627        while (((APacketSource *)source.get())
1628                ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1629            usleep(100000ll);
1630        }
1631#endif
1632
1633        const char *mime;
1634        CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1635
1636        if (!strncasecmp("video/", mime, 6)) {
1637            setVideoSource(source);
1638        } else {
1639            CHECK(!strncasecmp("audio/", mime, 6));
1640            setAudioSource(source);
1641        }
1642
1643        mExtractorFlags = MediaExtractor::CAN_PAUSE;
1644
1645        return OK;
1646    } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1647        if (mLooper == NULL) {
1648            mLooper = new ALooper;
1649            mLooper->setName("rtsp");
1650            mLooper->start();
1651        }
1652        mRTSPController = new ARTSPController(mLooper);
1653        status_t err = mRTSPController->connect(mUri.string());
1654
1655        LOGI("ARTSPController::connect returned %d", err);
1656
1657        if (err != OK) {
1658            mRTSPController.clear();
1659            return err;
1660        }
1661
1662        sp<MediaExtractor> extractor = mRTSPController.get();
1663        return setDataSource_l(extractor);
1664    } else {
1665        dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1666    }
1667
1668    if (dataSource == NULL) {
1669        return UNKNOWN_ERROR;
1670    }
1671
1672    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1673
1674    if (extractor == NULL) {
1675        return UNKNOWN_ERROR;
1676    }
1677
1678    dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
1679    if (mDecryptHandle != NULL) {
1680        if (RightsStatus::RIGHTS_VALID == mDecryptHandle->status) {
1681            if (DecryptApiType::WV_BASED == mDecryptHandle->decryptApiType) {
1682                LOGD("Setting mCachedSource to NULL for WVM\n");
1683                mCachedSource.clear();
1684            }
1685        } else {
1686            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
1687        }
1688    }
1689
1690    return setDataSource_l(extractor);
1691}
1692
1693void AwesomePlayer::abortPrepare(status_t err) {
1694    CHECK(err != OK);
1695
1696    if (mIsAsyncPrepare) {
1697        notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1698    }
1699
1700    mPrepareResult = err;
1701    mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
1702    mAsyncPrepareEvent = NULL;
1703    mPreparedCondition.broadcast();
1704}
1705
1706// static
1707bool AwesomePlayer::ContinuePreparation(void *cookie) {
1708    AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1709
1710    return (me->mFlags & PREPARE_CANCELLED) == 0;
1711}
1712
1713void AwesomePlayer::onPrepareAsyncEvent() {
1714    Mutex::Autolock autoLock(mLock);
1715
1716    if (mFlags & PREPARE_CANCELLED) {
1717        LOGI("prepare was cancelled before doing anything");
1718        abortPrepare(UNKNOWN_ERROR);
1719        return;
1720    }
1721
1722    if (mUri.size() > 0) {
1723        status_t err = finishSetDataSource_l();
1724
1725        if (err != OK) {
1726            abortPrepare(err);
1727            return;
1728        }
1729    }
1730
1731    if (mVideoTrack != NULL && mVideoSource == NULL) {
1732        status_t err = initVideoDecoder();
1733
1734        if (err != OK) {
1735            abortPrepare(err);
1736            return;
1737        }
1738    }
1739
1740    if (mAudioTrack != NULL && mAudioSource == NULL) {
1741        status_t err = initAudioDecoder();
1742
1743        if (err != OK) {
1744            abortPrepare(err);
1745            return;
1746        }
1747    }
1748
1749    mFlags |= PREPARING_CONNECTED;
1750
1751    if (mCachedSource != NULL || mRTSPController != NULL) {
1752        postBufferingEvent_l();
1753    } else {
1754        finishAsyncPrepare_l();
1755    }
1756}
1757
1758void AwesomePlayer::finishAsyncPrepare_l() {
1759    if (mIsAsyncPrepare) {
1760        if (mVideoSource == NULL) {
1761            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1762        } else {
1763            notifyVideoSize_l();
1764        }
1765
1766        notifyListener_l(MEDIA_PREPARED);
1767    }
1768
1769    mPrepareResult = OK;
1770    mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
1771    mFlags |= PREPARED;
1772    mAsyncPrepareEvent = NULL;
1773    mPreparedCondition.broadcast();
1774}
1775
1776uint32_t AwesomePlayer::flags() const {
1777    return mExtractorFlags;
1778}
1779
1780void AwesomePlayer::postAudioEOS() {
1781    postCheckAudioStatusEvent_l();
1782}
1783
1784void AwesomePlayer::postAudioSeekComplete() {
1785    postCheckAudioStatusEvent_l();
1786}
1787
1788}  // namespace android
1789