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