MyHandler.h revision dab718bba3945332dc75e268e1e7f0fe2eb91c4a
1cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber/*
2cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * Copyright (C) 2010 The Android Open Source Project
3cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber *
4cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * you may not use this file except in compliance with the License.
6cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * You may obtain a copy of the License at
7cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber *
8cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
9cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber *
10cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * Unless required by applicable law or agreed to in writing, software
11cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * See the License for the specific language governing permissions and
14cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * limitations under the License.
15cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber */
16cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
17cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#ifndef MY_HANDLER_H_
18cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
19cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#define MY_HANDLER_H_
20cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
216e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber//#define LOG_NDEBUG 0
226e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber#define LOG_TAG "MyHandler"
236e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber#include <utils/Log.h>
246e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber
25cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include "APacketSource.h"
26cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include "ARTPConnection.h"
27cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include "ARTSPConnection.h"
28cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include "ASessionDescription.h"
29cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
308d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber#include <ctype.h>
312bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#include <cutils/properties.h>
328d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
33cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/foundation/ABuffer.h>
34cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/foundation/ADebug.h>
35cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/foundation/ALooper.h>
36cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/foundation/AMessage.h>
37cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/MediaErrors.h>
38cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
392bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#include <arpa/inet.h>
402bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#include <sys/socket.h>
41de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber#include <netdb.h>
422bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
43dab718bba3945332dc75e268e1e7f0fe2eb91c4aAndreas Huber#include "HTTPBase.h"
449b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber
45100a4408968b90e314526185d572c72ea4cc784aAndreas Huber// If no access units are received within 5 secs, assume that the rtp
46e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber// stream has ended and signal end of stream.
47100a4408968b90e314526185d572c72ea4cc784aAndreas Huberstatic int64_t kAccessUnitTimeoutUs = 5000000ll;
48e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber
49e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber// If no access units arrive for the first 10 secs after starting the
50e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber// stream, assume none ever will and signal EOS or switch transports.
51e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huberstatic int64_t kStartupTimeoutUs = 10000000ll;
52e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber
53cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Hubernamespace android {
54cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
552bc940b4f961e588459c83862b2c6bea314a4027Andreas Huberstatic void MakeUserAgentString(AString *s) {
562bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    s->setTo("stagefright/1.1 (Linux;Android ");
572bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
582bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#if (PROPERTY_VALUE_MAX < 8)
592bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#error "PROPERTY_VALUE_MAX must be at least 8"
602bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#endif
612bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
622bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    char value[PROPERTY_VALUE_MAX];
632bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    property_get("ro.build.version.release", value, "Unknown");
642bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    s->append(value);
652bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    s->append(")");
662bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber}
672bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
688d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huberstatic bool GetAttribute(const char *s, const char *key, AString *value) {
698d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    value->clear();
708d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
718d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    size_t keyLen = strlen(key);
728d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
738d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    for (;;) {
748d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        while (isspace(*s)) {
758d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            ++s;
768d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
778d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
788d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        const char *colonPos = strchr(s, ';');
798d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
808d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        size_t len =
818d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            (colonPos == NULL) ? strlen(s) : colonPos - s;
828d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
838d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
848d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            value->setTo(&s[keyLen + 1], len - keyLen - 1);
858d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            return true;
868d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
878d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
888d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        if (colonPos == NULL) {
898d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            return false;
908d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
918d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
928d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        s = colonPos + 1;
938d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    }
948d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber}
958d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
96cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huberstruct MyHandler : public AHandler {
979b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber    MyHandler(
989b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber            const char *url, const sp<ALooper> &looper,
999b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber            bool uidValid = false, uid_t uid = 0)
1009b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber        : mUIDValid(uidValid),
1019b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber          mUID(uid),
1029b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber          mLooper(looper),
103348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber          mNetLooper(new ALooper),
1049b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber          mConn(new ARTSPConnection(mUIDValid, mUID)),
105cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mRTPConn(new ARTPConnection),
1064579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber          mOriginalSessionURL(url),
107cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mSessionURL(url),
108cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber          mSetupTracksSuccessful(false),
109cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber          mSeekPending(false),
110cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber          mFirstAccessUnit(true),
111100a4408968b90e314526185d572c72ea4cc784aAndreas Huber          mNTPAnchorUs(-1),
112100a4408968b90e314526185d572c72ea4cc784aAndreas Huber          mMediaAnchorUs(-1),
113100a4408968b90e314526185d572c72ea4cc784aAndreas Huber          mLastMediaTimeUs(0),
1148d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber          mNumAccessUnitsReceived(0),
1157aef03379179c109c2547c33c410bfc93c8db576Andreas Huber          mCheckPending(false),
116a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber          mCheckGeneration(0),
117e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber          mTryTCPInterleaving(false),
118f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber          mTryFakeRTCP(false),
1190dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber          mReceivedFirstRTCPPacket(false),
120f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber          mReceivedFirstRTPPacket(false),
1210dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber          mSeekable(false) {
122a814c1fdc2acf0ed2ee3b175110f6039be7c4873Andreas Huber        mNetLooper->setName("rtsp net");
123348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber        mNetLooper->start(false /* runOnCallingThread */,
124348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                          false /* canCallJava */,
125348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                          PRIORITY_HIGHEST);
1264579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber
1274579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        // Strip any authentication info from the session url, we don't
1284579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        // want to transmit user/pass in cleartext.
1294579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        AString host, path, user, pass;
1304579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        unsigned port;
131de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        CHECK(ARTSPConnection::ParseURL(
132de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                    mSessionURL.c_str(), &host, &port, &path, &user, &pass));
133de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
134de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        if (user.size() > 0) {
1354579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.clear();
1364579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.append("rtsp://");
1374579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.append(host);
1384579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.append(":");
1394579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.append(StringPrintf("%u", port));
1404579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.append(path);
1414579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber
1424579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            LOGI("rewritten session url: '%s'", mSessionURL.c_str());
1434579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        }
144de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
145de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        mSessionHost = host;
146348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber    }
147348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber
1481b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber    void connect(const sp<AMessage> &doneMsg) {
1491b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber        mDoneMsg = doneMsg;
1501b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber
151cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mLooper->registerHandler(this);
152cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mLooper->registerHandler(mConn);
153348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber        (1 ? mNetLooper : mLooper)->registerHandler(mRTPConn);
154348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber
1550792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber        sp<AMessage> notify = new AMessage('biny', id());
1560792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber        mConn->observeBinaryData(notify);
1570792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
1581b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber        sp<AMessage> reply = new AMessage('conn', id());
1594579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        mConn->connect(mOriginalSessionURL.c_str(), reply);
160cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
161cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1621b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber    void disconnect(const sp<AMessage> &doneMsg) {
1631b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber        mDoneMsg = doneMsg;
1641b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber
1651b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber        (new AMessage('abor', id()))->post();
166348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber    }
167348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber
1680dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber    void seek(int64_t timeUs, const sp<AMessage> &doneMsg) {
169cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber        sp<AMessage> msg = new AMessage('seek', id());
170cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber        msg->setInt64("time", timeUs);
1710dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber        msg->setMessage("doneMsg", doneMsg);
172cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber        msg->post();
173cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber    }
174cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
1758d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    int64_t getNormalPlayTimeUs() {
1768d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        int64_t maxTimeUs = 0;
1778d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        for (size_t i = 0; i < mTracks.size(); ++i) {
1788d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            int64_t timeUs = mTracks.editItemAt(i).mPacketSource
1798d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                ->getNormalPlayTimeUs();
1808d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
1818d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            if (i == 0 || timeUs > maxTimeUs) {
1828d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                maxTimeUs = timeUs;
1838d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            }
1848d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
1858d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
1868d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        return maxTimeUs;
1878d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    }
1888d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
1892bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    static void addRR(const sp<ABuffer> &buf) {
1902bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        uint8_t *ptr = buf->data() + buf->size();
1912bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[0] = 0x80 | 0;
1922bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[1] = 201;  // RR
1932bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[2] = 0;
1942bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[3] = 1;
1952bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[4] = 0xde;  // SSRC
1962bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[5] = 0xad;
1972bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[6] = 0xbe;
1982bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[7] = 0xef;
1992bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2002bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        buf->setRange(0, buf->size() + 8);
2012bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    }
2022bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2032bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    static void addSDES(int s, const sp<ABuffer> &buffer) {
2042bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        struct sockaddr_in addr;
2052bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        socklen_t addrSize = sizeof(addr);
2062bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        CHECK_EQ(0, getsockname(s, (sockaddr *)&addr, &addrSize));
2072bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2082bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        uint8_t *data = buffer->data() + buffer->size();
2092bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[0] = 0x80 | 1;
2102bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[1] = 202;  // SDES
2112bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[4] = 0xde;  // SSRC
2122bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[5] = 0xad;
2132bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[6] = 0xbe;
2142bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[7] = 0xef;
2152bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2162bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        size_t offset = 8;
2172bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2182bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = 1;  // CNAME
2192bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2202bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString cname = "stagefright@";
2212bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        cname.append(inet_ntoa(addr.sin_addr));
2222bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = cname.size();
2232bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2242bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        memcpy(&data[offset], cname.c_str(), cname.size());
2252bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        offset += cname.size();
2262bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2272bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = 6;  // TOOL
2282bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2292bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString tool;
2302bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        MakeUserAgentString(&tool);
2312bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2322bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = tool.size();
2332bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2342bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        memcpy(&data[offset], tool.c_str(), tool.size());
2352bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        offset += tool.size();
2362bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2372bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = 0;
2382bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2392bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if ((offset % 4) > 0) {
2402bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            size_t count = 4 - (offset % 4);
2412bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            switch (count) {
2422bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                case 3:
2432bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                    data[offset++] = 0;
2442bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                case 2:
2452bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                    data[offset++] = 0;
2462bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                case 1:
2472bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                    data[offset++] = 0;
2482bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            }
2492bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
2502bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2512bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        size_t numWords = (offset / 4) - 1;
2522bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[2] = numWords >> 8;
2532bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[3] = numWords & 0xff;
2542bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2552bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        buffer->setRange(buffer->offset(), buffer->size() + offset);
2562bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    }
2572bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2582bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    // In case we're behind NAT, fire off two UDP packets to the remote
2592bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    // rtp/rtcp ports to poke a hole into the firewall for future incoming
2602bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    // packets. We're going to send an RR/SDES RTCP packet to both of them.
261dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber    bool pokeAHole(int rtpSocket, int rtcpSocket, const AString &transport) {
262de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        struct sockaddr_in addr;
263de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
264de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        addr.sin_family = AF_INET;
265de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
2662bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString source;
2672bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString server_port;
2682bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if (!GetAttribute(transport.c_str(),
2692bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                          "source",
270de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                          &source)) {
271de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            LOGW("Missing 'source' field in Transport response. Using "
272de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                 "RTSP endpoint address.");
273de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
274de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            struct hostent *ent = gethostbyname(mSessionHost.c_str());
275de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            if (ent == NULL) {
276de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                LOGE("Failed to look up address of session host '%s'",
277de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                     mSessionHost.c_str());
278de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
279de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                return false;
280de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            }
281de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
282de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
283de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        } else {
284de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            addr.sin_addr.s_addr = inet_addr(source.c_str());
285de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        }
286de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
287de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        if (!GetAttribute(transport.c_str(),
2882bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                                 "server_port",
2892bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                                 &server_port)) {
290de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            LOGI("Missing 'server_port' field in Transport response.");
291dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return false;
2922bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
2932bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2942bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        int rtpPort, rtcpPort;
2952bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if (sscanf(server_port.c_str(), "%d-%d", &rtpPort, &rtcpPort) != 2
2962bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                || rtpPort <= 0 || rtpPort > 65535
2972bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                || rtcpPort <=0 || rtcpPort > 65535
298dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                || rtcpPort != rtpPort + 1) {
299dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            LOGE("Server picked invalid RTP/RTCP port pair %s,"
300dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                 " RTP port must be even, RTCP port must be one higher.",
301dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                 server_port.c_str());
302dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
303dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return false;
304dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        }
305dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
306dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        if (rtpPort & 1) {
307dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            LOGW("Server picked an odd RTP port, it should've picked an "
308dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                 "even one, we'll let it pass for now, but this may break "
309dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                 "in the future.");
3102bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
3112bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3122bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if (addr.sin_addr.s_addr == INADDR_NONE) {
313dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return true;
314dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        }
315dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
316dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        if (IN_LOOPBACK(ntohl(addr.sin_addr.s_addr))) {
317dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            // No firewalls to traverse on the loopback interface.
318dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return true;
3192bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
3202bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3212bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        // Make up an RR/SDES RTCP packet.
3222bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        sp<ABuffer> buf = new ABuffer(65536);
3232bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        buf->setRange(0, 0);
3242bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addRR(buf);
3252bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addSDES(rtpSocket, buf);
3262bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3272bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addr.sin_port = htons(rtpPort);
3282bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3292bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ssize_t n = sendto(
3302bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                rtpSocket, buf->data(), buf->size(), 0,
3312bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                (const sockaddr *)&addr, sizeof(addr));
332dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
333dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        if (n < (ssize_t)buf->size()) {
334dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            LOGE("failed to poke a hole for RTP packets");
335dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return false;
336dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        }
3372bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3382bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addr.sin_port = htons(rtcpPort);
3392bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3402bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        n = sendto(
3412bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                rtcpSocket, buf->data(), buf->size(), 0,
3422bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                (const sockaddr *)&addr, sizeof(addr));
343dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
344dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        if (n < (ssize_t)buf->size()) {
345dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            LOGE("failed to poke a hole for RTCP packets");
346dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return false;
347dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        }
3482bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3492bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        LOGV("successfully poked holes.");
350dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
351dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        return true;
3522bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    }
3532bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
354cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    virtual void onMessageReceived(const sp<AMessage> &msg) {
355cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        switch (msg->what()) {
356cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'conn':
357cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
358cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
359cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
360cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
3616e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("connection request completed with result %d (%s)",
3626e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
363cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
364cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
365cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    AString request;
366cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request = "DESCRIBE ";
367cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(mSessionURL);
368cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(" RTSP/1.0\r\n");
369cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("Accept: application/sdp\r\n");
370cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("\r\n");
371cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
372cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('desc', id());
373cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->sendRequest(request.c_str(), reply);
3740792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                } else {
3750792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                    (new AMessage('disc', id()))->post();
376cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
377cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
378cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
379cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
380cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'disc':
381cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
3827aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                int32_t reconnect;
3837aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
3847aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    sp<AMessage> reply = new AMessage('conn', id());
3854579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber                    mConn->connect(mOriginalSessionURL.c_str(), reply);
3867aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                } else {
3877aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    (new AMessage('quit', id()))->post();
3887aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
389cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
390cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
391cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
392cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'desc':
393cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
394cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
395cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
396cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
3976e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("DESCRIBE completed with result %d (%s)",
3986e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
399cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
400cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
401cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<RefBase> obj;
402cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(msg->findObject("response", &obj));
403cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<ARTSPResponse> response =
404cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
405cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
406cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    if (response->mStatusCode == 302) {
407cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        ssize_t i = response->mHeaders.indexOfKey("location");
408cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        CHECK_GE(i, 0);
409cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
410cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        mSessionURL = response->mHeaders.valueAt(i);
411cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
412cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        AString request;
413cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request = "DESCRIBE ";
414cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append(mSessionURL);
415cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append(" RTSP/1.0\r\n");
416cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append("Accept: application/sdp\r\n");
417cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append("\r\n");
418cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
419cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        sp<AMessage> reply = new AMessage('desc', id());
420cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        mConn->sendRequest(request.c_str(), reply);
421cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        break;
422cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    }
423cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
424e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    if (response->mStatusCode != 200) {
425e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        result = UNKNOWN_ERROR;
426e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    } else {
427e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        mSessionDesc = new ASessionDescription;
428cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
429e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        mSessionDesc->setTo(
430e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                response->mContent->data(),
431e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                response->mContent->size());
432cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
4336f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        if (!mSessionDesc->isValid()) {
434dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                            LOGE("Failed to parse session description.");
4356f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                            result = ERROR_MALFORMED;
436cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        } else {
4376f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                            ssize_t i = response->mHeaders.indexOfKey("content-base");
438e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            if (i >= 0) {
439e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                mBaseURL = response->mHeaders.valueAt(i);
440e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            } else {
4416f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                i = response->mHeaders.indexOfKey("content-location");
4426f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                if (i >= 0) {
4436f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                    mBaseURL = response->mHeaders.valueAt(i);
4446f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                } else {
4456f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                    mBaseURL = mSessionURL;
4466f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                }
447e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            }
448e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
449dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                            if (!mBaseURL.startsWith("rtsp://")) {
450dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                // Some misbehaving servers specify a relative
451dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                // URL in one of the locations above, combine
452dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                // it with the absolute session URL to get
453dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                // something usable...
454dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
455dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                LOGW("Server specified a non-absolute base URL"
456dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                     ", combining it with the session URL to "
457dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                     "get something usable...");
458dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
459dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                AString tmp;
460dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                CHECK(MakeURL(
461dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                            mSessionURL.c_str(),
462dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                            mBaseURL.c_str(),
463dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                            &tmp));
464dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
465dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                mBaseURL = tmp;
466dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                            }
467dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
4686f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                            CHECK_GT(mSessionDesc->countTracks(), 1u);
4696f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                            setupTrack(1);
4706f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        }
471cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    }
472e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                }
473cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
474e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (result != OK) {
475cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
476cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->disconnect(reply);
477cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
478cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
479cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
480cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
481cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'setu':
482cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
483cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                size_t index;
484cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findSize("index", &index));
485cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
48639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                TrackInfo *track = NULL;
487cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                size_t trackIndex;
48839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                if (msg->findSize("track-index", &trackIndex)) {
48939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                    track = &mTracks.editItemAt(trackIndex);
49039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                }
491cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
492cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
493cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
494cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
4956e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("SETUP(%d) completed with result %d (%s)",
4966e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     index, result, strerror(-result));
497cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
498e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (result == OK) {
49939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                    CHECK(track != NULL);
500cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
501cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<RefBase> obj;
502cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(msg->findObject("response", &obj));
503cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<ARTSPResponse> response =
504cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
505cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
506e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    if (response->mStatusCode != 200) {
507e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        result = UNKNOWN_ERROR;
508e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    } else {
509e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        ssize_t i = response->mHeaders.indexOfKey("session");
510e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        CHECK_GE(i, 0);
511cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
512cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        mSessionID = response->mHeaders.valueAt(i);
513cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        i = mSessionID.find(";");
514cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        if (i >= 0) {
515cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                            // Remove options, i.e. ";timeout=90"
516cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                            mSessionID.erase(i, mSessionID.size() - i);
517cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        }
518cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
519e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        sp<AMessage> notify = new AMessage('accu', id());
520e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        notify->setSize("track-index", trackIndex);
521cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
5222bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        i = response->mHeaders.indexOfKey("transport");
5232bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        CHECK_GE(i, 0);
5242bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
5252bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        if (!track->mUsingInterleavedTCP) {
5262bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                            AString transport = response->mHeaders.valueAt(i);
5272bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
528de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                            // We are going to continue even if we were
529de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                            // unable to poke a hole into the firewall...
530de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                            pokeAHole(
531de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                    track->mRTPSocket,
532de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                    track->mRTCPSocket,
533de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                    transport);
5342bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        }
5352bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
536de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                        mRTPConn->addStream(
537de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                track->mRTPSocket, track->mRTCPSocket,
538de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                mSessionDesc, index,
539de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                notify, track->mUsingInterleavedTCP);
540cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
541de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                        mSetupTracksSuccessful = true;
542e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    }
543e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                }
544e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
545e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (result != OK) {
546e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    if (track) {
547e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        if (!track->mUsingInterleavedTCP) {
548e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            close(track->mRTPSocket);
549e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            close(track->mRTCPSocket);
550e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        }
551e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
552e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        mTracks.removeItemsAt(trackIndex);
553e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    }
554cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
555cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
55639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                ++index;
55739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                if (index < mSessionDesc->countTracks()) {
55839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                    setupTrack(index);
55939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                } else if (mSetupTracksSuccessful) {
560cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    AString request = "PLAY ";
561cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(mSessionURL);
562cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(" RTSP/1.0\r\n");
563cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
564cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("Session: ");
565cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(mSessionID);
566cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("\r\n");
567cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
568cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("\r\n");
569cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
570cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('play', id());
571cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->sendRequest(request.c_str(), reply);
572cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                } else {
573cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
574cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->disconnect(reply);
575cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
576cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
577cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
578cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
579cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'play':
580cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
581cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
582cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
583cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
5846e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("PLAY completed with result %d (%s)",
5856e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
586cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
587cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
588cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<RefBase> obj;
589cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(msg->findObject("response", &obj));
590cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<ARTSPResponse> response =
591cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
592cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
5936f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    if (response->mStatusCode != 200) {
5946f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        result = UNKNOWN_ERROR;
5956f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    } else {
5966f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        parsePlayResponse(response);
597cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
5986f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        sp<AMessage> timeout = new AMessage('tiou', id());
5996f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        timeout->post(kStartupTimeoutUs);
6006f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    }
6016f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
6028d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
6036f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (result != OK) {
604cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
605cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->disconnect(reply);
606cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
607cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
608cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
609cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
610cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
611cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'abor':
612cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
613cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
6147aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    TrackInfo *info = &mTracks.editItemAt(i);
6157aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
6167aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    info->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
6177aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
6187aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    if (!info->mUsingInterleavedTCP) {
6197aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket);
6207aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
6217aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        close(info->mRTPSocket);
6227aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        close(info->mRTCPSocket);
6237aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    }
624cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
6257aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                mTracks.clear();
626e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mSetupTracksSuccessful = false;
627e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mSeekPending = false;
628e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mFirstAccessUnit = true;
629100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                mNTPAnchorUs = -1;
630100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                mMediaAnchorUs = -1;
631e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mNumAccessUnitsReceived = 0;
632e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mReceivedFirstRTCPPacket = false;
633f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                mReceivedFirstRTPPacket = false;
6340dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                mSeekable = false;
635cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
636cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<AMessage> reply = new AMessage('tear', id());
637cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
6387aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                int32_t reconnect;
6397aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
6407aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    reply->setInt32("reconnect", true);
6417aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
6427aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
643cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                AString request;
644cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request = "TEARDOWN ";
645cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
646cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                // XXX should use aggregate url from SDP here...
647cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mSessionURL);
648cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(" RTSP/1.0\r\n");
649cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
650cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("Session: ");
651cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mSessionID);
652cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
653cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
654cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
655cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
656cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConn->sendRequest(request.c_str(), reply);
657cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
658cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
659cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
660cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'tear':
661cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
662cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
663cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
664cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
6656e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("TEARDOWN completed with result %d (%s)",
6666e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
667cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
668cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<AMessage> reply = new AMessage('disc', id());
6697aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
6707aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                int32_t reconnect;
6717aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
6727aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    reply->setInt32("reconnect", true);
6737aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
6747aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
675cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConn->disconnect(reply);
676cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
677cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
678cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
679cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'quit':
680cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
6811b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber                if (mDoneMsg != NULL) {
6821b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber                    mDoneMsg->setInt32("result", UNKNOWN_ERROR);
6831b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber                    mDoneMsg->post();
6841b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber                    mDoneMsg = NULL;
6851b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber                }
686cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
687cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
688cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
6898d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            case 'chek':
6908d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            {
691a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                int32_t generation;
692a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                CHECK(msg->findInt32("generation", &generation));
693a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                if (generation != mCheckGeneration) {
694a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                    // This is an outdated message. Ignore.
695a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                    break;
696a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                }
697a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
6988d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                if (mNumAccessUnitsReceived == 0) {
6996e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGI("stream ended? aborting.");
7008d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    (new AMessage('abor', id()))->post();
7018d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    break;
7028d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
7038d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
7048d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                mNumAccessUnitsReceived = 0;
705e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber                msg->post(kAccessUnitTimeoutUs);
7068d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                break;
7078d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            }
7088d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
709cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'accu':
710cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
711100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                int32_t timeUpdate;
712100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                if (msg->findInt32("time-update", &timeUpdate) && timeUpdate) {
713100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    size_t trackIndex;
714100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    CHECK(msg->findSize("track-index", &trackIndex));
715100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
716100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    uint32_t rtpTime;
717100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    uint64_t ntpTime;
718100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    CHECK(msg->findInt32("rtp-time", (int32_t *)&rtpTime));
719100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    CHECK(msg->findInt64("ntp-time", (int64_t *)&ntpTime));
720100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
721100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    onTimeUpdate(trackIndex, rtpTime, ntpTime);
722100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    break;
723100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                }
724100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
725f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                int32_t first;
726f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                if (msg->findInt32("first-rtcp", &first)) {
727e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    mReceivedFirstRTCPPacket = true;
728e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    break;
729e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                }
730e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
731f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                if (msg->findInt32("first-rtp", &first)) {
732f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                    mReceivedFirstRTPPacket = true;
733f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                    break;
734f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                }
735f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber
7368d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                ++mNumAccessUnitsReceived;
737a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                postAccessUnitTimeoutCheck();
7388d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
739cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                size_t trackIndex;
740cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findSize("track-index", &trackIndex));
741cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
7427aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (trackIndex >= mTracks.size()) {
7436e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGV("late packets ignored.");
7447aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    break;
7457aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
7467aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
7478d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                TrackInfo *track = &mTracks.editItemAt(trackIndex);
7488d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
749ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                int32_t eos;
750ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                if (msg->findInt32("eos", &eos)) {
7516e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGI("received BYE on track index %d", trackIndex);
752ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber#if 0
753ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                    track->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
754ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber#endif
755ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                    return;
756ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                }
757ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber
758cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<RefBase> obj;
759cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findObject("access-unit", &obj));
760cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
761cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());
762cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
7638d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                uint32_t seqNum = (uint32_t)accessUnit->int32Data();
7648d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
7656f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (mSeekPending) {
7666e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGV("we're seeking, dropping stale packet.");
7676f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    break;
7686f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
7696f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber
7708d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                if (seqNum < track->mFirstSeqNumInSegment) {
7716e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGV("dropping stale access-unit (%d < %d)",
7726e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                         seqNum, track->mFirstSeqNumInSegment);
7738d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    break;
7748d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
7758d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
7768d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                if (track->mNewSegment) {
7778d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    track->mNewSegment = false;
7788d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
7798d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
780100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                onAccessUnitComplete(trackIndex, accessUnit);
781cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
782cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
783cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
784cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            case 'seek':
785cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            {
7860dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                sp<AMessage> doneMsg;
7870dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                CHECK(msg->findMessage("doneMsg", &doneMsg));
7880dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
789cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                if (mSeekPending) {
7900dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                    doneMsg->post();
7910dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                    break;
7920dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                }
7930dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
7940dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                if (!mSeekable) {
7950dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                    LOGW("This is a live stream, ignoring seek request.");
7960dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                    doneMsg->post();
797cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                    break;
798cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                }
799cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
800cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                int64_t timeUs;
801cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(msg->findInt64("time", &timeUs));
802cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
803cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                mSeekPending = true;
804cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
805a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                // Disable the access unit timeout until we resumed
806a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                // playback again.
807a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                mCheckPending = true;
808a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                ++mCheckGeneration;
809a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
810cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                AString request = "PAUSE ";
811cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionURL);
812cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(" RTSP/1.0\r\n");
813cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
814cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("Session: ");
815cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionID);
816cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
817cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
818cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
819cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
820cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                sp<AMessage> reply = new AMessage('see1', id());
821cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                reply->setInt64("time", timeUs);
8220dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                reply->setMessage("doneMsg", doneMsg);
823cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                mConn->sendRequest(request.c_str(), reply);
824cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                break;
825cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            }
826cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
827cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            case 'see1':
828cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            {
8298d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                // Session is paused now.
8308d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
831100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    TrackInfo *info = &mTracks.editItemAt(i);
832100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
833100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    info->mPacketSource->flushQueue();
834100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    info->mRTPAnchor = 0;
835100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    info->mNTPAnchorUs = -1;
8368d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
8378d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
838100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                mNTPAnchorUs = -1;
839100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
840cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                int64_t timeUs;
841cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(msg->findInt64("time", &timeUs));
842cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
843cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                AString request = "PLAY ";
844cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionURL);
845cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(" RTSP/1.0\r\n");
846cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
847cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("Session: ");
848cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionID);
849cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
850cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
851cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(
852cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                        StringPrintf(
853cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                            "Range: npt=%lld-\r\n", timeUs / 1000000ll));
854cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
855cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
856cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
8570dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                sp<AMessage> doneMsg;
8580dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                CHECK(msg->findMessage("doneMsg", &doneMsg));
8590dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
860cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                sp<AMessage> reply = new AMessage('see2', id());
8610dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                reply->setMessage("doneMsg", doneMsg);
862cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                mConn->sendRequest(request.c_str(), reply);
863cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                break;
864cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            }
865cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
866cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            case 'see2':
867cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            {
868cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(mSeekPending);
869cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
870cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                int32_t result;
871cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(msg->findInt32("result", &result));
8728d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
8736e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("PLAY completed with result %d (%s)",
8746e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
8758d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
876a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                mCheckPending = false;
877a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                postAccessUnitTimeoutCheck();
878a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
8796f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (result == OK) {
8806f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    sp<RefBase> obj;
8816f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    CHECK(msg->findObject("response", &obj));
8826f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    sp<ARTSPResponse> response =
8836f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
884cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
8856f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    if (response->mStatusCode != 200) {
8866f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        result = UNKNOWN_ERROR;
8876f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    } else {
8886f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        parsePlayResponse(response);
889cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
890100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                        ssize_t i = response->mHeaders.indexOfKey("rtp-info");
891100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                        CHECK_GE(i, 0);
892100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
893100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                        LOGV("rtp-info: %s", response->mHeaders.valueAt(i).c_str());
894100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
8956e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                        LOGI("seek completed.");
8966f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    }
8976f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
898cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
8996f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (result != OK) {
9006e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGE("seek failed, aborting.");
9016f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    (new AMessage('abor', id()))->post();
9026f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
9038d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9048d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                mSeekPending = false;
9050dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
9060dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                sp<AMessage> doneMsg;
9070dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                CHECK(msg->findMessage("doneMsg", &doneMsg));
9080dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
9090dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                doneMsg->post();
910cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                break;
911cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            }
912cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
9130792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            case 'biny':
9140792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            {
9150792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                sp<RefBase> obj;
9160792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                CHECK(msg->findObject("buffer", &obj));
9170792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
9180792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
9190792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                int32_t index;
9200792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                CHECK(buffer->meta()->findInt32("index", &index));
9210792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
9220792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                mRTPConn->injectPacket(index, buffer);
9230792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                break;
9240792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            }
9250792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
9260792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            case 'tiou':
9270792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            {
928e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (!mReceivedFirstRTCPPacket) {
929dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                    if (mReceivedFirstRTPPacket && !mTryFakeRTCP) {
930f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                        LOGW("We received RTP packets but no RTCP packets, "
931f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                             "using fake timestamps.");
932f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber
933f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                        mTryFakeRTCP = true;
934f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber
935f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                        mReceivedFirstRTCPPacket = true;
936dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
937dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                        fakeTimestamps();
938dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                    } else if (!mReceivedFirstRTPPacket && !mTryTCPInterleaving) {
9396e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                        LOGW("Never received any data, switching transports.");
9407aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
9417aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        mTryTCPInterleaving = true;
9427aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
9437aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        sp<AMessage> msg = new AMessage('abor', id());
9447aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        msg->setInt32("reconnect", true);
9457aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        msg->post();
946dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                    } else {
947dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                        LOGW("Never received any data, disconnecting.");
948dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                        (new AMessage('abor', id()))->post();
9497aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    }
9500792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                }
9510792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                break;
9520792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            }
9530792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
954cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            default:
955cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                TRESPASS();
956cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
957cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
958cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
959cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
960a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber    void postAccessUnitTimeoutCheck() {
961a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        if (mCheckPending) {
962a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber            return;
963a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        }
964a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
965a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        mCheckPending = true;
966a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        sp<AMessage> check = new AMessage('chek', id());
967a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        check->setInt32("generation", mCheckGeneration);
968a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        check->post(kAccessUnitTimeoutUs);
969a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber    }
970a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
9718d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    static void SplitString(
9728d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            const AString &s, const char *separator, List<AString> *items) {
9738d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        items->clear();
9748d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        size_t start = 0;
9758d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        while (start < s.size()) {
9768d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            ssize_t offset = s.find(separator, start);
9778d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9788d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            if (offset < 0) {
9798d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                items->push_back(AString(s, start, s.size() - start));
9808d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                break;
9818d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            }
9828d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9838d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            items->push_back(AString(s, start, offset - start));
9848d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            start = offset + strlen(separator);
9858d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
9868d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    }
9878d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9888d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    void parsePlayResponse(const sp<ARTSPResponse> &response) {
9890dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber        mSeekable = false;
9900dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
9918d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        ssize_t i = response->mHeaders.indexOfKey("range");
9928d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        if (i < 0) {
9938d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            // Server doesn't even tell use what range it is going to
9948d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            // play, therefore we won't support seeking.
9958d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            return;
9968d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
9978d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9988d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        AString range = response->mHeaders.valueAt(i);
9996e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber        LOGV("Range: %s", range.c_str());
10008d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10018d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        AString val;
10028d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        CHECK(GetAttribute(range.c_str(), "npt", &val));
10038d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
1004783e5cd85d4bd40b1a04dfdfed256c5dcb2525ccAndreas Huber        float npt1, npt2;
1005783e5cd85d4bd40b1a04dfdfed256c5dcb2525ccAndreas Huber        if (!ASessionDescription::parseNTPRange(val.c_str(), &npt1, &npt2)) {
10068d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            // This is a live stream and therefore not seekable.
1007ac5767a96df9fae46a37ffba62611472135a0f6dAndreas Huber            return;
10088d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
10098d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10108d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        i = response->mHeaders.indexOfKey("rtp-info");
10118d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        CHECK_GE(i, 0);
10128d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10138d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        AString rtpInfo = response->mHeaders.valueAt(i);
10148d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        List<AString> streamInfos;
10158d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        SplitString(rtpInfo, ",", &streamInfos);
10168d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10178d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        int n = 1;
10188d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        for (List<AString>::iterator it = streamInfos.begin();
10198d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber             it != streamInfos.end(); ++it) {
10208d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            (*it).trim();
10216e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber            LOGV("streamInfo[%d] = %s", n, (*it).c_str());
10228d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10238d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK(GetAttribute((*it).c_str(), "url", &val));
10248d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10258d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            size_t trackIndex = 0;
10268d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            while (trackIndex < mTracks.size()
10278d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    && !(val == mTracks.editItemAt(trackIndex).mURL)) {
10288d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                ++trackIndex;
10298d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            }
10308d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK_LT(trackIndex, mTracks.size());
10318d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10328d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK(GetAttribute((*it).c_str(), "seq", &val));
10338d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10348d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            char *end;
10358d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            unsigned long seq = strtoul(val.c_str(), &end, 10);
10368d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10378d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            TrackInfo *info = &mTracks.editItemAt(trackIndex);
10388d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            info->mFirstSeqNumInSegment = seq;
10398d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            info->mNewSegment = true;
10408d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10418d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK(GetAttribute((*it).c_str(), "rtptime", &val));
10428d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10438d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            uint32_t rtpTime = strtoul(val.c_str(), &end, 10);
10448d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
1045100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            LOGV("track #%d: rtpTime=%u <=> npt=%.2f", n, rtpTime, npt1);
10468d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10478d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            info->mPacketSource->setNormalPlayTimeMapping(
10488d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    rtpTime, (int64_t)(npt1 * 1E6));
10498d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10508d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            ++n;
10518d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
10520dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
1053ac5767a96df9fae46a37ffba62611472135a0f6dAndreas Huber        mSeekable = true;
10548d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    }
10558d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
1056cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<APacketSource> getPacketSource(size_t index) {
1057cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK_GE(index, 0u);
1058cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK_LT(index, mTracks.size());
1059cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1060cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        return mTracks.editItemAt(index).mPacketSource;
1061cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
1062cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1063cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    size_t countTracks() const {
1064cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        return mTracks.size();
1065cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
1066cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1067cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huberprivate:
1068100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    struct TrackInfo {
1069100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        AString mURL;
1070100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int mRTPSocket;
1071100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int mRTCPSocket;
1072100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        bool mUsingInterleavedTCP;
1073100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        uint32_t mFirstSeqNumInSegment;
1074100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        bool mNewSegment;
1075100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1076100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        uint32_t mRTPAnchor;
1077100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int64_t mNTPAnchorUs;
1078100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int32_t mTimeScale;
1079100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1080100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        sp<APacketSource> mPacketSource;
1081100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1082100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        // Stores packets temporarily while no notion of time
1083100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        // has been established yet.
1084100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        List<sp<ABuffer> > mPackets;
1085100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    };
1086100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
10879b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber    bool mUIDValid;
10889b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber    uid_t mUID;
1089cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ALooper> mLooper;
1090348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber    sp<ALooper> mNetLooper;
1091cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ARTSPConnection> mConn;
1092cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ARTPConnection> mRTPConn;
1093cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ASessionDescription> mSessionDesc;
10944579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber    AString mOriginalSessionURL;  // This one still has user:pass@
1095cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mSessionURL;
1096de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber    AString mSessionHost;
1097cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mBaseURL;
1098cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mSessionID;
1099cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    bool mSetupTracksSuccessful;
1100cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber    bool mSeekPending;
1101cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber    bool mFirstAccessUnit;
1102100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1103100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    int64_t mNTPAnchorUs;
1104100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    int64_t mMediaAnchorUs;
1105100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    int64_t mLastMediaTimeUs;
1106100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
11078d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    int64_t mNumAccessUnitsReceived;
11088d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    bool mCheckPending;
1109a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber    int32_t mCheckGeneration;
11107aef03379179c109c2547c33c410bfc93c8db576Andreas Huber    bool mTryTCPInterleaving;
1111f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber    bool mTryFakeRTCP;
1112e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber    bool mReceivedFirstRTCPPacket;
1113f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber    bool mReceivedFirstRTPPacket;
11140dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber    bool mSeekable;
1115cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1116cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    Vector<TrackInfo> mTracks;
1117cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
11181b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber    sp<AMessage> mDoneMsg;
11191b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber
1120cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    void setupTrack(size_t index) {
112139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        sp<APacketSource> source =
112239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            new APacketSource(mSessionDesc, index);
11237aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
112439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (source->initCheck() != OK) {
11256e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber            LOGW("Unsupported format. Ignoring track #%d.", index);
112639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
112739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            sp<AMessage> reply = new AMessage('setu', id());
112839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            reply->setSize("index", index);
112939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            reply->setInt32("result", ERROR_UNSUPPORTED);
113039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            reply->post();
113139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            return;
113239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
113339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
1134cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString url;
1135cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK(mSessionDesc->findAttribute(index, "a=control", &url));
1136cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1137cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString trackURL;
1138cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK(MakeURL(mBaseURL.c_str(), url.c_str(), &trackURL));
1139cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1140cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mTracks.push(TrackInfo());
1141cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1);
11428d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        info->mURL = trackURL;
114339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        info->mPacketSource = source;
11440792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber        info->mUsingInterleavedTCP = false;
11458d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        info->mFirstSeqNumInSegment = 0;
11468d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        info->mNewSegment = true;
1147100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        info->mRTPAnchor = 0;
1148100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        info->mNTPAnchorUs = -1;
1149100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1150100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        unsigned long PT;
1151100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        AString formatDesc;
1152100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        AString formatParams;
1153100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        mSessionDesc->getFormatType(index, &PT, &formatDesc, &formatParams);
1154100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1155100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int32_t timescale;
1156100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int32_t numChannels;
1157100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        ASessionDescription::ParseFormatDesc(
1158100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                formatDesc.c_str(), &timescale, &numChannels);
1159100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1160100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        info->mTimeScale = timescale;
11618d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11626e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber        LOGV("track #%d URL=%s", mTracks.size(), trackURL.c_str());
1163cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1164cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString request = "SETUP ";
1165cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append(trackURL);
1166cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append(" RTSP/1.0\r\n");
1167cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
11687aef03379179c109c2547c33c410bfc93c8db576Andreas Huber        if (mTryTCPInterleaving) {
11697aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            size_t interleaveIndex = 2 * (mTracks.size() - 1);
11707aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            info->mUsingInterleavedTCP = true;
11717aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            info->mRTPSocket = interleaveIndex;
11727aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            info->mRTCPSocket = interleaveIndex + 1;
11737aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
11747aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("Transport: RTP/AVP/TCP;interleaved=");
11757aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(interleaveIndex);
11767aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("-");
11777aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(interleaveIndex + 1);
11787aef03379179c109c2547c33c410bfc93c8db576Andreas Huber        } else {
11797aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            unsigned rtpPort;
11807aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            ARTPConnection::MakePortPair(
11817aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    &info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
11827aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
11839b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber            if (mUIDValid) {
1184dab718bba3945332dc75e268e1e7f0fe2eb91c4aAndreas Huber                HTTPBase::RegisterSocketUser(info->mRTPSocket, mUID);
1185dab718bba3945332dc75e268e1e7f0fe2eb91c4aAndreas Huber                HTTPBase::RegisterSocketUser(info->mRTCPSocket, mUID);
11869b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber            }
11879b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber
11887aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
11897aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(rtpPort);
11907aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("-");
11917aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(rtpPort + 1);
11927aef03379179c109c2547c33c410bfc93c8db576Andreas Huber        }
11930792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
1194cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append("\r\n");
1195cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1196cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (index > 1) {
1197cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            request.append("Session: ");
1198cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            request.append(mSessionID);
1199cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            request.append("\r\n");
1200cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1201cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1202cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append("\r\n");
1203cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1204cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sp<AMessage> reply = new AMessage('setu', id());
1205cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        reply->setSize("index", index);
1206cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        reply->setSize("track-index", mTracks.size() - 1);
1207cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mConn->sendRequest(request.c_str(), reply);
1208cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
1209cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1210cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    static bool MakeURL(const char *baseURL, const char *url, AString *out) {
1211cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        out->clear();
1212cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1213cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (strncasecmp("rtsp://", baseURL, 7)) {
1214cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            // Base URL must be absolute
1215cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            return false;
1216cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1217cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1218cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (!strncasecmp("rtsp://", url, 7)) {
1219cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            // "url" is already an absolute URL, ignore base URL.
1220cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->setTo(url);
1221cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            return true;
1222cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1223cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1224cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        size_t n = strlen(baseURL);
1225cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (baseURL[n - 1] == '/') {
1226cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->setTo(baseURL);
1227cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->append(url);
1228cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        } else {
12294e2ffa400b82559cab2c5717c8dcdff393d334a9Mike Lockwood            const char *slashPos = strrchr(baseURL, '/');
1230cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1231cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            if (slashPos > &baseURL[6]) {
1232cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                out->setTo(baseURL, slashPos - baseURL);
1233cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            } else {
1234cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                out->setTo(baseURL);
1235cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
1236cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1237cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->append("/");
1238cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->append(url);
1239cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1240cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1241cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        return true;
1242cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
1243cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1244dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber    void fakeTimestamps() {
1245dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        for (size_t i = 0; i < mTracks.size(); ++i) {
1246dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            onTimeUpdate(i, 0, 0ll);
1247dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        }
1248dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber    }
1249dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
1250100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    void onTimeUpdate(int32_t trackIndex, uint32_t rtpTime, uint64_t ntpTime) {
1251100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        LOGV("onTimeUpdate track %d, rtpTime = 0x%08x, ntpTime = 0x%016llx",
1252100a4408968b90e314526185d572c72ea4cc784aAndreas Huber             trackIndex, rtpTime, ntpTime);
1253100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1254100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int64_t ntpTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
1255100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1256100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        TrackInfo *track = &mTracks.editItemAt(trackIndex);
1257100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1258100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        track->mRTPAnchor = rtpTime;
1259100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        track->mNTPAnchorUs = ntpTimeUs;
1260100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1261100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        if (mNTPAnchorUs < 0) {
1262100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            mNTPAnchorUs = ntpTimeUs;
1263100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            mMediaAnchorUs = mLastMediaTimeUs;
1264100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1265100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    }
1266100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1267100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    void onAccessUnitComplete(
1268100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            int32_t trackIndex, const sp<ABuffer> &accessUnit) {
1269100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        LOGV("onAccessUnitComplete track %d", trackIndex);
1270100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1271100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        if (mFirstAccessUnit) {
1272100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            mDoneMsg->setInt32("result", OK);
1273100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            mDoneMsg->post();
1274100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            mDoneMsg = NULL;
1275100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1276100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            mFirstAccessUnit = false;
1277100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1278100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1279100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        TrackInfo *track = &mTracks.editItemAt(trackIndex);
1280100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1281100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        if (mNTPAnchorUs < 0 || mMediaAnchorUs < 0 || track->mNTPAnchorUs < 0) {
1282100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            LOGV("storing accessUnit, no time established yet");
1283100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            track->mPackets.push_back(accessUnit);
1284100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            return;
1285100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1286100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1287100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        while (!track->mPackets.empty()) {
1288100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            sp<ABuffer> accessUnit = *track->mPackets.begin();
1289100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            track->mPackets.erase(track->mPackets.begin());
1290100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1291100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            if (addMediaTimestamp(trackIndex, track, accessUnit)) {
1292100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                track->mPacketSource->queueAccessUnit(accessUnit);
1293100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            }
1294100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1295100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1296100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        if (addMediaTimestamp(trackIndex, track, accessUnit)) {
1297100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            track->mPacketSource->queueAccessUnit(accessUnit);
1298100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1299100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    }
1300100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1301100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    bool addMediaTimestamp(
1302100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            int32_t trackIndex, const TrackInfo *track,
1303100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            const sp<ABuffer> &accessUnit) {
1304100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        uint32_t rtpTime;
1305100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        CHECK(accessUnit->meta()->findInt32(
1306100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    "rtp-time", (int32_t *)&rtpTime));
1307100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1308100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int64_t relRtpTimeUs =
1309100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            (((int64_t)rtpTime - (int64_t)track->mRTPAnchor) * 1000000ll)
1310100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                / track->mTimeScale;
1311100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1312100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int64_t ntpTimeUs = track->mNTPAnchorUs + relRtpTimeUs;
1313100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1314100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int64_t mediaTimeUs = mMediaAnchorUs + ntpTimeUs - mNTPAnchorUs;
1315100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1316100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        if (mediaTimeUs > mLastMediaTimeUs) {
1317100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            mLastMediaTimeUs = mediaTimeUs;
1318100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1319100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1320100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        if (mediaTimeUs < 0) {
1321100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            LOGV("dropping early accessUnit.");
1322100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            return false;
1323100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1324100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1325100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        LOGV("track %d rtpTime=%d mediaTimeUs = %lld us (%.2f secs)",
1326100a4408968b90e314526185d572c72ea4cc784aAndreas Huber             trackIndex, rtpTime, mediaTimeUs, mediaTimeUs / 1E6);
1327100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1328100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        accessUnit->meta()->setInt64("timeUs", mediaTimeUs);
1329100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1330100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        return true;
1331100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    }
1332100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1333100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1334cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    DISALLOW_EVIL_CONSTRUCTORS(MyHandler);
1335cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber};
1336cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1337cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber}  // namespace android
1338cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1339cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif  // MY_HANDLER_H_
1340