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