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