RTSPSource.cpp revision 1228d6b175de8b21787cbe0c6c4bb5642f4d555e
12bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber/*
22bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber * Copyright (C) 2010 The Android Open Source Project
32bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber *
42bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
52bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber * you may not use this file except in compliance with the License.
62bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber * You may obtain a copy of the License at
72bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber *
82bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
92bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber *
102bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber * Unless required by applicable law or agreed to in writing, software
112bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
122bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber * See the License for the specific language governing permissions and
142bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber * limitations under the License.
152bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber */
162bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
172bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber//#define LOG_NDEBUG 0
182bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber#define LOG_TAG "RTSPSource"
192bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber#include <utils/Log.h>
202bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
212bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber#include "RTSPSource.h"
222bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
232bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber#include "AnotherPacketSource.h"
242bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber#include "MyHandler.h"
2581dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé#include "SDPLoader.h"
262bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
271b86fe063badb5f28c467ade39be0f4008688947Andreas Huber#include <media/IMediaHTTPService.h>
2849694688c82214f5fd9e969e177c9e126a240a26Andreas Huber#include <media/stagefright/MediaDefs.h>
292bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber#include <media/stagefright/MetaData.h>
302bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
312bfdd428c56c7524d1a11979f200a1762866032dAndreas Hubernamespace android {
322bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
33cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönssonconst int64_t kNearEOSTimeoutUs = 2000000ll; // 2 secs
34cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson
352bfdd428c56c7524d1a11979f200a1762866032dAndreas HuberNuPlayer::RTSPSource::RTSPSource(
365ab368af38fefacc4009e3ab1c1bbd00e62b3bcfAndreas Huber        const sp<AMessage> &notify,
371b86fe063badb5f28c467ade39be0f4008688947Andreas Huber        const sp<IMediaHTTPService> &httpService,
382bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        const char *url,
392bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        const KeyedVector<String8, String8> *headers,
402bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        bool uidValid,
4181dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        uid_t uid,
4281dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        bool isSDP)
435ab368af38fefacc4009e3ab1c1bbd00e62b3bcfAndreas Huber    : Source(notify),
441b86fe063badb5f28c467ade39be0f4008688947Andreas Huber      mHTTPService(httpService),
455ab368af38fefacc4009e3ab1c1bbd00e62b3bcfAndreas Huber      mURL(url),
462bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber      mUIDValid(uidValid),
472bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber      mUID(uid),
482bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber      mFlags(0),
4981dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé      mIsSDP(isSDP),
502bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber      mState(DISCONNECTED),
512bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber      mFinalResult(OK),
52ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber      mDisconnectReplyID(0),
53cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson      mBuffering(true),
54cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson      mSeekGeneration(0),
55cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson      mEOSTimeoutAudio(0),
56cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson      mEOSTimeoutVideo(0) {
572bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    if (headers) {
582bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        mExtraHeaders = *headers;
592bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
602bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        ssize_t index =
612bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
622bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
632bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        if (index >= 0) {
642bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            mFlags |= kFlagIncognito;
652bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
662bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            mExtraHeaders.removeItemsAt(index);
672bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        }
682bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
692bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
702bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
712bfdd428c56c7524d1a11979f200a1762866032dAndreas HuberNuPlayer::RTSPSource::~RTSPSource() {
72602f5bbd7596ec3fe447fde4329d5d4f0b370835Andreas Huber    if (mLooper != NULL) {
731228d6b175de8b21787cbe0c6c4bb5642f4d555eChong Zhang        mLooper->unregisterHandler(id());
74602f5bbd7596ec3fe447fde4329d5d4f0b370835Andreas Huber        mLooper->stop();
75602f5bbd7596ec3fe447fde4329d5d4f0b370835Andreas Huber    }
762bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
772bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
7857cea553cb19235553463412db5ad04c99835411Andreas Hubervoid NuPlayer::RTSPSource::prepareAsync() {
792bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    if (mLooper == NULL) {
802bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        mLooper = new ALooper;
812bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        mLooper->setName("rtsp");
822bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        mLooper->start();
832bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
841228d6b175de8b21787cbe0c6c4bb5642f4d555eChong Zhang        mLooper->registerHandler(this);
852bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
862bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
872bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    CHECK(mHandler == NULL);
8881dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    CHECK(mSDPLoader == NULL);
892bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
901228d6b175de8b21787cbe0c6c4bb5642f4d555eChong Zhang    sp<AMessage> notify = new AMessage(kWhatNotify, id());
912bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
922bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    CHECK_EQ(mState, (int)DISCONNECTED);
932bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    mState = CONNECTING;
942bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
9581dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    if (mIsSDP) {
9681dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        mSDPLoader = new SDPLoader(notify,
9781dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé                (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0,
9881e68448f3361eaf8618930471fdc3c21bdf5cbcAndreas Huber                mHTTPService);
9981dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
10057cea553cb19235553463412db5ad04c99835411Andreas Huber        mSDPLoader->load(
10157cea553cb19235553463412db5ad04c99835411Andreas Huber                mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
10281dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    } else {
10381dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
10481dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        mLooper->registerHandler(mHandler);
10581dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
10681dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        mHandler->connect();
10781dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    }
108cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson
109cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    sp<AMessage> notifyStart = dupNotify();
110cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    notifyStart->setInt32("what", kWhatBufferingStart);
111cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    notifyStart->post();
11257cea553cb19235553463412db5ad04c99835411Andreas Huber}
11357cea553cb19235553463412db5ad04c99835411Andreas Huber
11457cea553cb19235553463412db5ad04c99835411Andreas Hubervoid NuPlayer::RTSPSource::start() {
1152bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
1162bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
1172bfdd428c56c7524d1a11979f200a1762866032dAndreas Hubervoid NuPlayer::RTSPSource::stop() {
1185834181d3f168acb8ff4bf3eff1fd1186afb0bd4James Dong    if (mLooper == NULL) {
1195834181d3f168acb8ff4bf3eff1fd1186afb0bd4James Dong        return;
1205834181d3f168acb8ff4bf3eff1fd1186afb0bd4James Dong    }
1211228d6b175de8b21787cbe0c6c4bb5642f4d555eChong Zhang    sp<AMessage> msg = new AMessage(kWhatDisconnect, id());
1222bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
1232bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    sp<AMessage> dummy;
1242bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    msg->postAndAwaitResponse(&dummy);
1252bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
1262bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
12746d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönssonvoid NuPlayer::RTSPSource::pause() {
12846d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson    int64_t mediaDurationUs = 0;
12946d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson    getDuration(&mediaDurationUs);
13046d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson    for (size_t index = 0; index < mTracks.size(); index++) {
13146d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson        TrackInfo *info = &mTracks.editItemAt(index);
13246d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson        sp<AnotherPacketSource> source = info->mSource;
13346d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson
13446d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson        // Check if EOS or ERROR is received
13546d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson        if (source != NULL && source->isFinished(mediaDurationUs)) {
13646d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson            return;
13746d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson        }
13846d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson    }
13946d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson    mHandler->pause();
14046d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson}
14146d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson
14246d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönssonvoid NuPlayer::RTSPSource::resume() {
14346d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson    mHandler->resume();
14446d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson}
14546d13e3606b87d71379287672b54b50d0d9aa5ccRoger Jönsson
1462bfdd428c56c7524d1a11979f200a1762866032dAndreas Huberstatus_t NuPlayer::RTSPSource::feedMoreTSData() {
1472bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    return mFinalResult;
1482bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
1492bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
150840667883fd09d44015716d79bc3ac4d60edc0f0Andreas Hubersp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) {
1512bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    sp<AnotherPacketSource> source = getSource(audio);
1522bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
1532bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    if (source == NULL) {
1542bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        return NULL;
1552bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
1562bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
1572bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    return source->getFormat();
1582bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
1592bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
160bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huberbool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() {
161bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber    // We're going to buffer at least 2 secs worth data on all tracks before
162bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber    // starting playback (both at startup and after a seek).
163bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber
164bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber    static const int64_t kMinDurationUs = 2000000ll;
165bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber
166cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    int64_t mediaDurationUs = 0;
167cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    getDuration(&mediaDurationUs);
168cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    if ((mAudioTrack != NULL && mAudioTrack->isFinished(mediaDurationUs))
169cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            || (mVideoTrack != NULL && mVideoTrack->isFinished(mediaDurationUs))) {
170cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson        return true;
171cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    }
172cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson
173bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber    status_t err;
174bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber    int64_t durationUs;
175bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber    if (mAudioTrack != NULL
176bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber            && (durationUs = mAudioTrack->getBufferedDurationUs(&err))
177bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber                    < kMinDurationUs
178bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber            && err == OK) {
179bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber        ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)",
180bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber              durationUs / 1E6);
181bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber        return false;
182bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber    }
183bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber
184bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber    if (mVideoTrack != NULL
185bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber            && (durationUs = mVideoTrack->getBufferedDurationUs(&err))
186bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber                    < kMinDurationUs
187bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber            && err == OK) {
188bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber        ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)",
189bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber              durationUs / 1E6);
190bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber        return false;
191bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber    }
192bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber
193bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber    return true;
194bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber}
195bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber
1962bfdd428c56c7524d1a11979f200a1762866032dAndreas Huberstatus_t NuPlayer::RTSPSource::dequeueAccessUnit(
1972bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        bool audio, sp<ABuffer> *accessUnit) {
198cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    if (mBuffering) {
199bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber        if (!haveSufficientDataOnAllTracks()) {
200bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber            return -EWOULDBLOCK;
201bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber        }
202bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber
203cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson        mBuffering = false;
204cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson
205cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson        sp<AMessage> notify = dupNotify();
206cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson        notify->setInt32("what", kWhatBufferingEnd);
207cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson        notify->post();
208bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber    }
209bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber
2102bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    sp<AnotherPacketSource> source = getSource(audio);
2112bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
2122bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    if (source == NULL) {
2132bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        return -EWOULDBLOCK;
2142bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
2152bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
2162bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    status_t finalResult;
2172bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    if (!source->hasBufferAvailable(&finalResult)) {
218cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson        if (finalResult == OK) {
219cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            int64_t mediaDurationUs = 0;
220cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            getDuration(&mediaDurationUs);
221cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            sp<AnotherPacketSource> otherSource = getSource(!audio);
222cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            status_t otherFinalResult;
223cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson
224cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            // If other source already signaled EOS, this source should also signal EOS
225cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            if (otherSource != NULL &&
226cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                    !otherSource->hasBufferAvailable(&otherFinalResult) &&
227cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                    otherFinalResult == ERROR_END_OF_STREAM) {
228cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                source->signalEOS(ERROR_END_OF_STREAM);
229cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                return ERROR_END_OF_STREAM;
230cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            }
231cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson
232cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            // If this source has detected near end, give it some time to retrieve more
233cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            // data before signaling EOS
234cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            if (source->isFinished(mediaDurationUs)) {
235cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo;
236cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                if (eosTimeout == 0) {
237cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                    setEOSTimeout(audio, ALooper::GetNowUs());
238cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                } else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) {
239cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                    setEOSTimeout(audio, 0);
240cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                    source->signalEOS(ERROR_END_OF_STREAM);
241cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                    return ERROR_END_OF_STREAM;
242cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                }
243cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                return -EWOULDBLOCK;
244cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            }
245cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson
246cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            if (!(otherSource != NULL && otherSource->isFinished(mediaDurationUs))) {
247cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                // We should not enter buffering mode
248cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                // if any of the sources already have detected EOS.
249cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                mBuffering = true;
250cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson
251cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                sp<AMessage> notify = dupNotify();
252cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                notify->setInt32("what", kWhatBufferingStart);
253cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson                notify->post();
254cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            }
255cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson
256cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson            return -EWOULDBLOCK;
257cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson        }
258cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson        return finalResult;
2592bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
2602bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
261cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    setEOSTimeout(audio, 0);
262cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson
2632bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    return source->dequeueAccessUnit(accessUnit);
2642bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
2652bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
2662bfdd428c56c7524d1a11979f200a1762866032dAndreas Hubersp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
26749694688c82214f5fd9e969e177c9e126a240a26Andreas Huber    if (mTSParser != NULL) {
26849694688c82214f5fd9e969e177c9e126a240a26Andreas Huber        sp<MediaSource> source = mTSParser->getSource(
26949694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                audio ? ATSParser::AUDIO : ATSParser::VIDEO);
27049694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
27149694688c82214f5fd9e969e177c9e126a240a26Andreas Huber        return static_cast<AnotherPacketSource *>(source.get());
27249694688c82214f5fd9e969e177c9e126a240a26Andreas Huber    }
27349694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
2742bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    return audio ? mAudioTrack : mVideoTrack;
2752bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
2762bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
277cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönssonvoid NuPlayer::RTSPSource::setEOSTimeout(bool audio, int64_t timeout) {
278cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    if (audio) {
279cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson        mEOSTimeoutAudio = timeout;
280cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    } else {
281cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson        mEOSTimeoutVideo = timeout;
282cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson    }
283cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson}
284cfc3083927df14bf82403b20a45ae303a01c39f5Roger Jönsson
2852bfdd428c56c7524d1a11979f200a1762866032dAndreas Huberstatus_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
2862bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    *durationUs = 0ll;
2872bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
2882bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    int64_t audioDurationUs;
2892bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    if (mAudioTrack != NULL
2902bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            && mAudioTrack->getFormat()->findInt64(
2912bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                kKeyDuration, &audioDurationUs)
2922bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            && audioDurationUs > *durationUs) {
2932bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        *durationUs = audioDurationUs;
2942bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
2952bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
2962bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    int64_t videoDurationUs;
2972bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    if (mVideoTrack != NULL
2982bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            && mVideoTrack->getFormat()->findInt64(
2992bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                kKeyDuration, &videoDurationUs)
3002bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            && videoDurationUs > *durationUs) {
3012bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        *durationUs = videoDurationUs;
3022bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
3032bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3042bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    return OK;
3052bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
3062bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3072bfdd428c56c7524d1a11979f200a1762866032dAndreas Huberstatus_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
3081228d6b175de8b21787cbe0c6c4bb5642f4d555eChong Zhang    sp<AMessage> msg = new AMessage(kWhatPerformSeek, id());
309ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber    msg->setInt32("generation", ++mSeekGeneration);
310ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber    msg->setInt64("timeUs", seekTimeUs);
311ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber    msg->post(200000ll);
312ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber
313ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber    return OK;
314ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber}
315ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber
316ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Hubervoid NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
3172bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    if (mState != CONNECTED) {
318ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber        return;
3192bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
3202bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3212bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    mState = SEEKING;
3222bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    mHandler->seek(seekTimeUs);
3232bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
3242bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3252bfdd428c56c7524d1a11979f200a1762866032dAndreas Hubervoid NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
3262bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    if (msg->what() == kWhatDisconnect) {
3272bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        uint32_t replyID;
3282bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        CHECK(msg->senderAwaitsResponse(&replyID));
3292bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3302bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        mDisconnectReplyID = replyID;
3312bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        finishDisconnectIfPossible();
3322bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        return;
333ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber    } else if (msg->what() == kWhatPerformSeek) {
334ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber        int32_t generation;
335ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber        CHECK(msg->findInt32("generation", &generation));
336ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber
337ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber        if (generation != mSeekGeneration) {
338ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber            // obsolete.
339ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber            return;
340ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber        }
341ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber
342ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber        int64_t seekTimeUs;
343ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber        CHECK(msg->findInt64("timeUs", &seekTimeUs));
344ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber
345ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber        performSeek(seekTimeUs);
346ee736e9e74c5368db8d63214513c85cb74bb0183Andreas Huber        return;
3472bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
3482bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3492bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    CHECK_EQ(msg->what(), (int)kWhatNotify);
3502bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3512bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    int32_t what;
3522bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    CHECK(msg->findInt32("what", &what));
3532bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3542bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    switch (what) {
3552bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        case MyHandler::kWhatConnected:
3567f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber        {
3572bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            onConnected();
3587f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber
359ced1c2f8f6c422063092f5cc5c675ccdebb2dc10Chong Zhang            notifyVideoSizeChanged();
3607f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber
3617f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber            uint32_t flags = 0;
3627f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber
3637f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber            if (mHandler->isSeekable()) {
3644b7069dac546ad21cf62ca6132d50ea41857d08eChong Zhang                flags = FLAG_CAN_PAUSE
3654b7069dac546ad21cf62ca6132d50ea41857d08eChong Zhang                        | FLAG_CAN_SEEK
3664b7069dac546ad21cf62ca6132d50ea41857d08eChong Zhang                        | FLAG_CAN_SEEK_BACKWARD
3674b7069dac546ad21cf62ca6132d50ea41857d08eChong Zhang                        | FLAG_CAN_SEEK_FORWARD;
3687f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber            }
3697f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber
3707f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber            notifyFlagsChanged(flags);
3717f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber            notifyPrepared();
3722bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            break;
3737f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber        }
3742bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3752bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        case MyHandler::kWhatDisconnected:
3767f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber        {
3772bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            onDisconnected(msg);
3782bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            break;
3797f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber        }
3802bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3812bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        case MyHandler::kWhatSeekDone:
3822bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        {
3832bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            mState = CONNECTED;
3842bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            break;
3852bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        }
3862bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3872bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        case MyHandler::kWhatAccessUnit:
3882bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        {
3892bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            size_t trackIndex;
3902bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            CHECK(msg->findSize("trackIndex", &trackIndex));
39149694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
39249694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            if (mTSParser == NULL) {
39349694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                CHECK_LT(trackIndex, mTracks.size());
39449694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            } else {
39549694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                CHECK_EQ(trackIndex, 0u);
39649694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            }
3972bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
3982d8bedd05437b6fccdbc6bf70f673ffd86744d59Andreas Huber            sp<ABuffer> accessUnit;
3992d8bedd05437b6fccdbc6bf70f673ffd86744d59Andreas Huber            CHECK(msg->findBuffer("accessUnit", &accessUnit));
4002bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
4012bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            int32_t damaged;
4022bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            if (accessUnit->meta()->findInt32("damaged", &damaged)
4032bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                    && damaged) {
404df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                ALOGI("dropping damaged access unit.");
4052bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                break;
4062bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            }
4072bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
40849694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            if (mTSParser != NULL) {
40949694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                size_t offset = 0;
41049694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                status_t err = OK;
41149694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                while (offset + 188 <= accessUnit->size()) {
41249694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    err = mTSParser->feedTSPacket(
41349694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                            accessUnit->data() + offset, 188);
41449694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    if (err != OK) {
41549694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                        break;
41649694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    }
41749694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
41849694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    offset += 188;
41949694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                }
42049694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
42149694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                if (offset < accessUnit->size()) {
42249694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    err = ERROR_MALFORMED;
42349694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                }
42449694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
42549694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                if (err != OK) {
42649694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    sp<AnotherPacketSource> source = getSource(false /* audio */);
42749694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    if (source != NULL) {
42849694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                        source->signalEOS(err);
42949694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    }
43049694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
43149694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    source = getSource(true /* audio */);
43249694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    if (source != NULL) {
43349694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                        source->signalEOS(err);
43449694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    }
43549694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                }
43649694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                break;
43749694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            }
43849694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
4391906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber            TrackInfo *info = &mTracks.editItemAt(trackIndex);
4401906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber
4411906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber            sp<AnotherPacketSource> source = info->mSource;
4422bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            if (source != NULL) {
4432bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                uint32_t rtpTime;
4442bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
4452bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
4461906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                if (!info->mNPTMappingValid) {
4471906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                    // This is a live stream, we didn't receive any normal
448c9d1696d214d2175327067ccc1991bcb36976404Andreas Huber                    // playtime mapping. We won't map to npt time.
449c9d1696d214d2175327067ccc1991bcb36976404Andreas Huber                    source->queueAccessUnit(accessUnit);
450c9d1696d214d2175327067ccc1991bcb36976404Andreas Huber                    break;
4511906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                }
4521906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber
4532bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                int64_t nptUs =
4541906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                    ((double)rtpTime - (double)info->mRTPTime)
4551906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                        / info->mTimeScale
4562bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                        * 1000000ll
4571906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                        + info->mNormalPlaytimeUs;
4582bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
4592bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                accessUnit->meta()->setInt64("timeUs", nptUs);
4602bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
4612bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                source->queueAccessUnit(accessUnit);
4622bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            }
4632bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            break;
4642bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        }
4652bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
4662bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        case MyHandler::kWhatEOS:
4672bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        {
4682bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            int32_t finalResult;
4692bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            CHECK(msg->findInt32("finalResult", &finalResult));
4702bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            CHECK_NE(finalResult, (status_t)OK);
4712bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
47249694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            if (mTSParser != NULL) {
47349694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                sp<AnotherPacketSource> source = getSource(false /* audio */);
47449694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                if (source != NULL) {
47549694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    source->signalEOS(finalResult);
47649694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                }
47749694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
47849694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                source = getSource(true /* audio */);
47949694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                if (source != NULL) {
48049694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                    source->signalEOS(finalResult);
48149694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                }
48249694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
48349694688c82214f5fd9e969e177c9e126a240a26Andreas Huber                return;
48449694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            }
48549694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
48649694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            size_t trackIndex;
48749694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            CHECK(msg->findSize("trackIndex", &trackIndex));
48849694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            CHECK_LT(trackIndex, mTracks.size());
48949694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
4902bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            TrackInfo *info = &mTracks.editItemAt(trackIndex);
4912bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            sp<AnotherPacketSource> source = info->mSource;
4922bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            if (source != NULL) {
4932bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                source->signalEOS(finalResult);
4942bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            }
4952bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
4962bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            break;
4972bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        }
4982bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
4992bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        case MyHandler::kWhatSeekDiscontinuity:
5002bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        {
5012bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            size_t trackIndex;
5022bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            CHECK(msg->findSize("trackIndex", &trackIndex));
5032bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            CHECK_LT(trackIndex, mTracks.size());
5042bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5052bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            TrackInfo *info = &mTracks.editItemAt(trackIndex);
5062bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            sp<AnotherPacketSource> source = info->mSource;
5072bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            if (source != NULL) {
508632740c58119a132ce19f6d498e39c5c3773971aChong Zhang                source->queueDiscontinuity(
509632740c58119a132ce19f6d498e39c5c3773971aChong Zhang                        ATSParser::DISCONTINUITY_SEEK,
510632740c58119a132ce19f6d498e39c5c3773971aChong Zhang                        NULL,
511632740c58119a132ce19f6d498e39c5c3773971aChong Zhang                        true /* discard */);
5122bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            }
5132bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5142bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            break;
5152bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        }
5162bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5172bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        case MyHandler::kWhatNormalPlayTimeMapping:
5182bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        {
5192bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            size_t trackIndex;
5202bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            CHECK(msg->findSize("trackIndex", &trackIndex));
5212bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            CHECK_LT(trackIndex, mTracks.size());
5222bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5232bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            uint32_t rtpTime;
5242bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
5252bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5262bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            int64_t nptUs;
5272bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            CHECK(msg->findInt64("nptUs", &nptUs));
5282bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5292bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            TrackInfo *info = &mTracks.editItemAt(trackIndex);
5302bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            info->mRTPTime = rtpTime;
5312bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            info->mNormalPlaytimeUs = nptUs;
5321906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber            info->mNPTMappingValid = true;
5332bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            break;
5342bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        }
5352bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
53681dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        case SDPLoader::kWhatSDPLoaded:
53781dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        {
53881dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé            onSDPLoaded(msg);
53981dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé            break;
54081dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        }
54181dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
5422bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        default:
5432bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            TRESPASS();
5442bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
5452bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
5462bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5472bfdd428c56c7524d1a11979f200a1762866032dAndreas Hubervoid NuPlayer::RTSPSource::onConnected() {
5482bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    CHECK(mAudioTrack == NULL);
5492bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    CHECK(mVideoTrack == NULL);
5502bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5512bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    size_t numTracks = mHandler->countTracks();
5522bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    for (size_t i = 0; i < numTracks; ++i) {
5532bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        int32_t timeScale;
5542bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
5552bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5562bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        const char *mime;
5572bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        CHECK(format->findCString(kKeyMIMEType, &mime));
5582bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
55949694688c82214f5fd9e969e177c9e126a240a26Andreas Huber        if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
56049694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            // Very special case for MPEG2 Transport Streams.
56149694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            CHECK_EQ(numTracks, 1u);
56249694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
56349694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            mTSParser = new ATSParser;
56449694688c82214f5fd9e969e177c9e126a240a26Andreas Huber            return;
56549694688c82214f5fd9e969e177c9e126a240a26Andreas Huber        }
56649694688c82214f5fd9e969e177c9e126a240a26Andreas Huber
5672bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        bool isAudio = !strncasecmp(mime, "audio/", 6);
5682bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        bool isVideo = !strncasecmp(mime, "video/", 6);
5692bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5702bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        TrackInfo info;
5712bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        info.mTimeScale = timeScale;
5722bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        info.mRTPTime = 0;
5732bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        info.mNormalPlaytimeUs = 0ll;
5741906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber        info.mNPTMappingValid = false;
5752bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5762bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        if ((isAudio && mAudioTrack == NULL)
5772bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                || (isVideo && mVideoTrack == NULL)) {
5782bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            sp<AnotherPacketSource> source = new AnotherPacketSource(format);
5792bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5802bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            if (isAudio) {
5812bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                mAudioTrack = source;
5822bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            } else {
5832bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                mVideoTrack = source;
5842bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            }
5852bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5862bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            info.mSource = source;
5872bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        }
5882bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5892bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        mTracks.push(info);
5902bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
5912bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
5922bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    mState = CONNECTED;
5932bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
5942bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
59581dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhévoid NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) {
59681dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    status_t err;
59781dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    CHECK(msg->findInt32("result", &err));
59881dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
59981dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    mSDPLoader.clear();
60081dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
60181dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    if (mDisconnectReplyID != 0) {
60281dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        err = UNKNOWN_ERROR;
60381dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    }
60481dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
60581dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    if (err == OK) {
60681dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        sp<ASessionDescription> desc;
60781dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        sp<RefBase> obj;
60881dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        CHECK(msg->findObject("description", &obj));
60981dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        desc = static_cast<ASessionDescription *>(obj.get());
61081dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
61181dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        AString rtspUri;
61281dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        if (!desc->findAttribute(0, "a=control", &rtspUri)) {
61381dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé            ALOGE("Unable to find url in SDP");
61481dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé            err = UNKNOWN_ERROR;
61581dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        } else {
6161228d6b175de8b21787cbe0c6c4bb5642f4d555eChong Zhang            sp<AMessage> notify = new AMessage(kWhatNotify, id());
61781dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
61881dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé            mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID);
61981dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé            mLooper->registerHandler(mHandler);
62081dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
62181dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé            mHandler->loadSDP(desc);
62281dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        }
62381dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    }
62481dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
62581dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    if (err != OK) {
6267f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber        if (mState == CONNECTING) {
6277f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber            // We're still in the preparation phase, signal that it
6287f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber            // failed.
6297f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber            notifyPrepared(err);
6307f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber        }
6317f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber
63281dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        mState = DISCONNECTED;
63381dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        mFinalResult = err;
63481dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
63581dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        if (mDisconnectReplyID != 0) {
63681dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé            finishDisconnectIfPossible();
63781dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        }
63881dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé    }
63981dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé}
64081dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé
6412bfdd428c56c7524d1a11979f200a1762866032dAndreas Hubervoid NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
6420ad03bc59d090a0455f858d2f629834c105f6f37Fredrik Rosin    if (mState == DISCONNECTED) {
6430ad03bc59d090a0455f858d2f629834c105f6f37Fredrik Rosin        return;
6440ad03bc59d090a0455f858d2f629834c105f6f37Fredrik Rosin    }
6450ad03bc59d090a0455f858d2f629834c105f6f37Fredrik Rosin
6462bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    status_t err;
6472bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    CHECK(msg->findInt32("result", &err));
6482bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    CHECK_NE(err, (status_t)OK);
6492bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
6502bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    mLooper->unregisterHandler(mHandler->id());
6512bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    mHandler.clear();
6522bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
6537f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber    if (mState == CONNECTING) {
6547f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber        // We're still in the preparation phase, signal that it
6557f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber        // failed.
6567f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber        notifyPrepared(err);
6577f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber    }
6587f475c34ffc8e35345f2cceee2ef56a50bb5fea6Andreas Huber
6592bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    mState = DISCONNECTED;
6602bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    mFinalResult = err;
6612bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
6622bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    if (mDisconnectReplyID != 0) {
6632bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        finishDisconnectIfPossible();
6642bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
6652bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
6662bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
6672bfdd428c56c7524d1a11979f200a1762866032dAndreas Hubervoid NuPlayer::RTSPSource::finishDisconnectIfPossible() {
6682bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    if (mState != DISCONNECTED) {
66981dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        if (mHandler != NULL) {
67081dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé            mHandler->disconnect();
67181dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        } else if (mSDPLoader != NULL) {
67281dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé            mSDPLoader->cancel();
67381dd60e0340ddcf7f1d5fb80b6c30906fabf201aOscar Rydhé        }
6742bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        return;
6752bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
6762bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
6772bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    (new AMessage)->postReply(mDisconnectReplyID);
6782bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    mDisconnectReplyID = 0;
6792bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}
6802bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
6812bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber}  // namespace android
682