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