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