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