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