17a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber/*
27a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * Copyright (C) 2010 The Android Open Source Project
37a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber *
47a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
57a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * you may not use this file except in compliance with the License.
67a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * You may obtain a copy of the License at
77a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber *
87a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
97a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber *
107a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * Unless required by applicable law or agreed to in writing, software
117a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
127a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * See the License for the specific language governing permissions and
147a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * limitations under the License.
157a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber */
167a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
177a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#ifndef MY_HANDLER_H_
187a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
197a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#define MY_HANDLER_H_
207a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
216e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber//#define LOG_NDEBUG 0
226e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber#define LOG_TAG "MyHandler"
236e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber#include <utils/Log.h>
246e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber
257a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include "APacketSource.h"
267a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include "ARTPConnection.h"
277a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include "ARTSPConnection.h"
287a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include "ASessionDescription.h"
297a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
30eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber#include <ctype.h>
310dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber#include <cutils/properties.h>
32eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
337a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include <media/stagefright/foundation/ABuffer.h>
347a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include <media/stagefright/foundation/ADebug.h>
357a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include <media/stagefright/foundation/ALooper.h>
367a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include <media/stagefright/foundation/AMessage.h>
377a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include <media/stagefright/MediaErrors.h>
387a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
390dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber#include <arpa/inet.h>
400dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber#include <sys/socket.h>
4127db53de35bbe83ce3b906da675b065803471481Andreas Huber#include <netdb.h>
420dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
43c3119330a56c2dafa282b0b7450893c3f8cb5636Andreas Huber#include "HTTPBase.h"
44603d739b5a444c52b63f1ec7cd2098034151ad25Andreas Huber
45b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber// If no access units are received within 5 secs, assume that the rtp
46f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber// stream has ended and signal end of stream.
47a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huberstatic int64_t kAccessUnitTimeoutUs = 10000000ll;
48f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber
49f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber// If no access units arrive for the first 10 secs after starting the
50f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber// stream, assume none ever will and signal EOS or switch transports.
51f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huberstatic int64_t kStartupTimeoutUs = 10000000ll;
52f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber
53a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huberstatic int64_t kDefaultKeepAliveTimeoutUs = 60000000ll;
54a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
557a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Hubernamespace android {
567a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
570dc6403f3c660f6e6f1840276e3240365889103dAndreas Huberstatic void MakeUserAgentString(AString *s) {
580dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    s->setTo("stagefright/1.1 (Linux;Android ");
590dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
600dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber#if (PROPERTY_VALUE_MAX < 8)
610dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber#error "PROPERTY_VALUE_MAX must be at least 8"
620dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber#endif
630dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
640dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    char value[PROPERTY_VALUE_MAX];
650dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    property_get("ro.build.version.release", value, "Unknown");
660dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    s->append(value);
670dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    s->append(")");
680dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber}
690dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
70eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huberstatic bool GetAttribute(const char *s, const char *key, AString *value) {
71eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    value->clear();
72eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
73eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    size_t keyLen = strlen(key);
74eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
75eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    for (;;) {
76eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        while (isspace(*s)) {
77eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            ++s;
78eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
79eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
80eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        const char *colonPos = strchr(s, ';');
81eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
82eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        size_t len =
83eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            (colonPos == NULL) ? strlen(s) : colonPos - s;
84eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
85eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
86eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            value->setTo(&s[keyLen + 1], len - keyLen - 1);
87eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            return true;
88eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
89eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
90eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        if (colonPos == NULL) {
91eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            return false;
92eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
93eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
94eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        s = colonPos + 1;
95eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    }
96eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber}
97eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
987a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huberstruct MyHandler : public AHandler {
99a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    enum {
100a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        kWhatConnected                  = 'conn',
101a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        kWhatDisconnected               = 'disc',
102a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        kWhatSeekDone                   = 'sdon',
103a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
104a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        kWhatAccessUnit                 = 'accU',
105a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        kWhatEOS                        = 'eos!',
106a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        kWhatSeekDiscontinuity          = 'seeD',
107a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        kWhatNormalPlayTimeMapping      = 'nptM',
108a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    };
109a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
110603d739b5a444c52b63f1ec7cd2098034151ad25Andreas Huber    MyHandler(
111a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            const char *url,
112a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            const sp<AMessage> &notify,
113603d739b5a444c52b63f1ec7cd2098034151ad25Andreas Huber            bool uidValid = false, uid_t uid = 0)
114a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        : mNotify(notify),
115a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber          mUIDValid(uidValid),
116603d739b5a444c52b63f1ec7cd2098034151ad25Andreas Huber          mUID(uid),
1174e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber          mNetLooper(new ALooper),
118603d739b5a444c52b63f1ec7cd2098034151ad25Andreas Huber          mConn(new ARTSPConnection(mUIDValid, mUID)),
1197a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber          mRTPConn(new ARTPConnection),
120a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber          mOriginalSessionURL(url),
1217a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber          mSessionURL(url),
122e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber          mSetupTracksSuccessful(false),
123e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber          mSeekPending(false),
124e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber          mFirstAccessUnit(true),
125b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber          mNTPAnchorUs(-1),
126b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber          mMediaAnchorUs(-1),
127b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber          mLastMediaTimeUs(0),
128eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber          mNumAccessUnitsReceived(0),
129f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber          mCheckPending(false),
130e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber          mCheckGeneration(0),
1313a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber          mTryTCPInterleaving(false),
132cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber          mTryFakeRTCP(false),
1330c46b69f612da61ed39b32823d2d6baf2e8215e9Andreas Huber          mReceivedFirstRTCPPacket(false),
134cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber          mReceivedFirstRTPPacket(false),
135a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber          mSeekable(false),
136a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber          mKeepAliveTimeoutUs(kDefaultKeepAliveTimeoutUs),
137a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber          mKeepAliveGeneration(0) {
138c4e0b70a21fadb47d70955c71fc31ce1473da925Andreas Huber        mNetLooper->setName("rtsp net");
1394e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber        mNetLooper->start(false /* runOnCallingThread */,
1404e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                          false /* canCallJava */,
1414e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                          PRIORITY_HIGHEST);
142a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber
143a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber        // Strip any authentication info from the session url, we don't
144a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber        // want to transmit user/pass in cleartext.
145a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber        AString host, path, user, pass;
146a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber        unsigned port;
14727db53de35bbe83ce3b906da675b065803471481Andreas Huber        CHECK(ARTSPConnection::ParseURL(
14827db53de35bbe83ce3b906da675b065803471481Andreas Huber                    mSessionURL.c_str(), &host, &port, &path, &user, &pass));
14927db53de35bbe83ce3b906da675b065803471481Andreas Huber
15027db53de35bbe83ce3b906da675b065803471481Andreas Huber        if (user.size() > 0) {
151a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber            mSessionURL.clear();
152a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber            mSessionURL.append("rtsp://");
153a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber            mSessionURL.append(host);
154a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber            mSessionURL.append(":");
155a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber            mSessionURL.append(StringPrintf("%u", port));
156a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber            mSessionURL.append(path);
157a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber
158a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber            LOGI("rewritten session url: '%s'", mSessionURL.c_str());
159a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber        }
16027db53de35bbe83ce3b906da675b065803471481Andreas Huber
16127db53de35bbe83ce3b906da675b065803471481Andreas Huber        mSessionHost = host;
1624e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber    }
1634e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber
164a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    void connect() {
165a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        looper()->registerHandler(mConn);
166a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        (1 ? mNetLooper : looper())->registerHandler(mRTPConn);
1674e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber
1680416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber        sp<AMessage> notify = new AMessage('biny', id());
1690416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber        mConn->observeBinaryData(notify);
1700416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
1718370be11debc574b4a9fee62009009d999e29fa3Andreas Huber        sp<AMessage> reply = new AMessage('conn', id());
172a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber        mConn->connect(mOriginalSessionURL.c_str(), reply);
1737a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
1747a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
175a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    void disconnect() {
1768370be11debc574b4a9fee62009009d999e29fa3Andreas Huber        (new AMessage('abor', id()))->post();
1774e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber    }
1784e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber
179a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    void seek(int64_t timeUs) {
180e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber        sp<AMessage> msg = new AMessage('seek', id());
181e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber        msg->setInt64("time", timeUs);
182e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber        msg->post();
183e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber    }
184e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
1850dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    static void addRR(const sp<ABuffer> &buf) {
1860dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        uint8_t *ptr = buf->data() + buf->size();
1870dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        ptr[0] = 0x80 | 0;
1880dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        ptr[1] = 201;  // RR
1890dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        ptr[2] = 0;
1900dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        ptr[3] = 1;
1910dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        ptr[4] = 0xde;  // SSRC
1920dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        ptr[5] = 0xad;
1930dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        ptr[6] = 0xbe;
1940dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        ptr[7] = 0xef;
1950dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
1960dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        buf->setRange(0, buf->size() + 8);
1970dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    }
1980dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
1990dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    static void addSDES(int s, const sp<ABuffer> &buffer) {
2000dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        struct sockaddr_in addr;
2010dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        socklen_t addrSize = sizeof(addr);
2020dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        CHECK_EQ(0, getsockname(s, (sockaddr *)&addr, &addrSize));
2030dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2040dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        uint8_t *data = buffer->data() + buffer->size();
2050dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[0] = 0x80 | 1;
2060dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[1] = 202;  // SDES
2070dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[4] = 0xde;  // SSRC
2080dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[5] = 0xad;
2090dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[6] = 0xbe;
2100dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[7] = 0xef;
2110dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2120dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        size_t offset = 8;
2130dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2140dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[offset++] = 1;  // CNAME
2150dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2160dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        AString cname = "stagefright@";
2170dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        cname.append(inet_ntoa(addr.sin_addr));
2180dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[offset++] = cname.size();
2190dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2200dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        memcpy(&data[offset], cname.c_str(), cname.size());
2210dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        offset += cname.size();
2220dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2230dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[offset++] = 6;  // TOOL
2240dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2250dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        AString tool;
2260dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        MakeUserAgentString(&tool);
2270dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2280dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[offset++] = tool.size();
2290dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2300dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        memcpy(&data[offset], tool.c_str(), tool.size());
2310dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        offset += tool.size();
2320dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2330dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[offset++] = 0;
2340dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2350dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        if ((offset % 4) > 0) {
2360dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber            size_t count = 4 - (offset % 4);
2370dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber            switch (count) {
2380dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                case 3:
2390dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                    data[offset++] = 0;
2400dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                case 2:
2410dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                    data[offset++] = 0;
2420dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                case 1:
2430dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                    data[offset++] = 0;
2440dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber            }
2450dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        }
2460dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2470dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        size_t numWords = (offset / 4) - 1;
2480dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[2] = numWords >> 8;
2490dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        data[3] = numWords & 0xff;
2500dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2510dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        buffer->setRange(buffer->offset(), buffer->size() + offset);
2520dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    }
2530dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2540dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    // In case we're behind NAT, fire off two UDP packets to the remote
2550dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    // rtp/rtcp ports to poke a hole into the firewall for future incoming
2560dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    // packets. We're going to send an RR/SDES RTCP packet to both of them.
2570407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber    bool pokeAHole(int rtpSocket, int rtcpSocket, const AString &transport) {
25827db53de35bbe83ce3b906da675b065803471481Andreas Huber        struct sockaddr_in addr;
25927db53de35bbe83ce3b906da675b065803471481Andreas Huber        memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
26027db53de35bbe83ce3b906da675b065803471481Andreas Huber        addr.sin_family = AF_INET;
26127db53de35bbe83ce3b906da675b065803471481Andreas Huber
2620dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        AString source;
2630dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        AString server_port;
2640dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        if (!GetAttribute(transport.c_str(),
2650dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                          "source",
26627db53de35bbe83ce3b906da675b065803471481Andreas Huber                          &source)) {
26727db53de35bbe83ce3b906da675b065803471481Andreas Huber            LOGW("Missing 'source' field in Transport response. Using "
26827db53de35bbe83ce3b906da675b065803471481Andreas Huber                 "RTSP endpoint address.");
26927db53de35bbe83ce3b906da675b065803471481Andreas Huber
27027db53de35bbe83ce3b906da675b065803471481Andreas Huber            struct hostent *ent = gethostbyname(mSessionHost.c_str());
27127db53de35bbe83ce3b906da675b065803471481Andreas Huber            if (ent == NULL) {
27227db53de35bbe83ce3b906da675b065803471481Andreas Huber                LOGE("Failed to look up address of session host '%s'",
27327db53de35bbe83ce3b906da675b065803471481Andreas Huber                     mSessionHost.c_str());
27427db53de35bbe83ce3b906da675b065803471481Andreas Huber
27527db53de35bbe83ce3b906da675b065803471481Andreas Huber                return false;
27627db53de35bbe83ce3b906da675b065803471481Andreas Huber            }
27727db53de35bbe83ce3b906da675b065803471481Andreas Huber
27827db53de35bbe83ce3b906da675b065803471481Andreas Huber            addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
27927db53de35bbe83ce3b906da675b065803471481Andreas Huber        } else {
28027db53de35bbe83ce3b906da675b065803471481Andreas Huber            addr.sin_addr.s_addr = inet_addr(source.c_str());
28127db53de35bbe83ce3b906da675b065803471481Andreas Huber        }
28227db53de35bbe83ce3b906da675b065803471481Andreas Huber
28327db53de35bbe83ce3b906da675b065803471481Andreas Huber        if (!GetAttribute(transport.c_str(),
2840dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                                 "server_port",
2850dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                                 &server_port)) {
28627db53de35bbe83ce3b906da675b065803471481Andreas Huber            LOGI("Missing 'server_port' field in Transport response.");
2870407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            return false;
2880dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        }
2890dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
2900dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        int rtpPort, rtcpPort;
2910dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        if (sscanf(server_port.c_str(), "%d-%d", &rtpPort, &rtcpPort) != 2
2920dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                || rtpPort <= 0 || rtpPort > 65535
2930dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                || rtcpPort <=0 || rtcpPort > 65535
2940407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                || rtcpPort != rtpPort + 1) {
2950407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            LOGE("Server picked invalid RTP/RTCP port pair %s,"
2960407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                 " RTP port must be even, RTCP port must be one higher.",
2970407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                 server_port.c_str());
2980407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
2990407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            return false;
3000407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber        }
3010407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
3020407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber        if (rtpPort & 1) {
3030407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            LOGW("Server picked an odd RTP port, it should've picked an "
3040407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                 "even one, we'll let it pass for now, but this may break "
3050407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                 "in the future.");
3060dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        }
3070dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
3080dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        if (addr.sin_addr.s_addr == INADDR_NONE) {
3090407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            return true;
3100407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber        }
3110407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
3120407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber        if (IN_LOOPBACK(ntohl(addr.sin_addr.s_addr))) {
3130407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            // No firewalls to traverse on the loopback interface.
3140407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            return true;
3150dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        }
3160dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
3170dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        // Make up an RR/SDES RTCP packet.
3180dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        sp<ABuffer> buf = new ABuffer(65536);
3190dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        buf->setRange(0, 0);
3200dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        addRR(buf);
3210dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        addSDES(rtpSocket, buf);
3220dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
3230dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        addr.sin_port = htons(rtpPort);
3240dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
3250dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        ssize_t n = sendto(
3260dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                rtpSocket, buf->data(), buf->size(), 0,
3270dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                (const sockaddr *)&addr, sizeof(addr));
3280407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
3290407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber        if (n < (ssize_t)buf->size()) {
3300407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            LOGE("failed to poke a hole for RTP packets");
3310407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            return false;
3320407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber        }
3330dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
3340dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        addr.sin_port = htons(rtcpPort);
3350dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
3360dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        n = sendto(
3370dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                rtcpSocket, buf->data(), buf->size(), 0,
3380dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                (const sockaddr *)&addr, sizeof(addr));
3390407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
3400407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber        if (n < (ssize_t)buf->size()) {
3410407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            LOGE("failed to poke a hole for RTCP packets");
3420407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            return false;
3430407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber        }
3440dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
3450dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber        LOGV("successfully poked holes.");
3460407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
3470407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber        return true;
3480dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber    }
3490dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
3507a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    virtual void onMessageReceived(const sp<AMessage> &msg) {
3517a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        switch (msg->what()) {
3527a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'conn':
3537a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
3547a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                int32_t result;
3557a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findInt32("result", &result));
3567a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3576e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                LOGI("connection request completed with result %d (%s)",
3586e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                     result, strerror(-result));
3597a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3607a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                if (result == OK) {
3617a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    AString request;
3627a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request = "DESCRIBE ";
3637a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append(mSessionURL);
3647a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append(" RTSP/1.0\r\n");
3657a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append("Accept: application/sdp\r\n");
3667a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append("\r\n");
3677a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3687a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<AMessage> reply = new AMessage('desc', id());
3697a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    mConn->sendRequest(request.c_str(), reply);
3700416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                } else {
3710416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                    (new AMessage('disc', id()))->post();
3727a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
3737a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
3747a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
3757a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3767a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'disc':
3777a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
378a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                ++mKeepAliveGeneration;
379a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
380f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                int32_t reconnect;
381f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
382f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    sp<AMessage> reply = new AMessage('conn', id());
383a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber                    mConn->connect(mOriginalSessionURL.c_str(), reply);
384f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                } else {
385f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    (new AMessage('quit', id()))->post();
386f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                }
3877a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
3887a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
3897a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3907a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'desc':
3917a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
3927a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                int32_t result;
3937a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findInt32("result", &result));
3947a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3956e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                LOGI("DESCRIBE completed with result %d (%s)",
3966e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                     result, strerror(-result));
3977a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3987a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                if (result == OK) {
3997a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<RefBase> obj;
4007a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    CHECK(msg->findObject("response", &obj));
4017a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<ARTSPResponse> response =
4027a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
4037a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4047a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    if (response->mStatusCode == 302) {
4057a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        ssize_t i = response->mHeaders.indexOfKey("location");
4067a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        CHECK_GE(i, 0);
4077a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4087a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        mSessionURL = response->mHeaders.valueAt(i);
4097a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4107a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        AString request;
4117a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        request = "DESCRIBE ";
4127a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        request.append(mSessionURL);
4137a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        request.append(" RTSP/1.0\r\n");
4147a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        request.append("Accept: application/sdp\r\n");
4157a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        request.append("\r\n");
4167a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4177a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        sp<AMessage> reply = new AMessage('desc', id());
4187a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        mConn->sendRequest(request.c_str(), reply);
4197a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        break;
4207a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    }
4217a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4223a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    if (response->mStatusCode != 200) {
4233a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        result = UNKNOWN_ERROR;
4243a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    } else {
4253a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        mSessionDesc = new ASessionDescription;
4267a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4273a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        mSessionDesc->setTo(
4283a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                                response->mContent->data(),
4293a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                                response->mContent->size());
4307a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
431f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        if (!mSessionDesc->isValid()) {
4320407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                            LOGE("Failed to parse session description.");
433f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                            result = ERROR_MALFORMED;
4347a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        } else {
435f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                            ssize_t i = response->mHeaders.indexOfKey("content-base");
4363a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                            if (i >= 0) {
4373a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                                mBaseURL = response->mHeaders.valueAt(i);
4383a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                            } else {
439f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                i = response->mHeaders.indexOfKey("content-location");
440f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                if (i >= 0) {
441f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                    mBaseURL = response->mHeaders.valueAt(i);
442f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                } else {
443f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                    mBaseURL = mSessionURL;
444f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                }
4453a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                            }
4463a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber
4470407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                            if (!mBaseURL.startsWith("rtsp://")) {
4480407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                // Some misbehaving servers specify a relative
4490407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                // URL in one of the locations above, combine
4500407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                // it with the absolute session URL to get
4510407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                // something usable...
4520407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
4530407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                LOGW("Server specified a non-absolute base URL"
4540407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                     ", combining it with the session URL to "
4550407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                     "get something usable...");
4560407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
4570407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                AString tmp;
4580407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                CHECK(MakeURL(
4590407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                            mSessionURL.c_str(),
4600407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                            mBaseURL.c_str(),
4610407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                            &tmp));
4620407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
4630407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                                mBaseURL = tmp;
4640407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                            }
4650407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
46657cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber                            if (mSessionDesc->countTracks() < 2) {
46757cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber                                // There's no actual tracks in this session.
46857cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber                                // The first "track" is merely session meta
46957cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber                                // data.
47057cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber
47157cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber                                LOGW("Session doesn't contain any playable "
47257cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber                                     "tracks. Aborting.");
47357cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber                                result = ERROR_UNSUPPORTED;
47457cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber                            } else {
47557cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber                                setupTrack(1);
47657cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber                            }
477f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        }
4787a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    }
4793a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                }
4807a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4813a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                if (result != OK) {
4827a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
4837a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    mConn->disconnect(reply);
4847a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
4857a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
4867a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
4877a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4887a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'setu':
4897a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
4907a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                size_t index;
4917a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findSize("index", &index));
4927a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
49357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                TrackInfo *track = NULL;
4947a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                size_t trackIndex;
49557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                if (msg->findSize("track-index", &trackIndex)) {
49657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                    track = &mTracks.editItemAt(trackIndex);
49757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                }
4987a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4997a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                int32_t result;
5007a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findInt32("result", &result));
5017a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
5026e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                LOGI("SETUP(%d) completed with result %d (%s)",
5036e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                     index, result, strerror(-result));
5047a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
5053a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                if (result == OK) {
50657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                    CHECK(track != NULL);
5077a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
5087a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<RefBase> obj;
5097a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    CHECK(msg->findObject("response", &obj));
5107a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<ARTSPResponse> response =
5117a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
5127a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
5133a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    if (response->mStatusCode != 200) {
5143a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        result = UNKNOWN_ERROR;
5153a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    } else {
5163a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        ssize_t i = response->mHeaders.indexOfKey("session");
5173a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        CHECK_GE(i, 0);
5187a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
5197a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        mSessionID = response->mHeaders.valueAt(i);
520a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
521a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                        mKeepAliveTimeoutUs = kDefaultKeepAliveTimeoutUs;
522a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                        AString timeoutStr;
523a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                        if (GetAttribute(
524a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                    mSessionID.c_str(), "timeout", &timeoutStr)) {
525a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                            char *end;
526a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                            unsigned long timeoutSecs =
527a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                strtoul(timeoutStr.c_str(), &end, 10);
528a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
529a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                            if (end == timeoutStr.c_str() || *end != '\0') {
530a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                LOGW("server specified malformed timeout '%s'",
531a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                     timeoutStr.c_str());
532a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
533a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                mKeepAliveTimeoutUs = kDefaultKeepAliveTimeoutUs;
534a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                            } else if (timeoutSecs < 15) {
535a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                LOGW("server specified too short a timeout "
536a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                     "(%lu secs), using default.",
537a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                     timeoutSecs);
538a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
539a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                mKeepAliveTimeoutUs = kDefaultKeepAliveTimeoutUs;
540a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                            } else {
541a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                mKeepAliveTimeoutUs = timeoutSecs * 1000000ll;
542a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
543a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                LOGI("server specified timeout of %lu secs.",
544a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                                     timeoutSecs);
545a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                            }
546a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                        }
547a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
5487a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        i = mSessionID.find(";");
5497a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        if (i >= 0) {
5507a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                            // Remove options, i.e. ";timeout=90"
5517a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                            mSessionID.erase(i, mSessionID.size() - i);
5527a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        }
5537a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
5543a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        sp<AMessage> notify = new AMessage('accu', id());
5553a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        notify->setSize("track-index", trackIndex);
5567a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
5570dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                        i = response->mHeaders.indexOfKey("transport");
5580dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                        CHECK_GE(i, 0);
5590dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
5600dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                        if (!track->mUsingInterleavedTCP) {
5610dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                            AString transport = response->mHeaders.valueAt(i);
5620dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
56327db53de35bbe83ce3b906da675b065803471481Andreas Huber                            // We are going to continue even if we were
56427db53de35bbe83ce3b906da675b065803471481Andreas Huber                            // unable to poke a hole into the firewall...
56527db53de35bbe83ce3b906da675b065803471481Andreas Huber                            pokeAHole(
56627db53de35bbe83ce3b906da675b065803471481Andreas Huber                                    track->mRTPSocket,
56727db53de35bbe83ce3b906da675b065803471481Andreas Huber                                    track->mRTCPSocket,
56827db53de35bbe83ce3b906da675b065803471481Andreas Huber                                    transport);
5690dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber                        }
5700dc6403f3c660f6e6f1840276e3240365889103dAndreas Huber
57127db53de35bbe83ce3b906da675b065803471481Andreas Huber                        mRTPConn->addStream(
57227db53de35bbe83ce3b906da675b065803471481Andreas Huber                                track->mRTPSocket, track->mRTCPSocket,
57327db53de35bbe83ce3b906da675b065803471481Andreas Huber                                mSessionDesc, index,
57427db53de35bbe83ce3b906da675b065803471481Andreas Huber                                notify, track->mUsingInterleavedTCP);
5757a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
57627db53de35bbe83ce3b906da675b065803471481Andreas Huber                        mSetupTracksSuccessful = true;
5773a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    }
5783a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                }
5793a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber
5803a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                if (result != OK) {
5813a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    if (track) {
5823a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        if (!track->mUsingInterleavedTCP) {
583d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                            // Clear the tag
584d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                            if (mUIDValid) {
585d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                                HTTPBase::UnRegisterSocketUserTag(track->mRTPSocket);
586d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                                HTTPBase::UnRegisterSocketUserTag(track->mRTCPSocket);
587d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                            }
588d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma
5893a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                            close(track->mRTPSocket);
5903a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                            close(track->mRTCPSocket);
5913a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        }
5923a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber
5933a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        mTracks.removeItemsAt(trackIndex);
5943a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    }
5957a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
5967a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
59757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                ++index;
59857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                if (index < mSessionDesc->countTracks()) {
59957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                    setupTrack(index);
60057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                } else if (mSetupTracksSuccessful) {
601a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                    ++mKeepAliveGeneration;
602a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                    postKeepAlive();
603a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
6047a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    AString request = "PLAY ";
6057a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append(mSessionURL);
6067a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append(" RTSP/1.0\r\n");
6077a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
6087a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append("Session: ");
6097a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append(mSessionID);
6107a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append("\r\n");
6117a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
6127a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append("\r\n");
6137a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
6147a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<AMessage> reply = new AMessage('play', id());
6157a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    mConn->sendRequest(request.c_str(), reply);
6167a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                } else {
6177a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
6187a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    mConn->disconnect(reply);
6197a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
6207a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
6217a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
6227a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
6237a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'play':
6247a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
6257a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                int32_t result;
6267a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findInt32("result", &result));
6277a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
6286e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                LOGI("PLAY completed with result %d (%s)",
6296e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                     result, strerror(-result));
6307a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
6317a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                if (result == OK) {
6327a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<RefBase> obj;
6337a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    CHECK(msg->findObject("response", &obj));
6347a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<ARTSPResponse> response =
6357a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
6367a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
637f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    if (response->mStatusCode != 200) {
638f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        result = UNKNOWN_ERROR;
639f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    } else {
640f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        parsePlayResponse(response);
6417a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
642f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        sp<AMessage> timeout = new AMessage('tiou', id());
643f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        timeout->post(kStartupTimeoutUs);
644f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    }
645f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                }
646eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
647f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                if (result != OK) {
6487a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
6497a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    mConn->disconnect(reply);
6507a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
6517a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
6527a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
6537a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
6547a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
655a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber            case 'aliv':
656a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber            {
657a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                int32_t generation;
658a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                CHECK(msg->findInt32("generation", &generation));
659a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
660a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                if (generation != mKeepAliveGeneration) {
661a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                    // obsolete event.
662a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                    break;
663a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                }
664a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
665a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                AString request;
666a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                request.append("OPTIONS ");
667a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                request.append(mSessionURL);
668a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                request.append(" RTSP/1.0\r\n");
669a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                request.append("Session: ");
670a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                request.append(mSessionID);
671a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                request.append("\r\n");
672a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                request.append("\r\n");
673a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
674a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                sp<AMessage> reply = new AMessage('opts', id());
675a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                reply->setInt32("generation", mKeepAliveGeneration);
676a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                mConn->sendRequest(request.c_str(), reply);
677a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                break;
678a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber            }
679a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
680a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber            case 'opts':
681a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber            {
682a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                int32_t result;
683a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                CHECK(msg->findInt32("result", &result));
684a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
685a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                LOGI("OPTIONS completed with result %d (%s)",
686a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                     result, strerror(-result));
687a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
688a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                int32_t generation;
689a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                CHECK(msg->findInt32("generation", &generation));
690a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
691a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                if (generation != mKeepAliveGeneration) {
692a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                    // obsolete event.
693a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                    break;
694a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                }
695a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
696a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                postKeepAlive();
697a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber                break;
698a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber            }
699a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
7007a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'abor':
7017a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
7027a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
703f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    TrackInfo *info = &mTracks.editItemAt(i);
704f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
705a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                    if (!mFirstAccessUnit) {
706a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                        postQueueEOS(i, ERROR_END_OF_STREAM);
707a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                    }
708f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
709f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    if (!info->mUsingInterleavedTCP) {
710f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket);
711f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
712d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                        // Clear the tag
713d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                        if (mUIDValid) {
714d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                            HTTPBase::UnRegisterSocketUserTag(info->mRTPSocket);
715d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                            HTTPBase::UnRegisterSocketUserTag(info->mRTCPSocket);
716d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                        }
717d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma
718f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        close(info->mRTPSocket);
719f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        close(info->mRTCPSocket);
720f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    }
7217a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
722f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                mTracks.clear();
7233a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                mSetupTracksSuccessful = false;
7243a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                mSeekPending = false;
7253a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                mFirstAccessUnit = true;
726b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                mNTPAnchorUs = -1;
727b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                mMediaAnchorUs = -1;
7283a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                mNumAccessUnitsReceived = 0;
7293a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                mReceivedFirstRTCPPacket = false;
730cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber                mReceivedFirstRTPPacket = false;
7310c46b69f612da61ed39b32823d2d6baf2e8215e9Andreas Huber                mSeekable = false;
7327a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7337a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                sp<AMessage> reply = new AMessage('tear', id());
7347a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
735f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                int32_t reconnect;
736f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
737f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    reply->setInt32("reconnect", true);
738f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                }
739f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
7407a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                AString request;
7417a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request = "TEARDOWN ";
7427a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7437a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                // XXX should use aggregate url from SDP here...
7447a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append(mSessionURL);
7457a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append(" RTSP/1.0\r\n");
7467a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7477a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append("Session: ");
7487a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append(mSessionID);
7497a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append("\r\n");
7507a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7517a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append("\r\n");
7527a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7537a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                mConn->sendRequest(request.c_str(), reply);
7547a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
7557a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
7567a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7577a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'tear':
7587a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
7597a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                int32_t result;
7607a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findInt32("result", &result));
7617a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7626e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                LOGI("TEARDOWN completed with result %d (%s)",
7636e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                     result, strerror(-result));
7647a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7657a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                sp<AMessage> reply = new AMessage('disc', id());
766f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
767f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                int32_t reconnect;
768f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
769f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    reply->setInt32("reconnect", true);
770f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                }
771f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
7727a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                mConn->disconnect(reply);
7737a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
7747a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
7757a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7767a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'quit':
7777a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
778a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                sp<AMessage> msg = mNotify->dup();
779a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                msg->setInt32("what", kWhatDisconnected);
780a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                msg->setInt32("result", UNKNOWN_ERROR);
781a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                msg->post();
7827a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
7837a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
7847a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
785eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            case 'chek':
786eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            {
787e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                int32_t generation;
788e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                CHECK(msg->findInt32("generation", &generation));
789e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                if (generation != mCheckGeneration) {
790e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                    // This is an outdated message. Ignore.
791e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                    break;
792e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                }
793e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber
794eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                if (mNumAccessUnitsReceived == 0) {
79554c7efa4dd7300a2ab008d392a83bfbdf97cdfadAndreas Huber#if 1
7966e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                    LOGI("stream ended? aborting.");
797eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    (new AMessage('abor', id()))->post();
798eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    break;
79957cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber#else
80057cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber                    LOGI("haven't seen an AU in a looong time.");
80157cc14fcc1642e0437b791ca3056e3728808092eAndreas Huber#endif
802eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                }
803eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
804eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                mNumAccessUnitsReceived = 0;
805f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber                msg->post(kAccessUnitTimeoutUs);
806eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                break;
807eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            }
808eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
8097a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'accu':
8107a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
811b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                int32_t timeUpdate;
812b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                if (msg->findInt32("time-update", &timeUpdate) && timeUpdate) {
813b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    size_t trackIndex;
814b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    CHECK(msg->findSize("track-index", &trackIndex));
815b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
816b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    uint32_t rtpTime;
817b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    uint64_t ntpTime;
818b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    CHECK(msg->findInt32("rtp-time", (int32_t *)&rtpTime));
819b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    CHECK(msg->findInt64("ntp-time", (int64_t *)&ntpTime));
820b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
821b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    onTimeUpdate(trackIndex, rtpTime, ntpTime);
822b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    break;
823b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                }
824b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
825cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber                int32_t first;
826cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber                if (msg->findInt32("first-rtcp", &first)) {
8273a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    mReceivedFirstRTCPPacket = true;
8283a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    break;
8293a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                }
8303a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber
831cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber                if (msg->findInt32("first-rtp", &first)) {
832cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber                    mReceivedFirstRTPPacket = true;
833cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber                    break;
834cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber                }
835cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber
836eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                ++mNumAccessUnitsReceived;
837e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                postAccessUnitTimeoutCheck();
838eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
8397a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                size_t trackIndex;
8407a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findSize("track-index", &trackIndex));
8417a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
842f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                if (trackIndex >= mTracks.size()) {
8436e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                    LOGV("late packets ignored.");
844f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    break;
845f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                }
846f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
847eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                TrackInfo *track = &mTracks.editItemAt(trackIndex);
848eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
849af063a67b291c4622321a35af6966b8568d5a564Andreas Huber                int32_t eos;
850af063a67b291c4622321a35af6966b8568d5a564Andreas Huber                if (msg->findInt32("eos", &eos)) {
8516e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                    LOGI("received BYE on track index %d", trackIndex);
852af063a67b291c4622321a35af6966b8568d5a564Andreas Huber#if 0
853af063a67b291c4622321a35af6966b8568d5a564Andreas Huber                    track->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
854af063a67b291c4622321a35af6966b8568d5a564Andreas Huber#endif
855af063a67b291c4622321a35af6966b8568d5a564Andreas Huber                    return;
856af063a67b291c4622321a35af6966b8568d5a564Andreas Huber                }
857af063a67b291c4622321a35af6966b8568d5a564Andreas Huber
8587a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                sp<RefBase> obj;
8597a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findObject("access-unit", &obj));
8607a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8617a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());
8627a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
863eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                uint32_t seqNum = (uint32_t)accessUnit->int32Data();
864eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
865f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                if (mSeekPending) {
8666e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                    LOGV("we're seeking, dropping stale packet.");
867f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    break;
868f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                }
869f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber
870eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                if (seqNum < track->mFirstSeqNumInSegment) {
8716e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                    LOGV("dropping stale access-unit (%d < %d)",
8726e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                         seqNum, track->mFirstSeqNumInSegment);
873eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    break;
874eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                }
875eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
876eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                if (track->mNewSegment) {
877eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    track->mNewSegment = false;
878eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                }
879eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
880b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                onAccessUnitComplete(trackIndex, accessUnit);
8817a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
8827a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
8837a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
884e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            case 'seek':
885e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            {
8860c46b69f612da61ed39b32823d2d6baf2e8215e9Andreas Huber                if (!mSeekable) {
8870c46b69f612da61ed39b32823d2d6baf2e8215e9Andreas Huber                    LOGW("This is a live stream, ignoring seek request.");
888a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
889a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                    sp<AMessage> msg = mNotify->dup();
890a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                    msg->setInt32("what", kWhatSeekDone);
891a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                    msg->post();
892e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                    break;
893e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                }
894e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
895e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                int64_t timeUs;
896e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                CHECK(msg->findInt64("time", &timeUs));
897e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
898e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                mSeekPending = true;
899e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
900e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                // Disable the access unit timeout until we resumed
901e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                // playback again.
902e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                mCheckPending = true;
903e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                ++mCheckGeneration;
904e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber
905e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                AString request = "PAUSE ";
906e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(mSessionURL);
907e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(" RTSP/1.0\r\n");
908e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
909e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("Session: ");
910e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(mSessionID);
911e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("\r\n");
912e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
913e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("\r\n");
914e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
915e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                sp<AMessage> reply = new AMessage('see1', id());
916e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                reply->setInt64("time", timeUs);
917e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                mConn->sendRequest(request.c_str(), reply);
918e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                break;
919e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            }
920e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
921e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            case 'see1':
922e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            {
923eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                // Session is paused now.
924eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
925b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    TrackInfo *info = &mTracks.editItemAt(i);
926b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
927a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                    postQueueSeekDiscontinuity(i);
928a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
929b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    info->mRTPAnchor = 0;
930b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    info->mNTPAnchorUs = -1;
931eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                }
932eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
933b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                mNTPAnchorUs = -1;
934b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
935e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                int64_t timeUs;
936e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                CHECK(msg->findInt64("time", &timeUs));
937e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
938e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                AString request = "PLAY ";
939e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(mSessionURL);
940e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(" RTSP/1.0\r\n");
941e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
942e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("Session: ");
943e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(mSessionID);
944e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("\r\n");
945e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
946e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(
947e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                        StringPrintf(
948e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                            "Range: npt=%lld-\r\n", timeUs / 1000000ll));
949e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
950e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("\r\n");
951e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
952e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                sp<AMessage> reply = new AMessage('see2', id());
953e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                mConn->sendRequest(request.c_str(), reply);
954e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                break;
955e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            }
956e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
957e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            case 'see2':
958e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            {
959e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                CHECK(mSeekPending);
960e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
961e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                int32_t result;
962e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                CHECK(msg->findInt32("result", &result));
963eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
9646e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                LOGI("PLAY completed with result %d (%s)",
9656e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                     result, strerror(-result));
966eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
967e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                mCheckPending = false;
968e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber                postAccessUnitTimeoutCheck();
969e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber
970f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                if (result == OK) {
971f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    sp<RefBase> obj;
972f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    CHECK(msg->findObject("response", &obj));
973f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    sp<ARTSPResponse> response =
974f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        static_cast<ARTSPResponse *>(obj.get());
975e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
976f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    if (response->mStatusCode != 200) {
977f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        result = UNKNOWN_ERROR;
978f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    } else {
979f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        parsePlayResponse(response);
980e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
981b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                        ssize_t i = response->mHeaders.indexOfKey("rtp-info");
982b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                        CHECK_GE(i, 0);
983b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
984b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                        LOGV("rtp-info: %s", response->mHeaders.valueAt(i).c_str());
985b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
9866e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                        LOGI("seek completed.");
987f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    }
988f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                }
989e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
990f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                if (result != OK) {
9916e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                    LOGE("seek failed, aborting.");
992f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    (new AMessage('abor', id()))->post();
993f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                }
994eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
995eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                mSeekPending = false;
9960c46b69f612da61ed39b32823d2d6baf2e8215e9Andreas Huber
997a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                sp<AMessage> msg = mNotify->dup();
998a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                msg->setInt32("what", kWhatSeekDone);
999a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                msg->post();
1000e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                break;
1001e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            }
1002e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
10030416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            case 'biny':
10040416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            {
10050416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                sp<RefBase> obj;
10060416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                CHECK(msg->findObject("buffer", &obj));
10070416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
10080416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
10090416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                int32_t index;
10100416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                CHECK(buffer->meta()->findInt32("index", &index));
10110416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
10120416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                mRTPConn->injectPacket(index, buffer);
10130416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                break;
10140416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            }
10150416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
10160416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            case 'tiou':
10170416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            {
10183a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                if (!mReceivedFirstRTCPPacket) {
10190407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                    if (mReceivedFirstRTPPacket && !mTryFakeRTCP) {
1020cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber                        LOGW("We received RTP packets but no RTCP packets, "
1021cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber                             "using fake timestamps.");
1022cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber
1023cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber                        mTryFakeRTCP = true;
1024cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber
1025cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber                        mReceivedFirstRTCPPacket = true;
10260407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
10270407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                        fakeTimestamps();
10280407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                    } else if (!mReceivedFirstRTPPacket && !mTryTCPInterleaving) {
10296e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber                        LOGW("Never received any data, switching transports.");
1030f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
1031f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        mTryTCPInterleaving = true;
1032f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
1033f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        sp<AMessage> msg = new AMessage('abor', id());
1034f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        msg->setInt32("reconnect", true);
1035f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        msg->post();
10360407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                    } else {
10370407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                        LOGW("Never received any data, disconnecting.");
10380407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber                        (new AMessage('abor', id()))->post();
1039f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    }
10400416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                }
10410416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                break;
10420416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            }
10430416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
10447a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            default:
10457a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                TRESPASS();
10467a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
10477a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        }
10487a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
10497a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1050a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber    void postKeepAlive() {
1051a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber        sp<AMessage> msg = new AMessage('aliv', id());
1052a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber        msg->setInt32("generation", mKeepAliveGeneration);
1053a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber        msg->post((mKeepAliveTimeoutUs * 9) / 10);
1054a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber    }
1055a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber
1056e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber    void postAccessUnitTimeoutCheck() {
1057e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber        if (mCheckPending) {
1058e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber            return;
1059e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber        }
1060e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber
1061e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber        mCheckPending = true;
1062e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber        sp<AMessage> check = new AMessage('chek', id());
1063e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber        check->setInt32("generation", mCheckGeneration);
1064e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber        check->post(kAccessUnitTimeoutUs);
1065e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber    }
1066e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber
1067eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    static void SplitString(
1068eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            const AString &s, const char *separator, List<AString> *items) {
1069eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        items->clear();
1070eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        size_t start = 0;
1071eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        while (start < s.size()) {
1072eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            ssize_t offset = s.find(separator, start);
1073eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1074eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            if (offset < 0) {
1075eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                items->push_back(AString(s, start, s.size() - start));
1076eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                break;
1077eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            }
1078eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1079eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            items->push_back(AString(s, start, offset - start));
1080eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            start = offset + strlen(separator);
1081eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
1082eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    }
1083eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1084eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    void parsePlayResponse(const sp<ARTSPResponse> &response) {
10850c46b69f612da61ed39b32823d2d6baf2e8215e9Andreas Huber        mSeekable = false;
10860c46b69f612da61ed39b32823d2d6baf2e8215e9Andreas Huber
1087eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        ssize_t i = response->mHeaders.indexOfKey("range");
1088eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        if (i < 0) {
1089eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            // Server doesn't even tell use what range it is going to
1090eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            // play, therefore we won't support seeking.
1091eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            return;
1092eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
1093eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1094eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        AString range = response->mHeaders.valueAt(i);
10956e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber        LOGV("Range: %s", range.c_str());
1096eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1097eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        AString val;
1098eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        CHECK(GetAttribute(range.c_str(), "npt", &val));
1099eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1100a2edd7d8d1323aad756d6f58f545d01c0bf33458Andreas Huber        float npt1, npt2;
1101a2edd7d8d1323aad756d6f58f545d01c0bf33458Andreas Huber        if (!ASessionDescription::parseNTPRange(val.c_str(), &npt1, &npt2)) {
1102eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            // This is a live stream and therefore not seekable.
1103f6ae711450581d248e646b8d8d6b0bf75c4d19eaAndreas Huber
1104f6ae711450581d248e646b8d8d6b0bf75c4d19eaAndreas Huber            LOGI("This is a live stream");
1105d4a6cac34d9e75dc708f894863d1870e456c93d6Andreas Huber            return;
1106eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
1107eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1108eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        i = response->mHeaders.indexOfKey("rtp-info");
1109eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        CHECK_GE(i, 0);
1110eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1111eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        AString rtpInfo = response->mHeaders.valueAt(i);
1112eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        List<AString> streamInfos;
1113eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        SplitString(rtpInfo, ",", &streamInfos);
1114eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1115eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        int n = 1;
1116eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        for (List<AString>::iterator it = streamInfos.begin();
1117eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber             it != streamInfos.end(); ++it) {
1118eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            (*it).trim();
11196e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber            LOGV("streamInfo[%d] = %s", n, (*it).c_str());
1120eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1121eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            CHECK(GetAttribute((*it).c_str(), "url", &val));
1122eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1123eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            size_t trackIndex = 0;
1124eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            while (trackIndex < mTracks.size()
1125eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    && !(val == mTracks.editItemAt(trackIndex).mURL)) {
1126eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                ++trackIndex;
1127eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            }
1128eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            CHECK_LT(trackIndex, mTracks.size());
1129eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1130eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            CHECK(GetAttribute((*it).c_str(), "seq", &val));
1131eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1132eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            char *end;
1133eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            unsigned long seq = strtoul(val.c_str(), &end, 10);
1134eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1135eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            TrackInfo *info = &mTracks.editItemAt(trackIndex);
1136eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            info->mFirstSeqNumInSegment = seq;
1137eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            info->mNewSegment = true;
1138eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1139eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            CHECK(GetAttribute((*it).c_str(), "rtptime", &val));
1140eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1141eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            uint32_t rtpTime = strtoul(val.c_str(), &end, 10);
1142eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1143b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            LOGV("track #%d: rtpTime=%u <=> npt=%.2f", n, rtpTime, npt1);
1144eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1145a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            info->mNormalPlayTimeRTP = rtpTime;
1146a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            info->mNormalPlayTimeUs = (int64_t)(npt1 * 1E6);
1147a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
1148a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            if (!mFirstAccessUnit) {
1149a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                postNormalPlayTimeMapping(
1150a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                        trackIndex,
1151a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                        info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
1152a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            }
1153eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1154eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            ++n;
1155eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
11560c46b69f612da61ed39b32823d2d6baf2e8215e9Andreas Huber
1157d4a6cac34d9e75dc708f894863d1870e456c93d6Andreas Huber        mSeekable = true;
1158eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    }
1159eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1160a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    sp<MetaData> getTrackFormat(size_t index, int32_t *timeScale) {
11617a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        CHECK_GE(index, 0u);
11627a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        CHECK_LT(index, mTracks.size());
11637a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1164a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        const TrackInfo &info = mTracks.itemAt(index);
1165a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
1166a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        *timeScale = info.mTimeScale;
1167a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
1168a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        return info.mPacketSource->getFormat();
11697a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
11707a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
11717a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    size_t countTracks() const {
11727a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        return mTracks.size();
11737a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
11747a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
11757a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huberprivate:
1176b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber    struct TrackInfo {
1177b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        AString mURL;
1178b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        int mRTPSocket;
1179b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        int mRTCPSocket;
1180b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        bool mUsingInterleavedTCP;
1181b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        uint32_t mFirstSeqNumInSegment;
1182b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        bool mNewSegment;
1183b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1184b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        uint32_t mRTPAnchor;
1185b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        int64_t mNTPAnchorUs;
1186b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        int32_t mTimeScale;
1187b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1188a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        uint32_t mNormalPlayTimeRTP;
1189a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        int64_t mNormalPlayTimeUs;
1190a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
1191b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        sp<APacketSource> mPacketSource;
1192b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1193b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        // Stores packets temporarily while no notion of time
1194b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        // has been established yet.
1195b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        List<sp<ABuffer> > mPackets;
1196b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber    };
1197b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1198a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    sp<AMessage> mNotify;
1199603d739b5a444c52b63f1ec7cd2098034151ad25Andreas Huber    bool mUIDValid;
1200603d739b5a444c52b63f1ec7cd2098034151ad25Andreas Huber    uid_t mUID;
12014e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber    sp<ALooper> mNetLooper;
12027a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    sp<ARTSPConnection> mConn;
12037a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    sp<ARTPConnection> mRTPConn;
12047a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    sp<ASessionDescription> mSessionDesc;
1205a0b442edbf6e1f602f89b3bda1c8894ef8740d72Andreas Huber    AString mOriginalSessionURL;  // This one still has user:pass@
12067a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    AString mSessionURL;
120727db53de35bbe83ce3b906da675b065803471481Andreas Huber    AString mSessionHost;
12087a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    AString mBaseURL;
12097a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    AString mSessionID;
12107a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    bool mSetupTracksSuccessful;
1211e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber    bool mSeekPending;
1212e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber    bool mFirstAccessUnit;
1213b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1214b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber    int64_t mNTPAnchorUs;
1215b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber    int64_t mMediaAnchorUs;
1216b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber    int64_t mLastMediaTimeUs;
1217b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1218eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    int64_t mNumAccessUnitsReceived;
1219eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    bool mCheckPending;
1220e51e80990e72dee6372e3300fbbcdac3a115b60aAndreas Huber    int32_t mCheckGeneration;
1221f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber    bool mTryTCPInterleaving;
1222cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber    bool mTryFakeRTCP;
12233a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber    bool mReceivedFirstRTCPPacket;
1224cc5fb1d5e5c1971cabfc2cba89de63ba65678882Andreas Huber    bool mReceivedFirstRTPPacket;
12250c46b69f612da61ed39b32823d2d6baf2e8215e9Andreas Huber    bool mSeekable;
1226a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber    int64_t mKeepAliveTimeoutUs;
1227a1b3e3d49ea04cc42aadbd07a6304008fda1e515Andreas Huber    int32_t mKeepAliveGeneration;
12287a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
12297a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    Vector<TrackInfo> mTracks;
12307a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
12317a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    void setupTrack(size_t index) {
123257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        sp<APacketSource> source =
123357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            new APacketSource(mSessionDesc, index);
1234f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
123557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        if (source->initCheck() != OK) {
12366e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber            LOGW("Unsupported format. Ignoring track #%d.", index);
123757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
123857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            sp<AMessage> reply = new AMessage('setu', id());
123957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            reply->setSize("index", index);
124057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            reply->setInt32("result", ERROR_UNSUPPORTED);
124157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            reply->post();
124257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            return;
124357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        }
124457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
12457a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        AString url;
12467a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        CHECK(mSessionDesc->findAttribute(index, "a=control", &url));
12477a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
12487a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        AString trackURL;
12497a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        CHECK(MakeURL(mBaseURL.c_str(), url.c_str(), &trackURL));
12507a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
12517a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        mTracks.push(TrackInfo());
12527a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1);
1253eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        info->mURL = trackURL;
125457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        info->mPacketSource = source;
12550416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber        info->mUsingInterleavedTCP = false;
1256eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        info->mFirstSeqNumInSegment = 0;
1257eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        info->mNewSegment = true;
1258b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        info->mRTPAnchor = 0;
1259b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        info->mNTPAnchorUs = -1;
1260a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        info->mNormalPlayTimeRTP = 0;
1261a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        info->mNormalPlayTimeUs = 0ll;
1262b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1263b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        unsigned long PT;
1264b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        AString formatDesc;
1265b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        AString formatParams;
1266b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        mSessionDesc->getFormatType(index, &PT, &formatDesc, &formatParams);
1267b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1268b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        int32_t timescale;
1269b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        int32_t numChannels;
1270b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        ASessionDescription::ParseFormatDesc(
1271b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                formatDesc.c_str(), &timescale, &numChannels);
1272b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1273b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        info->mTimeScale = timescale;
1274eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
12756e3fa444c5b3970666707bb2b6d25e2615dafe80Andreas Huber        LOGV("track #%d URL=%s", mTracks.size(), trackURL.c_str());
12767a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
12777a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        AString request = "SETUP ";
12787a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        request.append(trackURL);
12797a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        request.append(" RTSP/1.0\r\n");
12807a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1281f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber        if (mTryTCPInterleaving) {
1282f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            size_t interleaveIndex = 2 * (mTracks.size() - 1);
1283f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            info->mUsingInterleavedTCP = true;
1284f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            info->mRTPSocket = interleaveIndex;
1285f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            info->mRTCPSocket = interleaveIndex + 1;
1286f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
1287f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append("Transport: RTP/AVP/TCP;interleaved=");
1288f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append(interleaveIndex);
1289f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append("-");
1290f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append(interleaveIndex + 1);
1291f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber        } else {
1292f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            unsigned rtpPort;
1293f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            ARTPConnection::MakePortPair(
1294f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    &info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
1295f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
1296603d739b5a444c52b63f1ec7cd2098034151ad25Andreas Huber            if (mUIDValid) {
1297d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                HTTPBase::RegisterSocketUserTag(info->mRTPSocket, mUID,
1298d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                                                (uint32_t)*(uint32_t*) "RTP_");
1299d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                HTTPBase::RegisterSocketUserTag(info->mRTCPSocket, mUID,
1300d5a20d8d75718fda8a9435d7113f3d6bb8f79a33Ashish Sharma                                                (uint32_t)*(uint32_t*) "RTP_");
1301603d739b5a444c52b63f1ec7cd2098034151ad25Andreas Huber            }
1302603d739b5a444c52b63f1ec7cd2098034151ad25Andreas Huber
1303f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
1304f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append(rtpPort);
1305f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append("-");
1306f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append(rtpPort + 1);
1307f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber        }
13080416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
13097a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        request.append("\r\n");
13107a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
13117a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        if (index > 1) {
13127a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            request.append("Session: ");
13137a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            request.append(mSessionID);
13147a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            request.append("\r\n");
13157a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        }
13167a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
13177a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        request.append("\r\n");
13187a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
13197a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        sp<AMessage> reply = new AMessage('setu', id());
13207a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        reply->setSize("index", index);
13217a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        reply->setSize("track-index", mTracks.size() - 1);
13227a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        mConn->sendRequest(request.c_str(), reply);
13237a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
13247a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
13257a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    static bool MakeURL(const char *baseURL, const char *url, AString *out) {
13267a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        out->clear();
13277a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
13287a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        if (strncasecmp("rtsp://", baseURL, 7)) {
13297a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            // Base URL must be absolute
13307a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            return false;
13317a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        }
13327a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
13337a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        if (!strncasecmp("rtsp://", url, 7)) {
13347a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            // "url" is already an absolute URL, ignore base URL.
13357a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            out->setTo(url);
13367a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            return true;
13377a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        }
13387a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
13397a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        size_t n = strlen(baseURL);
13407a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        if (baseURL[n - 1] == '/') {
13417a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            out->setTo(baseURL);
13427a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            out->append(url);
13437a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        } else {
13445a23f8c41ee83a0316ae8265841beaf6d97a66d9Mike Lockwood            const char *slashPos = strrchr(baseURL, '/');
13457a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
13467a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            if (slashPos > &baseURL[6]) {
13477a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                out->setTo(baseURL, slashPos - baseURL);
13487a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            } else {
13497a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                out->setTo(baseURL);
13507a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
13517a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
13527a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            out->append("/");
13537a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            out->append(url);
13547a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        }
13557a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
13567a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        return true;
13577a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
13587a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
13590407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber    void fakeTimestamps() {
13600407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber        for (size_t i = 0; i < mTracks.size(); ++i) {
13610407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber            onTimeUpdate(i, 0, 0ll);
13620407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber        }
13630407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber    }
13640407269ae35e62a6aa2f6e40964970db1bd4b14aAndreas Huber
1365b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber    void onTimeUpdate(int32_t trackIndex, uint32_t rtpTime, uint64_t ntpTime) {
1366b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        LOGV("onTimeUpdate track %d, rtpTime = 0x%08x, ntpTime = 0x%016llx",
1367b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber             trackIndex, rtpTime, ntpTime);
1368b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1369b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        int64_t ntpTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
1370b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1371b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        TrackInfo *track = &mTracks.editItemAt(trackIndex);
1372b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1373b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        track->mRTPAnchor = rtpTime;
1374b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        track->mNTPAnchorUs = ntpTimeUs;
1375b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1376b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        if (mNTPAnchorUs < 0) {
1377b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            mNTPAnchorUs = ntpTimeUs;
1378b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            mMediaAnchorUs = mLastMediaTimeUs;
1379b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        }
1380b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber    }
1381b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1382b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber    void onAccessUnitComplete(
1383b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            int32_t trackIndex, const sp<ABuffer> &accessUnit) {
1384b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        LOGV("onAccessUnitComplete track %d", trackIndex);
1385b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1386b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        if (mFirstAccessUnit) {
1387a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            sp<AMessage> msg = mNotify->dup();
1388a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            msg->setInt32("what", kWhatConnected);
1389a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            msg->post();
1390a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
1391f6ae711450581d248e646b8d8d6b0bf75c4d19eaAndreas Huber            if (mSeekable) {
1392f6ae711450581d248e646b8d8d6b0bf75c4d19eaAndreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
1393f6ae711450581d248e646b8d8d6b0bf75c4d19eaAndreas Huber                    TrackInfo *info = &mTracks.editItemAt(i);
1394a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
1395f6ae711450581d248e646b8d8d6b0bf75c4d19eaAndreas Huber                    postNormalPlayTimeMapping(
1396f6ae711450581d248e646b8d8d6b0bf75c4d19eaAndreas Huber                            i,
1397f6ae711450581d248e646b8d8d6b0bf75c4d19eaAndreas Huber                            info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
1398f6ae711450581d248e646b8d8d6b0bf75c4d19eaAndreas Huber                }
1399a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            }
1400b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1401b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            mFirstAccessUnit = false;
1402b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        }
1403b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1404b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        TrackInfo *track = &mTracks.editItemAt(trackIndex);
1405b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1406b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        if (mNTPAnchorUs < 0 || mMediaAnchorUs < 0 || track->mNTPAnchorUs < 0) {
1407b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            LOGV("storing accessUnit, no time established yet");
1408b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            track->mPackets.push_back(accessUnit);
1409b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            return;
1410b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        }
1411b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1412b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        while (!track->mPackets.empty()) {
1413b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            sp<ABuffer> accessUnit = *track->mPackets.begin();
1414b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            track->mPackets.erase(track->mPackets.begin());
1415b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1416b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            if (addMediaTimestamp(trackIndex, track, accessUnit)) {
1417a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber                postQueueAccessUnit(trackIndex, accessUnit);
1418b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            }
1419b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        }
1420b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1421b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        if (addMediaTimestamp(trackIndex, track, accessUnit)) {
1422a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            postQueueAccessUnit(trackIndex, accessUnit);
1423b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        }
1424b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber    }
1425b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1426b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber    bool addMediaTimestamp(
1427b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            int32_t trackIndex, const TrackInfo *track,
1428b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            const sp<ABuffer> &accessUnit) {
1429b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        uint32_t rtpTime;
1430b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        CHECK(accessUnit->meta()->findInt32(
1431b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                    "rtp-time", (int32_t *)&rtpTime));
1432b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1433b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        int64_t relRtpTimeUs =
1434b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            (((int64_t)rtpTime - (int64_t)track->mRTPAnchor) * 1000000ll)
1435b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber                / track->mTimeScale;
1436b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1437b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        int64_t ntpTimeUs = track->mNTPAnchorUs + relRtpTimeUs;
1438b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1439b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        int64_t mediaTimeUs = mMediaAnchorUs + ntpTimeUs - mNTPAnchorUs;
1440b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1441b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        if (mediaTimeUs > mLastMediaTimeUs) {
1442b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            mLastMediaTimeUs = mediaTimeUs;
1443b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        }
1444b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1445b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        if (mediaTimeUs < 0) {
1446b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            LOGV("dropping early accessUnit.");
1447b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber            return false;
1448b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        }
1449b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1450b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        LOGV("track %d rtpTime=%d mediaTimeUs = %lld us (%.2f secs)",
1451b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber             trackIndex, rtpTime, mediaTimeUs, mediaTimeUs / 1E6);
1452b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1453b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        accessUnit->meta()->setInt64("timeUs", mediaTimeUs);
1454b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1455b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber        return true;
1456b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber    }
1457b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
1458a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    void postQueueAccessUnit(
1459a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            size_t trackIndex, const sp<ABuffer> &accessUnit) {
1460a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        sp<AMessage> msg = mNotify->dup();
1461a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setInt32("what", kWhatAccessUnit);
1462a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setSize("trackIndex", trackIndex);
1463a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setObject("accessUnit", accessUnit);
1464a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->post();
1465a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    }
1466a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
1467a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    void postQueueEOS(size_t trackIndex, status_t finalResult) {
1468a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        sp<AMessage> msg = mNotify->dup();
1469a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setInt32("what", kWhatEOS);
1470a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setSize("trackIndex", trackIndex);
1471a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setInt32("finalResult", finalResult);
1472a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->post();
1473a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    }
1474a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
1475a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    void postQueueSeekDiscontinuity(size_t trackIndex) {
1476a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        sp<AMessage> msg = mNotify->dup();
1477a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setInt32("what", kWhatSeekDiscontinuity);
1478a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setSize("trackIndex", trackIndex);
1479a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->post();
1480a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    }
1481a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber
1482a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    void postNormalPlayTimeMapping(
1483a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber            size_t trackIndex, uint32_t rtpTime, int64_t nptUs) {
1484a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        sp<AMessage> msg = mNotify->dup();
1485a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setInt32("what", kWhatNormalPlayTimeMapping);
1486a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setSize("trackIndex", trackIndex);
1487a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setInt32("rtpTime", rtpTime);
1488a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->setInt64("nptUs", nptUs);
1489a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber        msg->post();
1490a6be6dcd03fbcce8999d495abdd2ae209a06b4c9Andreas Huber    }
1491b2934b16eac8d8a866c37a7d1d7e03635f475b08Andreas Huber
14927a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    DISALLOW_EVIL_CONSTRUCTORS(MyHandler);
14937a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber};
14947a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
14957a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber}  // namespace android
14967a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
14977a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#endif  // MY_HANDLER_H_
1498