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