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.
47908dbdee96856693decc04fa143c2ba525495d43Andreas Huberstatic int64_t kAccessUnitTimeoutUs = 10000000ll;
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
53908dbdee96856693decc04fa143c2ba525495d43Andreas Huberstatic int64_t kDefaultKeepAliveTimeoutUs = 60000000ll;
54908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
55cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Hubernamespace android {
56cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
572bc940b4f961e588459c83862b2c6bea314a4027Andreas Huberstatic void MakeUserAgentString(AString *s) {
582bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    s->setTo("stagefright/1.1 (Linux;Android ");
592bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
602bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#if (PROPERTY_VALUE_MAX < 8)
612bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#error "PROPERTY_VALUE_MAX must be at least 8"
622bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#endif
632bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
642bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    char value[PROPERTY_VALUE_MAX];
652bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    property_get("ro.build.version.release", value, "Unknown");
662bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    s->append(value);
672bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    s->append(")");
682bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber}
692bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
708d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huberstatic bool GetAttribute(const char *s, const char *key, AString *value) {
718d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    value->clear();
728d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
738d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    size_t keyLen = strlen(key);
748d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
758d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    for (;;) {
768d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        while (isspace(*s)) {
778d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            ++s;
788d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
798d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
808d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        const char *colonPos = strchr(s, ';');
818d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
828d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        size_t len =
838d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            (colonPos == NULL) ? strlen(s) : colonPos - s;
848d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
858d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
868d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            value->setTo(&s[keyLen + 1], len - keyLen - 1);
878d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            return true;
888d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
898d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
908d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        if (colonPos == NULL) {
918d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            return false;
928d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
938d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
948d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        s = colonPos + 1;
958d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    }
968d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber}
978d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
98cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huberstruct MyHandler : public AHandler {
992bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    enum {
1002bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        kWhatConnected                  = 'conn',
1012bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        kWhatDisconnected               = 'disc',
1022bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        kWhatSeekDone                   = 'sdon',
1032bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
1042bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        kWhatAccessUnit                 = 'accU',
1052bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        kWhatEOS                        = 'eos!',
1062bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        kWhatSeekDiscontinuity          = 'seeD',
1072bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        kWhatNormalPlayTimeMapping      = 'nptM',
1082bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    };
1092bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
1109b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber    MyHandler(
1112bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            const char *url,
1122bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            const sp<AMessage> &notify,
1139b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber            bool uidValid = false, uid_t uid = 0)
1142bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        : mNotify(notify),
1152bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber          mUIDValid(uidValid),
1169b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber          mUID(uid),
117348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber          mNetLooper(new ALooper),
1189b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber          mConn(new ARTSPConnection(mUIDValid, mUID)),
119cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mRTPConn(new ARTPConnection),
1204579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber          mOriginalSessionURL(url),
121cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mSessionURL(url),
122cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber          mSetupTracksSuccessful(false),
123cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber          mSeekPending(false),
124cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber          mFirstAccessUnit(true),
1257e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber          mAllTracksHaveTime(false),
126100a4408968b90e314526185d572c72ea4cc784aAndreas Huber          mNTPAnchorUs(-1),
127100a4408968b90e314526185d572c72ea4cc784aAndreas Huber          mMediaAnchorUs(-1),
128100a4408968b90e314526185d572c72ea4cc784aAndreas Huber          mLastMediaTimeUs(0),
1298d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber          mNumAccessUnitsReceived(0),
1307aef03379179c109c2547c33c410bfc93c8db576Andreas Huber          mCheckPending(false),
131a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber          mCheckGeneration(0),
132e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber          mTryTCPInterleaving(false),
133f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber          mTryFakeRTCP(false),
1340dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber          mReceivedFirstRTCPPacket(false),
135f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber          mReceivedFirstRTPPacket(false),
136908dbdee96856693decc04fa143c2ba525495d43Andreas Huber          mSeekable(false),
137908dbdee96856693decc04fa143c2ba525495d43Andreas Huber          mKeepAliveTimeoutUs(kDefaultKeepAliveTimeoutUs),
138908dbdee96856693decc04fa143c2ba525495d43Andreas Huber          mKeepAliveGeneration(0) {
139a814c1fdc2acf0ed2ee3b175110f6039be7c4873Andreas Huber        mNetLooper->setName("rtsp net");
140348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber        mNetLooper->start(false /* runOnCallingThread */,
141348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                          false /* canCallJava */,
142348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                          PRIORITY_HIGHEST);
1434579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber
1444579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        // Strip any authentication info from the session url, we don't
1454579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        // want to transmit user/pass in cleartext.
1464579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        AString host, path, user, pass;
1474579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        unsigned port;
148de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        CHECK(ARTSPConnection::ParseURL(
149de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                    mSessionURL.c_str(), &host, &port, &path, &user, &pass));
150de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
151de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        if (user.size() > 0) {
1524579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.clear();
1534579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.append("rtsp://");
1544579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.append(host);
1554579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.append(":");
1564579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.append(StringPrintf("%u", port));
1574579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber            mSessionURL.append(path);
1584579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber
159df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("rewritten session url: '%s'", mSessionURL.c_str());
1604579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        }
161de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
162de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        mSessionHost = host;
163348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber    }
164348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber
1652bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    void connect() {
1662bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        looper()->registerHandler(mConn);
1672bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        (1 ? mNetLooper : looper())->registerHandler(mRTPConn);
168348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber
1690792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber        sp<AMessage> notify = new AMessage('biny', id());
1700792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber        mConn->observeBinaryData(notify);
1710792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
1721b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber        sp<AMessage> reply = new AMessage('conn', id());
1734579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber        mConn->connect(mOriginalSessionURL.c_str(), reply);
174cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
175cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1762bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    void disconnect() {
1771b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber        (new AMessage('abor', id()))->post();
178348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber    }
179348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber
1802bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    void seek(int64_t timeUs) {
181cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber        sp<AMessage> msg = new AMessage('seek', id());
182cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber        msg->setInt64("time", timeUs);
183cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber        msg->post();
184cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber    }
185cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
1862bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    static void addRR(const sp<ABuffer> &buf) {
1872bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        uint8_t *ptr = buf->data() + buf->size();
1882bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[0] = 0x80 | 0;
1892bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[1] = 201;  // RR
1902bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[2] = 0;
1912bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[3] = 1;
1922bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[4] = 0xde;  // SSRC
1932bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[5] = 0xad;
1942bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[6] = 0xbe;
1952bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[7] = 0xef;
1962bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
1972bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        buf->setRange(0, buf->size() + 8);
1982bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    }
1992bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2002bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    static void addSDES(int s, const sp<ABuffer> &buffer) {
2012bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        struct sockaddr_in addr;
2022bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        socklen_t addrSize = sizeof(addr);
2032bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        CHECK_EQ(0, getsockname(s, (sockaddr *)&addr, &addrSize));
2042bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2052bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        uint8_t *data = buffer->data() + buffer->size();
2062bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[0] = 0x80 | 1;
2072bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[1] = 202;  // SDES
2082bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[4] = 0xde;  // SSRC
2092bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[5] = 0xad;
2102bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[6] = 0xbe;
2112bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[7] = 0xef;
2122bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2132bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        size_t offset = 8;
2142bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2152bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = 1;  // CNAME
2162bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2172bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString cname = "stagefright@";
2182bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        cname.append(inet_ntoa(addr.sin_addr));
2192bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = cname.size();
2202bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2212bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        memcpy(&data[offset], cname.c_str(), cname.size());
2222bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        offset += cname.size();
2232bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2242bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = 6;  // TOOL
2252bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2262bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString tool;
2272bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        MakeUserAgentString(&tool);
2282bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2292bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = tool.size();
2302bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2312bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        memcpy(&data[offset], tool.c_str(), tool.size());
2322bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        offset += tool.size();
2332bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2342bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = 0;
2352bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2362bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if ((offset % 4) > 0) {
2372bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            size_t count = 4 - (offset % 4);
2382bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            switch (count) {
2392bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                case 3:
2402bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                    data[offset++] = 0;
2412bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                case 2:
2422bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                    data[offset++] = 0;
2432bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                case 1:
2442bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                    data[offset++] = 0;
2452bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            }
2462bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
2472bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2482bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        size_t numWords = (offset / 4) - 1;
2492bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[2] = numWords >> 8;
2502bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[3] = numWords & 0xff;
2512bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2522bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        buffer->setRange(buffer->offset(), buffer->size() + offset);
2532bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    }
2542bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2552bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    // In case we're behind NAT, fire off two UDP packets to the remote
2562bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    // rtp/rtcp ports to poke a hole into the firewall for future incoming
2572bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    // packets. We're going to send an RR/SDES RTCP packet to both of them.
258dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber    bool pokeAHole(int rtpSocket, int rtcpSocket, const AString &transport) {
259de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        struct sockaddr_in addr;
260de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
261de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        addr.sin_family = AF_INET;
262de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
2632bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString source;
2642bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString server_port;
2652bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if (!GetAttribute(transport.c_str(),
2662bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                          "source",
267de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                          &source)) {
2685ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block            ALOGW("Missing 'source' field in Transport response. Using "
269de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                 "RTSP endpoint address.");
270de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
271de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            struct hostent *ent = gethostbyname(mSessionHost.c_str());
272de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            if (ent == NULL) {
27329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("Failed to look up address of session host '%s'",
274de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                     mSessionHost.c_str());
275de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
276de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                return false;
277de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            }
278de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
279de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
280de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        } else {
281de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber            addr.sin_addr.s_addr = inet_addr(source.c_str());
282de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        }
283de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber
284de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber        if (!GetAttribute(transport.c_str(),
2852bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                                 "server_port",
2862bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                                 &server_port)) {
287df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("Missing 'server_port' field in Transport response.");
288dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return false;
2892bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
2902bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2912bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        int rtpPort, rtcpPort;
2922bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if (sscanf(server_port.c_str(), "%d-%d", &rtpPort, &rtcpPort) != 2
2932bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                || rtpPort <= 0 || rtpPort > 65535
2942bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                || rtcpPort <=0 || rtcpPort > 65535
295dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                || rtcpPort != rtpPort + 1) {
29629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Server picked invalid RTP/RTCP port pair %s,"
297dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                 " RTP port must be even, RTCP port must be one higher.",
298dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                 server_port.c_str());
299dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
300dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return false;
301dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        }
302dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
303dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        if (rtpPort & 1) {
3045ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block            ALOGW("Server picked an odd RTP port, it should've picked an "
305dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                 "even one, we'll let it pass for now, but this may break "
306dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                 "in the future.");
3072bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
3082bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3092bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if (addr.sin_addr.s_addr == INADDR_NONE) {
310dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return true;
311dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        }
312dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
313dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        if (IN_LOOPBACK(ntohl(addr.sin_addr.s_addr))) {
314dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            // No firewalls to traverse on the loopback interface.
315dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return true;
3162bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
3172bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3182bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        // Make up an RR/SDES RTCP packet.
3192bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        sp<ABuffer> buf = new ABuffer(65536);
3202bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        buf->setRange(0, 0);
3212bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addRR(buf);
3222bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addSDES(rtpSocket, buf);
3232bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3242bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addr.sin_port = htons(rtpPort);
3252bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3262bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ssize_t n = sendto(
3272bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                rtpSocket, buf->data(), buf->size(), 0,
3282bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                (const sockaddr *)&addr, sizeof(addr));
329dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
330dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        if (n < (ssize_t)buf->size()) {
33129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("failed to poke a hole for RTP packets");
332dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return false;
333dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        }
3342bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3352bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addr.sin_port = htons(rtcpPort);
3362bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3372bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        n = sendto(
3382bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                rtcpSocket, buf->data(), buf->size(), 0,
3392bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                (const sockaddr *)&addr, sizeof(addr));
340dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
341dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        if (n < (ssize_t)buf->size()) {
34229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("failed to poke a hole for RTCP packets");
343dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            return false;
344dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        }
3452bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
3463856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("successfully poked holes.");
347dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
348dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        return true;
3492bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    }
3502bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
351cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    virtual void onMessageReceived(const sp<AMessage> &msg) {
352cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        switch (msg->what()) {
353cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'conn':
354cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
355cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
356cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
357cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
358df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                ALOGI("connection request completed with result %d (%s)",
3596e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
360cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
361cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
362cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    AString request;
363cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request = "DESCRIBE ";
364cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(mSessionURL);
365cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(" RTSP/1.0\r\n");
366cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("Accept: application/sdp\r\n");
367cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("\r\n");
368cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
369cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('desc', id());
370cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->sendRequest(request.c_str(), reply);
3710792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                } else {
3720792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                    (new AMessage('disc', id()))->post();
373cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
374cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
375cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
376cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
377cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'disc':
378cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
379908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                ++mKeepAliveGeneration;
380908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
3817aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                int32_t reconnect;
3827aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
3837aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    sp<AMessage> reply = new AMessage('conn', id());
3844579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber                    mConn->connect(mOriginalSessionURL.c_str(), reply);
3857aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                } else {
3867aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    (new AMessage('quit', id()))->post();
3877aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
388cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
389cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
390cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
391cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'desc':
392cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
393cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
394cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
395cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
396df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                ALOGI("DESCRIBE completed with result %d (%s)",
3976e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
398cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
399cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
400cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<RefBase> obj;
401cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(msg->findObject("response", &obj));
402cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<ARTSPResponse> response =
403cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
404cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
405cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    if (response->mStatusCode == 302) {
406cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        ssize_t i = response->mHeaders.indexOfKey("location");
407cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        CHECK_GE(i, 0);
408cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
409cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        mSessionURL = response->mHeaders.valueAt(i);
410cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
411cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        AString request;
412cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request = "DESCRIBE ";
413cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append(mSessionURL);
414cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append(" RTSP/1.0\r\n");
415cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append("Accept: application/sdp\r\n");
416cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append("\r\n");
417cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
418cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        sp<AMessage> reply = new AMessage('desc', id());
419cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        mConn->sendRequest(request.c_str(), reply);
420cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        break;
421cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    }
422cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
423e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    if (response->mStatusCode != 200) {
424e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        result = UNKNOWN_ERROR;
425e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    } else {
426e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        mSessionDesc = new ASessionDescription;
427cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
428e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        mSessionDesc->setTo(
429e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                response->mContent->data(),
430e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                response->mContent->size());
431cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
4326f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        if (!mSessionDesc->isValid()) {
43329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                            ALOGE("Failed to parse session description.");
4346f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                            result = ERROR_MALFORMED;
435cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        } else {
4366f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                            ssize_t i = response->mHeaders.indexOfKey("content-base");
437e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            if (i >= 0) {
438e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                mBaseURL = response->mHeaders.valueAt(i);
439e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            } else {
4406f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                i = response->mHeaders.indexOfKey("content-location");
4416f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                if (i >= 0) {
4426f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                    mBaseURL = response->mHeaders.valueAt(i);
4436f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                } else {
4446f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                    mBaseURL = mSessionURL;
4456f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                }
446e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            }
447e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
448dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                            if (!mBaseURL.startsWith("rtsp://")) {
449dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                // Some misbehaving servers specify a relative
450dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                // URL in one of the locations above, combine
451dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                // it with the absolute session URL to get
452dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                // something usable...
453dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
4545ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block                                ALOGW("Server specified a non-absolute base URL"
455dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                     ", combining it with the session URL to "
456dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                     "get something usable...");
457dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
458dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                AString tmp;
459dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                CHECK(MakeURL(
460dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                            mSessionURL.c_str(),
461dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                            mBaseURL.c_str(),
462dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                            &tmp));
463dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
464dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                                mBaseURL = tmp;
465dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                            }
466dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
467f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber                            if (mSessionDesc->countTracks() < 2) {
468f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber                                // There's no actual tracks in this session.
469f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber                                // The first "track" is merely session meta
470f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber                                // data.
471f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber
4725ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block                                ALOGW("Session doesn't contain any playable "
473f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber                                     "tracks. Aborting.");
474f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber                                result = ERROR_UNSUPPORTED;
475f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber                            } else {
476f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber                                setupTrack(1);
477f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber                            }
4786f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        }
479cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    }
480e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                }
481cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
482e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (result != OK) {
483cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
484cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->disconnect(reply);
485cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
486cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
487cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
488cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
489cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'setu':
490cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
491cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                size_t index;
492cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findSize("index", &index));
493cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
49439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                TrackInfo *track = NULL;
495cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                size_t trackIndex;
49639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                if (msg->findSize("track-index", &trackIndex)) {
49739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                    track = &mTracks.editItemAt(trackIndex);
49839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                }
499cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
500cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
501cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
502cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
503df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                ALOGI("SETUP(%d) completed with result %d (%s)",
5046e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     index, result, strerror(-result));
505cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
506e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (result == OK) {
50739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                    CHECK(track != NULL);
508cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
509cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<RefBase> obj;
510cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(msg->findObject("response", &obj));
511cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<ARTSPResponse> response =
512cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
513cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
514e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    if (response->mStatusCode != 200) {
515e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        result = UNKNOWN_ERROR;
516e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    } else {
517e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        ssize_t i = response->mHeaders.indexOfKey("session");
518e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        CHECK_GE(i, 0);
519cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
520cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        mSessionID = response->mHeaders.valueAt(i);
521908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
522908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                        mKeepAliveTimeoutUs = kDefaultKeepAliveTimeoutUs;
523908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                        AString timeoutStr;
524908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                        if (GetAttribute(
525908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                                    mSessionID.c_str(), "timeout", &timeoutStr)) {
526908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                            char *end;
527908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                            unsigned long timeoutSecs =
528908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                                strtoul(timeoutStr.c_str(), &end, 10);
529908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
530908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                            if (end == timeoutStr.c_str() || *end != '\0') {
5315ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block                                ALOGW("server specified malformed timeout '%s'",
532908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                                     timeoutStr.c_str());
533908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
534908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                                mKeepAliveTimeoutUs = kDefaultKeepAliveTimeoutUs;
535908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                            } else if (timeoutSecs < 15) {
5365ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block                                ALOGW("server specified too short a timeout "
537908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                                     "(%lu secs), using default.",
538908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                                     timeoutSecs);
539908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
540908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                                mKeepAliveTimeoutUs = kDefaultKeepAliveTimeoutUs;
541908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                            } else {
542908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                                mKeepAliveTimeoutUs = timeoutSecs * 1000000ll;
543908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
544df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                                ALOGI("server specified timeout of %lu secs.",
545908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                                     timeoutSecs);
546908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                            }
547908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                        }
548908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
549cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        i = mSessionID.find(";");
550cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        if (i >= 0) {
551cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                            // Remove options, i.e. ";timeout=90"
552cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                            mSessionID.erase(i, mSessionID.size() - i);
553cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        }
554cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
555e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        sp<AMessage> notify = new AMessage('accu', id());
556e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        notify->setSize("track-index", trackIndex);
557cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
5582bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        i = response->mHeaders.indexOfKey("transport");
5592bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        CHECK_GE(i, 0);
5602bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
5612bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        if (!track->mUsingInterleavedTCP) {
5622bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                            AString transport = response->mHeaders.valueAt(i);
5632bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
564de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                            // We are going to continue even if we were
565de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                            // unable to poke a hole into the firewall...
566de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                            pokeAHole(
567de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                    track->mRTPSocket,
568de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                    track->mRTCPSocket,
569de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                    transport);
5702bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        }
5712bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
572de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                        mRTPConn->addStream(
573de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                track->mRTPSocket, track->mRTCPSocket,
574de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                mSessionDesc, index,
575de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                                notify, track->mUsingInterleavedTCP);
576cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
577de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber                        mSetupTracksSuccessful = true;
578e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    }
579e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                }
580e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
581e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (result != OK) {
582e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    if (track) {
583e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        if (!track->mUsingInterleavedTCP) {
584a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                            // Clear the tag
585a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                            if (mUIDValid) {
586a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                                HTTPBase::UnRegisterSocketUserTag(track->mRTPSocket);
587a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                                HTTPBase::UnRegisterSocketUserTag(track->mRTCPSocket);
588a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                            }
589a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma
590e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            close(track->mRTPSocket);
591e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            close(track->mRTCPSocket);
592e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        }
593e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
594e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        mTracks.removeItemsAt(trackIndex);
595e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    }
596cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
597cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
59839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                ++index;
59939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                if (index < mSessionDesc->countTracks()) {
60039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                    setupTrack(index);
60139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                } else if (mSetupTracksSuccessful) {
602908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                    ++mKeepAliveGeneration;
603908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                    postKeepAlive();
604908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
605cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    AString request = "PLAY ";
606cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(mSessionURL);
607cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(" RTSP/1.0\r\n");
608cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
609cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("Session: ");
610cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(mSessionID);
611cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("\r\n");
612cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
613cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("\r\n");
614cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
615cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('play', id());
616cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->sendRequest(request.c_str(), reply);
617cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                } else {
618cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
619cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->disconnect(reply);
620cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
621cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
622cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
623cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
624cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'play':
625cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
626cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
627cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
628cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
629df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                ALOGI("PLAY completed with result %d (%s)",
6306e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
631cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
632cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
633cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<RefBase> obj;
634cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(msg->findObject("response", &obj));
635cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<ARTSPResponse> response =
636cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
637cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
6386f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    if (response->mStatusCode != 200) {
6396f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        result = UNKNOWN_ERROR;
6406f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    } else {
6416f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        parsePlayResponse(response);
642cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
6436f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        sp<AMessage> timeout = new AMessage('tiou', id());
6446f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        timeout->post(kStartupTimeoutUs);
6456f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    }
6466f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
6478d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
6486f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (result != OK) {
649cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
650cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->disconnect(reply);
651cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
652cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
653cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
654cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
655cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
656908dbdee96856693decc04fa143c2ba525495d43Andreas Huber            case 'aliv':
657908dbdee96856693decc04fa143c2ba525495d43Andreas Huber            {
658908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                int32_t generation;
659908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                CHECK(msg->findInt32("generation", &generation));
660908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
661908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                if (generation != mKeepAliveGeneration) {
662908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                    // obsolete event.
663908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                    break;
664908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                }
665908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
666908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                AString request;
667908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                request.append("OPTIONS ");
668908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                request.append(mSessionURL);
669908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                request.append(" RTSP/1.0\r\n");
670908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                request.append("Session: ");
671908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                request.append(mSessionID);
672908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                request.append("\r\n");
673908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                request.append("\r\n");
674908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
675908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                sp<AMessage> reply = new AMessage('opts', id());
676908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                reply->setInt32("generation", mKeepAliveGeneration);
677908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                mConn->sendRequest(request.c_str(), reply);
678908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                break;
679908dbdee96856693decc04fa143c2ba525495d43Andreas Huber            }
680908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
681908dbdee96856693decc04fa143c2ba525495d43Andreas Huber            case 'opts':
682908dbdee96856693decc04fa143c2ba525495d43Andreas Huber            {
683908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                int32_t result;
684908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                CHECK(msg->findInt32("result", &result));
685908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
686df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                ALOGI("OPTIONS completed with result %d (%s)",
687908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                     result, strerror(-result));
688908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
689908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                int32_t generation;
690908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                CHECK(msg->findInt32("generation", &generation));
691908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
692908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                if (generation != mKeepAliveGeneration) {
693908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                    // obsolete event.
694908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                    break;
695908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                }
696908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
697908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                postKeepAlive();
698908dbdee96856693decc04fa143c2ba525495d43Andreas Huber                break;
699908dbdee96856693decc04fa143c2ba525495d43Andreas Huber            }
700908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
701cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'abor':
702cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
703cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
7047aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    TrackInfo *info = &mTracks.editItemAt(i);
7057aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
7062bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                    if (!mFirstAccessUnit) {
7072bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                        postQueueEOS(i, ERROR_END_OF_STREAM);
7082bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                    }
7097aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
7107aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    if (!info->mUsingInterleavedTCP) {
7117aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket);
7127aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
713a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                        // Clear the tag
714a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                        if (mUIDValid) {
715a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                            HTTPBase::UnRegisterSocketUserTag(info->mRTPSocket);
716a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                            HTTPBase::UnRegisterSocketUserTag(info->mRTCPSocket);
717a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                        }
718a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma
7197aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        close(info->mRTPSocket);
7207aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        close(info->mRTCPSocket);
7217aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    }
722cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
7237aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                mTracks.clear();
724e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mSetupTracksSuccessful = false;
725e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mSeekPending = false;
726e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mFirstAccessUnit = true;
7277e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                mAllTracksHaveTime = false;
728100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                mNTPAnchorUs = -1;
729100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                mMediaAnchorUs = -1;
730e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mNumAccessUnitsReceived = 0;
731e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mReceivedFirstRTCPPacket = false;
732f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                mReceivedFirstRTPPacket = false;
7330dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                mSeekable = false;
734cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
735cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<AMessage> reply = new AMessage('tear', id());
736cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
7377aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                int32_t reconnect;
7387aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
7397aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    reply->setInt32("reconnect", true);
7407aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
7417aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
742cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                AString request;
743cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request = "TEARDOWN ";
744cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
745cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                // XXX should use aggregate url from SDP here...
746cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mSessionURL);
747cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(" RTSP/1.0\r\n");
748cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
749cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("Session: ");
750cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mSessionID);
751cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
752cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
753cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
754cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
755cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConn->sendRequest(request.c_str(), reply);
756cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
757cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
758cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
759cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'tear':
760cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
761cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
762cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
763cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
764df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                ALOGI("TEARDOWN completed with result %d (%s)",
7656e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
766cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
767cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<AMessage> reply = new AMessage('disc', id());
7687aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
7697aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                int32_t reconnect;
7707aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
7717aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    reply->setInt32("reconnect", true);
7727aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
7737aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
774cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConn->disconnect(reply);
775cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
776cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
777cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
778cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'quit':
779cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
7802bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                sp<AMessage> msg = mNotify->dup();
7812bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                msg->setInt32("what", kWhatDisconnected);
7822bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                msg->setInt32("result", UNKNOWN_ERROR);
7832bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                msg->post();
784cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
785cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
786cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
7878d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            case 'chek':
7888d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            {
789a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                int32_t generation;
790a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                CHECK(msg->findInt32("generation", &generation));
791a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                if (generation != mCheckGeneration) {
792a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                    // This is an outdated message. Ignore.
793a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                    break;
794a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                }
795a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
7968d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                if (mNumAccessUnitsReceived == 0) {
79791f230461288a2a5091182ef9e17079aabf8ebaaAndreas Huber#if 1
798df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                    ALOGI("stream ended? aborting.");
7998d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    (new AMessage('abor', id()))->post();
8008d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    break;
801f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber#else
802df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                    ALOGI("haven't seen an AU in a looong time.");
803f0c86a83c687074be79397e082e3775ca56641b1Andreas Huber#endif
8048d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
8058d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
8068d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                mNumAccessUnitsReceived = 0;
807e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber                msg->post(kAccessUnitTimeoutUs);
8088d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                break;
8098d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            }
8108d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
811cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'accu':
812cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
813100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                int32_t timeUpdate;
814100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                if (msg->findInt32("time-update", &timeUpdate) && timeUpdate) {
815100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    size_t trackIndex;
816100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    CHECK(msg->findSize("track-index", &trackIndex));
817100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
818100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    uint32_t rtpTime;
819100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    uint64_t ntpTime;
820100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    CHECK(msg->findInt32("rtp-time", (int32_t *)&rtpTime));
821100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    CHECK(msg->findInt64("ntp-time", (int64_t *)&ntpTime));
822100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
823100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    onTimeUpdate(trackIndex, rtpTime, ntpTime);
824100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    break;
825100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                }
826100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
827f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                int32_t first;
828f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                if (msg->findInt32("first-rtcp", &first)) {
829e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    mReceivedFirstRTCPPacket = true;
830e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    break;
831e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                }
832e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
833f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                if (msg->findInt32("first-rtp", &first)) {
834f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                    mReceivedFirstRTPPacket = true;
835f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                    break;
836f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                }
837f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber
8388d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                ++mNumAccessUnitsReceived;
839a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                postAccessUnitTimeoutCheck();
8408d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
841cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                size_t trackIndex;
842cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findSize("track-index", &trackIndex));
843cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
8447aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (trackIndex >= mTracks.size()) {
8453856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                    ALOGV("late packets ignored.");
8467aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    break;
8477aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
8487aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
8498d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                TrackInfo *track = &mTracks.editItemAt(trackIndex);
8508d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
851ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                int32_t eos;
852ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                if (msg->findInt32("eos", &eos)) {
853df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                    ALOGI("received BYE on track index %d", trackIndex);
854ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber#if 0
855ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                    track->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
856ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber#endif
857ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                    return;
858ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                }
859ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber
8602d8bedd05437b6fccdbc6bf70f673ffd86744d59Andreas Huber                sp<ABuffer> accessUnit;
8612d8bedd05437b6fccdbc6bf70f673ffd86744d59Andreas Huber                CHECK(msg->findBuffer("access-unit", &accessUnit));
862cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
8638d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                uint32_t seqNum = (uint32_t)accessUnit->int32Data();
8648d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
8656f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (mSeekPending) {
8663856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                    ALOGV("we're seeking, dropping stale packet.");
8676f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    break;
8686f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
8696f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber
8708d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                if (seqNum < track->mFirstSeqNumInSegment) {
8713856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                    ALOGV("dropping stale access-unit (%d < %d)",
8726e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                         seqNum, track->mFirstSeqNumInSegment);
8738d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    break;
8748d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
8758d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
8768d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                if (track->mNewSegment) {
8778d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    track->mNewSegment = false;
8788d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
8798d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
880100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                onAccessUnitComplete(trackIndex, accessUnit);
881cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
882cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
883cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
884cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            case 'seek':
885cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            {
8860dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                if (!mSeekable) {
8875ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block                    ALOGW("This is a live stream, ignoring seek request.");
8882bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
8892bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                    sp<AMessage> msg = mNotify->dup();
8902bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                    msg->setInt32("what", kWhatSeekDone);
8912bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                    msg->post();
892cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                    break;
893cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                }
894cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
895cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                int64_t timeUs;
896cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(msg->findInt64("time", &timeUs));
897cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
898cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                mSeekPending = true;
899cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
900a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                // Disable the access unit timeout until we resumed
901a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                // playback again.
902a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                mCheckPending = true;
903a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                ++mCheckGeneration;
904a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
905cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                AString request = "PAUSE ";
906cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionURL);
907cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(" RTSP/1.0\r\n");
908cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
909cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("Session: ");
910cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionID);
911cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
912cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
913cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
914cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
915cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                sp<AMessage> reply = new AMessage('see1', id());
916cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                reply->setInt64("time", timeUs);
917cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                mConn->sendRequest(request.c_str(), reply);
918cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                break;
919cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            }
920cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
921cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            case 'see1':
922cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            {
9238d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                // Session is paused now.
9248d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
925100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    TrackInfo *info = &mTracks.editItemAt(i);
926100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
9272bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                    postQueueSeekDiscontinuity(i);
9282bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
929100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    info->mRTPAnchor = 0;
930100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    info->mNTPAnchorUs = -1;
9318d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
9328d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9337e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                mAllTracksHaveTime = false;
934100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                mNTPAnchorUs = -1;
935100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
936cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                int64_t timeUs;
937cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(msg->findInt64("time", &timeUs));
938cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
939cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                AString request = "PLAY ";
940cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionURL);
941cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(" RTSP/1.0\r\n");
942cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
943cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("Session: ");
944cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionID);
945cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
946cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
947cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(
948cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                        StringPrintf(
949cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                            "Range: npt=%lld-\r\n", timeUs / 1000000ll));
950cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
951cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
952cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
953cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                sp<AMessage> reply = new AMessage('see2', id());
954cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                mConn->sendRequest(request.c_str(), reply);
955cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                break;
956cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            }
957cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
958cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            case 'see2':
959cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            {
960cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(mSeekPending);
961cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
962cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                int32_t result;
963cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(msg->findInt32("result", &result));
9648d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
965df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                ALOGI("PLAY completed with result %d (%s)",
9666e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
9678d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
968a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                mCheckPending = false;
969a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                postAccessUnitTimeoutCheck();
970a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
9716f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (result == OK) {
9726f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    sp<RefBase> obj;
9736f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    CHECK(msg->findObject("response", &obj));
9746f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    sp<ARTSPResponse> response =
9756f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
976cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
9776f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    if (response->mStatusCode != 200) {
9786f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        result = UNKNOWN_ERROR;
9796f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    } else {
9806f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        parsePlayResponse(response);
981cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
982100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                        ssize_t i = response->mHeaders.indexOfKey("rtp-info");
983100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                        CHECK_GE(i, 0);
984100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
9853856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                        ALOGV("rtp-info: %s", response->mHeaders.valueAt(i).c_str());
986100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
987df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block                        ALOGI("seek completed.");
9886f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    }
9896f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
990cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
9916f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (result != OK) {
99229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("seek failed, aborting.");
9936f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    (new AMessage('abor', id()))->post();
9946f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
9958d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9968d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                mSeekPending = false;
9970dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
9982bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                sp<AMessage> msg = mNotify->dup();
9992bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                msg->setInt32("what", kWhatSeekDone);
10002bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                msg->post();
1001cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                break;
1002cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            }
1003cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
10040792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            case 'biny':
10050792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            {
10062d8bedd05437b6fccdbc6bf70f673ffd86744d59Andreas Huber                sp<ABuffer> buffer;
10072d8bedd05437b6fccdbc6bf70f673ffd86744d59Andreas Huber                CHECK(msg->findBuffer("buffer", &buffer));
10080792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
10090792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                int32_t index;
10100792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                CHECK(buffer->meta()->findInt32("index", &index));
10110792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
10120792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                mRTPConn->injectPacket(index, buffer);
10130792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                break;
10140792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            }
10150792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
10160792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            case 'tiou':
10170792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            {
1018e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (!mReceivedFirstRTCPPacket) {
1019dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                    if (mReceivedFirstRTPPacket && !mTryFakeRTCP) {
10205ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block                        ALOGW("We received RTP packets but no RTCP packets, "
1021f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                             "using fake timestamps.");
1022f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber
1023f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                        mTryFakeRTCP = true;
1024f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber
1025f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber                        mReceivedFirstRTCPPacket = true;
1026dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
1027dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                        fakeTimestamps();
1028dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                    } else if (!mReceivedFirstRTPPacket && !mTryTCPInterleaving) {
10295ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block                        ALOGW("Never received any data, switching transports.");
10307aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
10317aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        mTryTCPInterleaving = true;
10327aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
10337aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        sp<AMessage> msg = new AMessage('abor', id());
10347aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        msg->setInt32("reconnect", true);
10357aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        msg->post();
1036dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                    } else {
10375ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block                        ALOGW("Never received any data, disconnecting.");
1038dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber                        (new AMessage('abor', id()))->post();
10397aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    }
10407e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                } else {
10417e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                    if (!mAllTracksHaveTime) {
10427e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                        ALOGW("We received some RTCP packets, but time "
10437e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                              "could not be established on all tracks, now "
10447e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                              "using fake timestamps");
10457e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber
10467e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                        fakeTimestamps();
10477e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                    }
10480792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                }
10490792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                break;
10500792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            }
10510792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
1052cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            default:
1053cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                TRESPASS();
1054cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
1055cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1056cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
1057cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1058908dbdee96856693decc04fa143c2ba525495d43Andreas Huber    void postKeepAlive() {
1059908dbdee96856693decc04fa143c2ba525495d43Andreas Huber        sp<AMessage> msg = new AMessage('aliv', id());
1060908dbdee96856693decc04fa143c2ba525495d43Andreas Huber        msg->setInt32("generation", mKeepAliveGeneration);
1061908dbdee96856693decc04fa143c2ba525495d43Andreas Huber        msg->post((mKeepAliveTimeoutUs * 9) / 10);
1062908dbdee96856693decc04fa143c2ba525495d43Andreas Huber    }
1063908dbdee96856693decc04fa143c2ba525495d43Andreas Huber
1064a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber    void postAccessUnitTimeoutCheck() {
1065a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        if (mCheckPending) {
1066a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber            return;
1067a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        }
1068a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
1069a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        mCheckPending = true;
1070a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        sp<AMessage> check = new AMessage('chek', id());
1071a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        check->setInt32("generation", mCheckGeneration);
1072a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        check->post(kAccessUnitTimeoutUs);
1073a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber    }
1074a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
10758d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    static void SplitString(
10768d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            const AString &s, const char *separator, List<AString> *items) {
10778d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        items->clear();
10788d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        size_t start = 0;
10798d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        while (start < s.size()) {
10808d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            ssize_t offset = s.find(separator, start);
10818d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10828d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            if (offset < 0) {
10838d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                items->push_back(AString(s, start, s.size() - start));
10848d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                break;
10858d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            }
10868d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10878d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            items->push_back(AString(s, start, offset - start));
10888d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            start = offset + strlen(separator);
10898d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
10908d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    }
10918d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10928d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    void parsePlayResponse(const sp<ARTSPResponse> &response) {
10930dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber        mSeekable = false;
10940dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
10958d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        ssize_t i = response->mHeaders.indexOfKey("range");
10968d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        if (i < 0) {
10978d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            // Server doesn't even tell use what range it is going to
10988d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            // play, therefore we won't support seeking.
10998d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            return;
11008d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
11018d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11028d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        AString range = response->mHeaders.valueAt(i);
11033856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Range: %s", range.c_str());
11048d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11058d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        AString val;
11068d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        CHECK(GetAttribute(range.c_str(), "npt", &val));
11078d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
1108783e5cd85d4bd40b1a04dfdfed256c5dcb2525ccAndreas Huber        float npt1, npt2;
1109783e5cd85d4bd40b1a04dfdfed256c5dcb2525ccAndreas Huber        if (!ASessionDescription::parseNTPRange(val.c_str(), &npt1, &npt2)) {
11108d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            // This is a live stream and therefore not seekable.
11111906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber
1112df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("This is a live stream");
1113ac5767a96df9fae46a37ffba62611472135a0f6dAndreas Huber            return;
11148d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
11158d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11168d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        i = response->mHeaders.indexOfKey("rtp-info");
11178d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        CHECK_GE(i, 0);
11188d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11198d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        AString rtpInfo = response->mHeaders.valueAt(i);
11208d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        List<AString> streamInfos;
11218d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        SplitString(rtpInfo, ",", &streamInfos);
11228d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11238d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        int n = 1;
11248d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        for (List<AString>::iterator it = streamInfos.begin();
11258d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber             it != streamInfos.end(); ++it) {
11268d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            (*it).trim();
11273856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("streamInfo[%d] = %s", n, (*it).c_str());
11288d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11298d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK(GetAttribute((*it).c_str(), "url", &val));
11308d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11318d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            size_t trackIndex = 0;
11328d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            while (trackIndex < mTracks.size()
11338d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    && !(val == mTracks.editItemAt(trackIndex).mURL)) {
11348d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                ++trackIndex;
11358d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            }
11368d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK_LT(trackIndex, mTracks.size());
11378d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11388d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK(GetAttribute((*it).c_str(), "seq", &val));
11398d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11408d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            char *end;
11418d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            unsigned long seq = strtoul(val.c_str(), &end, 10);
11428d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11438d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            TrackInfo *info = &mTracks.editItemAt(trackIndex);
11448d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            info->mFirstSeqNumInSegment = seq;
11458d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            info->mNewSegment = true;
11468d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11478d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK(GetAttribute((*it).c_str(), "rtptime", &val));
11488d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11498d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            uint32_t rtpTime = strtoul(val.c_str(), &end, 10);
11508d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11513856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("track #%d: rtpTime=%u <=> npt=%.2f", n, rtpTime, npt1);
11528d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11532bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            info->mNormalPlayTimeRTP = rtpTime;
11542bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            info->mNormalPlayTimeUs = (int64_t)(npt1 * 1E6);
11552bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
11562bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            if (!mFirstAccessUnit) {
11572bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                postNormalPlayTimeMapping(
11582bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                        trackIndex,
11592bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                        info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
11602bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            }
11618d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11628d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            ++n;
11638d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
11640dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
1165ac5767a96df9fae46a37ffba62611472135a0f6dAndreas Huber        mSeekable = true;
11668d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    }
11678d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
11682bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    sp<MetaData> getTrackFormat(size_t index, int32_t *timeScale) {
1169cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK_GE(index, 0u);
1170cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK_LT(index, mTracks.size());
1171cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
11722bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        const TrackInfo &info = mTracks.itemAt(index);
11732bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
11742bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        *timeScale = info.mTimeScale;
11752bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
11762bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        return info.mPacketSource->getFormat();
1177cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
1178cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1179cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    size_t countTracks() const {
1180cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        return mTracks.size();
1181cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
1182cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1183cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huberprivate:
1184100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    struct TrackInfo {
1185100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        AString mURL;
1186100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int mRTPSocket;
1187100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int mRTCPSocket;
1188100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        bool mUsingInterleavedTCP;
1189100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        uint32_t mFirstSeqNumInSegment;
1190100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        bool mNewSegment;
1191100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1192100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        uint32_t mRTPAnchor;
1193100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int64_t mNTPAnchorUs;
1194100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int32_t mTimeScale;
1195100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
11962bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        uint32_t mNormalPlayTimeRTP;
11972bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        int64_t mNormalPlayTimeUs;
11982bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
1199100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        sp<APacketSource> mPacketSource;
1200100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1201100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        // Stores packets temporarily while no notion of time
1202100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        // has been established yet.
1203100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        List<sp<ABuffer> > mPackets;
1204100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    };
1205100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
12062bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    sp<AMessage> mNotify;
12079b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber    bool mUIDValid;
12089b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber    uid_t mUID;
1209348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber    sp<ALooper> mNetLooper;
1210cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ARTSPConnection> mConn;
1211cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ARTPConnection> mRTPConn;
1212cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ASessionDescription> mSessionDesc;
12134579b7d49f6dd4f37e6043e59debfd72d69b8e7bAndreas Huber    AString mOriginalSessionURL;  // This one still has user:pass@
1214cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mSessionURL;
1215de9a20c274983d4f7a688acb68d5dfc6a432eb10Andreas Huber    AString mSessionHost;
1216cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mBaseURL;
1217cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mSessionID;
1218cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    bool mSetupTracksSuccessful;
1219cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber    bool mSeekPending;
1220cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber    bool mFirstAccessUnit;
1221100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
12227e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber    bool mAllTracksHaveTime;
1223100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    int64_t mNTPAnchorUs;
1224100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    int64_t mMediaAnchorUs;
1225100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    int64_t mLastMediaTimeUs;
1226100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
12278d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    int64_t mNumAccessUnitsReceived;
12288d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    bool mCheckPending;
1229a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber    int32_t mCheckGeneration;
12307aef03379179c109c2547c33c410bfc93c8db576Andreas Huber    bool mTryTCPInterleaving;
1231f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber    bool mTryFakeRTCP;
1232e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber    bool mReceivedFirstRTCPPacket;
1233f61551f4fc79e7da879802e3974afa9b03ffb5d0Andreas Huber    bool mReceivedFirstRTPPacket;
12340dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber    bool mSeekable;
1235908dbdee96856693decc04fa143c2ba525495d43Andreas Huber    int64_t mKeepAliveTimeoutUs;
1236908dbdee96856693decc04fa143c2ba525495d43Andreas Huber    int32_t mKeepAliveGeneration;
1237cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1238cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    Vector<TrackInfo> mTracks;
1239cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1240cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    void setupTrack(size_t index) {
124139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        sp<APacketSource> source =
124239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            new APacketSource(mSessionDesc, index);
12437aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
124439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (source->initCheck() != OK) {
12455ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block            ALOGW("Unsupported format. Ignoring track #%d.", index);
124639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
124739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            sp<AMessage> reply = new AMessage('setu', id());
124839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            reply->setSize("index", index);
124939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            reply->setInt32("result", ERROR_UNSUPPORTED);
125039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            reply->post();
125139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            return;
125239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
125339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
1254cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString url;
1255cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK(mSessionDesc->findAttribute(index, "a=control", &url));
1256cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1257cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString trackURL;
1258cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK(MakeURL(mBaseURL.c_str(), url.c_str(), &trackURL));
1259cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1260cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mTracks.push(TrackInfo());
1261cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1);
12628d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        info->mURL = trackURL;
126339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        info->mPacketSource = source;
12640792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber        info->mUsingInterleavedTCP = false;
12658d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        info->mFirstSeqNumInSegment = 0;
12668d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        info->mNewSegment = true;
1267100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        info->mRTPAnchor = 0;
1268100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        info->mNTPAnchorUs = -1;
12692bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        info->mNormalPlayTimeRTP = 0;
12702bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        info->mNormalPlayTimeUs = 0ll;
1271100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1272100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        unsigned long PT;
1273100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        AString formatDesc;
1274100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        AString formatParams;
1275100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        mSessionDesc->getFormatType(index, &PT, &formatDesc, &formatParams);
1276100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1277100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int32_t timescale;
1278100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int32_t numChannels;
1279100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        ASessionDescription::ParseFormatDesc(
1280100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                formatDesc.c_str(), &timescale, &numChannels);
1281100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1282100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        info->mTimeScale = timescale;
12838d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
12843856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("track #%d URL=%s", mTracks.size(), trackURL.c_str());
1285cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1286cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString request = "SETUP ";
1287cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append(trackURL);
1288cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append(" RTSP/1.0\r\n");
1289cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
12907aef03379179c109c2547c33c410bfc93c8db576Andreas Huber        if (mTryTCPInterleaving) {
12917aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            size_t interleaveIndex = 2 * (mTracks.size() - 1);
12927aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            info->mUsingInterleavedTCP = true;
12937aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            info->mRTPSocket = interleaveIndex;
12947aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            info->mRTCPSocket = interleaveIndex + 1;
12957aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
12967aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("Transport: RTP/AVP/TCP;interleaved=");
12977aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(interleaveIndex);
12987aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("-");
12997aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(interleaveIndex + 1);
13007aef03379179c109c2547c33c410bfc93c8db576Andreas Huber        } else {
13017aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            unsigned rtpPort;
13027aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            ARTPConnection::MakePortPair(
13037aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    &info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
13047aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
13059b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber            if (mUIDValid) {
1306a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                HTTPBase::RegisterSocketUserTag(info->mRTPSocket, mUID,
1307a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                                                (uint32_t)*(uint32_t*) "RTP_");
1308a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                HTTPBase::RegisterSocketUserTag(info->mRTCPSocket, mUID,
1309a23456b306f35b9ecf973bf5818ca39295e9e029Ashish Sharma                                                (uint32_t)*(uint32_t*) "RTP_");
13109b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber            }
13119b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber
13127aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
13137aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(rtpPort);
13147aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("-");
13157aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(rtpPort + 1);
13167aef03379179c109c2547c33c410bfc93c8db576Andreas Huber        }
13170792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
1318cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append("\r\n");
1319cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1320cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (index > 1) {
1321cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            request.append("Session: ");
1322cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            request.append(mSessionID);
1323cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            request.append("\r\n");
1324cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1325cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1326cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append("\r\n");
1327cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1328cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sp<AMessage> reply = new AMessage('setu', id());
1329cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        reply->setSize("index", index);
1330cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        reply->setSize("track-index", mTracks.size() - 1);
1331cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mConn->sendRequest(request.c_str(), reply);
1332cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
1333cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1334cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    static bool MakeURL(const char *baseURL, const char *url, AString *out) {
1335cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        out->clear();
1336cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1337cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (strncasecmp("rtsp://", baseURL, 7)) {
1338cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            // Base URL must be absolute
1339cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            return false;
1340cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1341cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1342cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (!strncasecmp("rtsp://", url, 7)) {
1343cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            // "url" is already an absolute URL, ignore base URL.
1344cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->setTo(url);
1345cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            return true;
1346cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1347cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1348cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        size_t n = strlen(baseURL);
1349cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (baseURL[n - 1] == '/') {
1350cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->setTo(baseURL);
1351cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->append(url);
1352cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        } else {
13534e2ffa400b82559cab2c5717c8dcdff393d334a9Mike Lockwood            const char *slashPos = strrchr(baseURL, '/');
1354cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1355cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            if (slashPos > &baseURL[6]) {
1356cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                out->setTo(baseURL, slashPos - baseURL);
1357cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            } else {
1358cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                out->setTo(baseURL);
1359cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
1360cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1361cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->append("/");
1362cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->append(url);
1363cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1364cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1365cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        return true;
1366cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
1367cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1368dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber    void fakeTimestamps() {
13697e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber        mNTPAnchorUs = -1ll;
1370dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        for (size_t i = 0; i < mTracks.size(); ++i) {
1371dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber            onTimeUpdate(i, 0, 0ll);
1372dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber        }
1373dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber    }
1374dc468c5f9d72ce54de0070493e9a23efb8907e06Andreas Huber
1375100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    void onTimeUpdate(int32_t trackIndex, uint32_t rtpTime, uint64_t ntpTime) {
13763856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("onTimeUpdate track %d, rtpTime = 0x%08x, ntpTime = 0x%016llx",
1377100a4408968b90e314526185d572c72ea4cc784aAndreas Huber             trackIndex, rtpTime, ntpTime);
1378100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1379100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int64_t ntpTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
1380100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1381100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        TrackInfo *track = &mTracks.editItemAt(trackIndex);
1382100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1383100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        track->mRTPAnchor = rtpTime;
1384100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        track->mNTPAnchorUs = ntpTimeUs;
1385100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1386100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        if (mNTPAnchorUs < 0) {
1387100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            mNTPAnchorUs = ntpTimeUs;
1388100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            mMediaAnchorUs = mLastMediaTimeUs;
1389100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
13907e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber
13917e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber        if (!mAllTracksHaveTime) {
13927e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber            bool allTracksHaveTime = true;
13937e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber            for (size_t i = 0; i < mTracks.size(); ++i) {
13947e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                TrackInfo *track = &mTracks.editItemAt(i);
13957e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                if (track->mNTPAnchorUs < 0) {
13967e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                    allTracksHaveTime = false;
13977e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                    break;
13987e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                }
13997e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber            }
14007e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber            if (allTracksHaveTime) {
14017e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                mAllTracksHaveTime = true;
14027e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber                ALOGI("Time now established for all tracks.");
14037e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber            }
14047e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber        }
1405100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    }
1406100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1407100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    void onAccessUnitComplete(
1408100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            int32_t trackIndex, const sp<ABuffer> &accessUnit) {
14093856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("onAccessUnitComplete track %d", trackIndex);
1410100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1411100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        if (mFirstAccessUnit) {
14122bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            sp<AMessage> msg = mNotify->dup();
14132bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            msg->setInt32("what", kWhatConnected);
14142bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            msg->post();
14152bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
14161906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber            if (mSeekable) {
14171906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
14181906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                    TrackInfo *info = &mTracks.editItemAt(i);
14192bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
14201906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                    postNormalPlayTimeMapping(
14211906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                            i,
14221906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                            info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
14231906e5c7492b9cbc88601365536a69e9a490c963Andreas Huber                }
14242bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            }
1425100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1426100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            mFirstAccessUnit = false;
1427100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1428100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1429100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        TrackInfo *track = &mTracks.editItemAt(trackIndex);
1430100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
14317e73e44c2d2208a7079e562f7b0b9b73ef6a29f1Andreas Huber        if (!mAllTracksHaveTime) {
14323856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("storing accessUnit, no time established yet");
1433100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            track->mPackets.push_back(accessUnit);
1434100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            return;
1435100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1436100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1437100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        while (!track->mPackets.empty()) {
1438100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            sp<ABuffer> accessUnit = *track->mPackets.begin();
1439100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            track->mPackets.erase(track->mPackets.begin());
1440100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1441100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            if (addMediaTimestamp(trackIndex, track, accessUnit)) {
14422bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber                postQueueAccessUnit(trackIndex, accessUnit);
1443100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            }
1444100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1445100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1446100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        if (addMediaTimestamp(trackIndex, track, accessUnit)) {
14472bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            postQueueAccessUnit(trackIndex, accessUnit);
1448100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1449100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    }
1450100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1451100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    bool addMediaTimestamp(
1452100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            int32_t trackIndex, const TrackInfo *track,
1453100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            const sp<ABuffer> &accessUnit) {
1454100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        uint32_t rtpTime;
1455100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        CHECK(accessUnit->meta()->findInt32(
1456100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                    "rtp-time", (int32_t *)&rtpTime));
1457100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1458100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int64_t relRtpTimeUs =
1459100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            (((int64_t)rtpTime - (int64_t)track->mRTPAnchor) * 1000000ll)
1460100a4408968b90e314526185d572c72ea4cc784aAndreas Huber                / track->mTimeScale;
1461100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1462100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int64_t ntpTimeUs = track->mNTPAnchorUs + relRtpTimeUs;
1463100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1464100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        int64_t mediaTimeUs = mMediaAnchorUs + ntpTimeUs - mNTPAnchorUs;
1465100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1466100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        if (mediaTimeUs > mLastMediaTimeUs) {
1467100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            mLastMediaTimeUs = mediaTimeUs;
1468100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1469100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1470100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        if (mediaTimeUs < 0) {
14713856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("dropping early accessUnit.");
1472100a4408968b90e314526185d572c72ea4cc784aAndreas Huber            return false;
1473100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        }
1474100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
14753856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("track %d rtpTime=%d mediaTimeUs = %lld us (%.2f secs)",
1476100a4408968b90e314526185d572c72ea4cc784aAndreas Huber             trackIndex, rtpTime, mediaTimeUs, mediaTimeUs / 1E6);
1477100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1478100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        accessUnit->meta()->setInt64("timeUs", mediaTimeUs);
1479100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1480100a4408968b90e314526185d572c72ea4cc784aAndreas Huber        return true;
1481100a4408968b90e314526185d572c72ea4cc784aAndreas Huber    }
1482100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
14832bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    void postQueueAccessUnit(
14842bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            size_t trackIndex, const sp<ABuffer> &accessUnit) {
14852bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        sp<AMessage> msg = mNotify->dup();
14862bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->setInt32("what", kWhatAccessUnit);
14872bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->setSize("trackIndex", trackIndex);
14882d8bedd05437b6fccdbc6bf70f673ffd86744d59Andreas Huber        msg->setBuffer("accessUnit", accessUnit);
14892bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->post();
14902bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
14912bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
14922bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    void postQueueEOS(size_t trackIndex, status_t finalResult) {
14932bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        sp<AMessage> msg = mNotify->dup();
14942bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->setInt32("what", kWhatEOS);
14952bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->setSize("trackIndex", trackIndex);
14962bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->setInt32("finalResult", finalResult);
14972bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->post();
14982bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
14992bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
15002bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    void postQueueSeekDiscontinuity(size_t trackIndex) {
15012bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        sp<AMessage> msg = mNotify->dup();
15022bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->setInt32("what", kWhatSeekDiscontinuity);
15032bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->setSize("trackIndex", trackIndex);
15042bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->post();
15052bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
15062bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber
15072bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    void postNormalPlayTimeMapping(
15082bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber            size_t trackIndex, uint32_t rtpTime, int64_t nptUs) {
15092bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        sp<AMessage> msg = mNotify->dup();
15102bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->setInt32("what", kWhatNormalPlayTimeMapping);
15112bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->setSize("trackIndex", trackIndex);
15122bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->setInt32("rtpTime", rtpTime);
15132bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->setInt64("nptUs", nptUs);
15142bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber        msg->post();
15152bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber    }
1516100a4408968b90e314526185d572c72ea4cc784aAndreas Huber
1517cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    DISALLOW_EVIL_CONSTRUCTORS(MyHandler);
1518cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber};
1519cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1520cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber}  // namespace android
1521cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1522cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif  // MY_HANDLER_H_
1523