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