MyHandler.h revision 2bc940b4f961e588459c83862b2c6bea314a4027
1cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber/*
2cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * Copyright (C) 2010 The Android Open Source Project
3cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber *
4cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * you may not use this file except in compliance with the License.
6cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * You may obtain a copy of the License at
7cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber *
8cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
9cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber *
10cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * Unless required by applicable law or agreed to in writing, software
11cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * See the License for the specific language governing permissions and
14cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber * limitations under the License.
15cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber */
16cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
17cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#ifndef MY_HANDLER_H_
18cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
19cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#define MY_HANDLER_H_
20cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
216e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber//#define LOG_NDEBUG 0
226e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber#define LOG_TAG "MyHandler"
236e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber#include <utils/Log.h>
246e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber
25cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include "APacketSource.h"
26cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include "ARTPConnection.h"
27cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include "ARTSPConnection.h"
28cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include "ASessionDescription.h"
29cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
308d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber#include <ctype.h>
312bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#include <cutils/properties.h>
328d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
33cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/foundation/ABuffer.h>
34cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/foundation/ADebug.h>
35cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/foundation/ALooper.h>
36cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/foundation/AMessage.h>
37cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/MediaErrors.h>
38cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
392bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#include <arpa/inet.h>
402bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#include <sys/socket.h>
412bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
42e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber// If no access units are received within 3 secs, assume that the rtp
43e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber// stream has ended and signal end of stream.
44e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huberstatic int64_t kAccessUnitTimeoutUs = 3000000ll;
45e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber
46e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber// If no access units arrive for the first 10 secs after starting the
47e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber// stream, assume none ever will and signal EOS or switch transports.
48e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huberstatic int64_t kStartupTimeoutUs = 10000000ll;
49e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber
50cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Hubernamespace android {
51cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
522bc940b4f961e588459c83862b2c6bea314a4027Andreas Huberstatic void MakeUserAgentString(AString *s) {
532bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    s->setTo("stagefright/1.1 (Linux;Android ");
542bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
552bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#if (PROPERTY_VALUE_MAX < 8)
562bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#error "PROPERTY_VALUE_MAX must be at least 8"
572bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber#endif
582bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
592bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    char value[PROPERTY_VALUE_MAX];
602bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    property_get("ro.build.version.release", value, "Unknown");
612bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    s->append(value);
622bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    s->append(")");
632bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber}
642bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
658d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huberstatic bool GetAttribute(const char *s, const char *key, AString *value) {
668d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    value->clear();
678d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
688d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    size_t keyLen = strlen(key);
698d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
708d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    for (;;) {
718d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        while (isspace(*s)) {
728d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            ++s;
738d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
748d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
758d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        const char *colonPos = strchr(s, ';');
768d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
778d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        size_t len =
788d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            (colonPos == NULL) ? strlen(s) : colonPos - s;
798d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
808d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
818d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            value->setTo(&s[keyLen + 1], len - keyLen - 1);
828d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            return true;
838d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
848d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
858d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        if (colonPos == NULL) {
868d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            return false;
878d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
888d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
898d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        s = colonPos + 1;
908d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    }
918d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber}
928d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
93cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huberstruct MyHandler : public AHandler {
94cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    MyHandler(const char *url, const sp<ALooper> &looper)
95cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        : mLooper(looper),
96348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber          mNetLooper(new ALooper),
97cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mConn(new ARTSPConnection),
98cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mRTPConn(new ARTPConnection),
99cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mSessionURL(url),
100cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber          mSetupTracksSuccessful(false),
101cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber          mSeekPending(false),
102cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber          mFirstAccessUnit(true),
1038d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber          mFirstAccessUnitNTP(0),
1048d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber          mNumAccessUnitsReceived(0),
1057aef03379179c109c2547c33c410bfc93c8db576Andreas Huber          mCheckPending(false),
106a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber          mCheckGeneration(0),
107e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber          mTryTCPInterleaving(false),
1080dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber          mReceivedFirstRTCPPacket(false),
1090dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber          mSeekable(false) {
110a814c1fdc2acf0ed2ee3b175110f6039be7c4873Andreas Huber        mNetLooper->setName("rtsp net");
111348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber        mNetLooper->start(false /* runOnCallingThread */,
112348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                          false /* canCallJava */,
113348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                          PRIORITY_HIGHEST);
114348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber    }
115348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber
1161b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber    void connect(const sp<AMessage> &doneMsg) {
1171b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber        mDoneMsg = doneMsg;
1181b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber
119cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mLooper->registerHandler(this);
120cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mLooper->registerHandler(mConn);
121348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber        (1 ? mNetLooper : mLooper)->registerHandler(mRTPConn);
122348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber
1230792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber        sp<AMessage> notify = new AMessage('biny', id());
1240792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber        mConn->observeBinaryData(notify);
1250792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
1261b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber        sp<AMessage> reply = new AMessage('conn', id());
127cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mConn->connect(mSessionURL.c_str(), reply);
128cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
129cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1301b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber    void disconnect(const sp<AMessage> &doneMsg) {
1311b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber        mDoneMsg = doneMsg;
1321b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber
1331b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber        (new AMessage('abor', id()))->post();
134348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber    }
135348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber
1360dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber    void seek(int64_t timeUs, const sp<AMessage> &doneMsg) {
137cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber        sp<AMessage> msg = new AMessage('seek', id());
138cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber        msg->setInt64("time", timeUs);
1390dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber        msg->setMessage("doneMsg", doneMsg);
140cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber        msg->post();
141cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber    }
142cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
1438d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    int64_t getNormalPlayTimeUs() {
1448d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        int64_t maxTimeUs = 0;
1458d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        for (size_t i = 0; i < mTracks.size(); ++i) {
1468d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            int64_t timeUs = mTracks.editItemAt(i).mPacketSource
1478d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                ->getNormalPlayTimeUs();
1488d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
1498d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            if (i == 0 || timeUs > maxTimeUs) {
1508d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                maxTimeUs = timeUs;
1518d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            }
1528d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
1538d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
1548d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        return maxTimeUs;
1558d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    }
1568d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
1572bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    static void addRR(const sp<ABuffer> &buf) {
1582bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        uint8_t *ptr = buf->data() + buf->size();
1592bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[0] = 0x80 | 0;
1602bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[1] = 201;  // RR
1612bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[2] = 0;
1622bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[3] = 1;
1632bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[4] = 0xde;  // SSRC
1642bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[5] = 0xad;
1652bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[6] = 0xbe;
1662bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ptr[7] = 0xef;
1672bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
1682bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        buf->setRange(0, buf->size() + 8);
1692bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    }
1702bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
1712bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    static void addSDES(int s, const sp<ABuffer> &buffer) {
1722bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        struct sockaddr_in addr;
1732bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        socklen_t addrSize = sizeof(addr);
1742bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        CHECK_EQ(0, getsockname(s, (sockaddr *)&addr, &addrSize));
1752bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
1762bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        uint8_t *data = buffer->data() + buffer->size();
1772bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[0] = 0x80 | 1;
1782bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[1] = 202;  // SDES
1792bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[4] = 0xde;  // SSRC
1802bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[5] = 0xad;
1812bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[6] = 0xbe;
1822bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[7] = 0xef;
1832bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
1842bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        size_t offset = 8;
1852bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
1862bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = 1;  // CNAME
1872bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
1882bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString cname = "stagefright@";
1892bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        cname.append(inet_ntoa(addr.sin_addr));
1902bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = cname.size();
1912bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
1922bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        memcpy(&data[offset], cname.c_str(), cname.size());
1932bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        offset += cname.size();
1942bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
1952bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = 6;  // TOOL
1962bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
1972bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString tool;
1982bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        MakeUserAgentString(&tool);
1992bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2002bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = tool.size();
2012bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2022bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        memcpy(&data[offset], tool.c_str(), tool.size());
2032bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        offset += tool.size();
2042bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2052bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[offset++] = 0;
2062bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2072bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if ((offset % 4) > 0) {
2082bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            size_t count = 4 - (offset % 4);
2092bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            switch (count) {
2102bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                case 3:
2112bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                    data[offset++] = 0;
2122bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                case 2:
2132bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                    data[offset++] = 0;
2142bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                case 1:
2152bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                    data[offset++] = 0;
2162bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            }
2172bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
2182bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2192bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        size_t numWords = (offset / 4) - 1;
2202bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[2] = numWords >> 8;
2212bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        data[3] = numWords & 0xff;
2222bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2232bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        buffer->setRange(buffer->offset(), buffer->size() + offset);
2242bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    }
2252bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2262bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    // In case we're behind NAT, fire off two UDP packets to the remote
2272bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    // rtp/rtcp ports to poke a hole into the firewall for future incoming
2282bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    // packets. We're going to send an RR/SDES RTCP packet to both of them.
2292bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    void pokeAHole(int rtpSocket, int rtcpSocket, const AString &transport) {
2302bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString source;
2312bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        AString server_port;
2322bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if (!GetAttribute(transport.c_str(),
2332bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                          "source",
2342bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                          &source)
2352bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                || !GetAttribute(transport.c_str(),
2362bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                                 "server_port",
2372bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                                 &server_port)) {
2382bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            return;
2392bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
2402bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2412bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        int rtpPort, rtcpPort;
2422bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if (sscanf(server_port.c_str(), "%d-%d", &rtpPort, &rtcpPort) != 2
2432bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                || rtpPort <= 0 || rtpPort > 65535
2442bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                || rtcpPort <=0 || rtcpPort > 65535
2452bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                || rtcpPort != rtpPort + 1
2462bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                || (rtpPort & 1) != 0) {
2472bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            return;
2482bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
2492bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2502bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        struct sockaddr_in addr;
2512bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
2522bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addr.sin_family = AF_INET;
2532bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addr.sin_addr.s_addr = inet_addr(source.c_str());
2542bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2552bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        if (addr.sin_addr.s_addr == INADDR_NONE) {
2562bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber            return;
2572bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        }
2582bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2592bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        // Make up an RR/SDES RTCP packet.
2602bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        sp<ABuffer> buf = new ABuffer(65536);
2612bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        buf->setRange(0, 0);
2622bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addRR(buf);
2632bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addSDES(rtpSocket, buf);
2642bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2652bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addr.sin_port = htons(rtpPort);
2662bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2672bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        ssize_t n = sendto(
2682bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                rtpSocket, buf->data(), buf->size(), 0,
2692bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                (const sockaddr *)&addr, sizeof(addr));
2702bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        CHECK_EQ(n, (ssize_t)buf->size());
2712bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2722bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        addr.sin_port = htons(rtcpPort);
2732bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2742bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        n = sendto(
2752bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                rtcpSocket, buf->data(), buf->size(), 0,
2762bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                (const sockaddr *)&addr, sizeof(addr));
2772bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        CHECK_EQ(n, (ssize_t)buf->size());
2782bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
2792bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber        LOGV("successfully poked holes.");
2802bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber    }
2812bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
282cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    virtual void onMessageReceived(const sp<AMessage> &msg) {
283cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        switch (msg->what()) {
284cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'conn':
285cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
286cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
287cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
288cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
2896e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("connection request completed with result %d (%s)",
2906e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
291cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
292cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
293cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    AString request;
294cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request = "DESCRIBE ";
295cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(mSessionURL);
296cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(" RTSP/1.0\r\n");
297cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("Accept: application/sdp\r\n");
298cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("\r\n");
299cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
300cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('desc', id());
301cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->sendRequest(request.c_str(), reply);
3020792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                } else {
3030792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                    (new AMessage('disc', id()))->post();
304cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
305cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
306cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
307cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
308cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'disc':
309cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
3107aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                int32_t reconnect;
3117aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
3127aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    sp<AMessage> reply = new AMessage('conn', id());
3137aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    mConn->connect(mSessionURL.c_str(), reply);
3147aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                } else {
3157aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    (new AMessage('quit', id()))->post();
3167aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
317cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
318cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
319cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
320cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'desc':
321cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
322cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
323cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
324cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
3256e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("DESCRIBE completed with result %d (%s)",
3266e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
327cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
328cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
329cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<RefBase> obj;
330cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(msg->findObject("response", &obj));
331cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<ARTSPResponse> response =
332cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
333cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
334cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    if (response->mStatusCode == 302) {
335cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        ssize_t i = response->mHeaders.indexOfKey("location");
336cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        CHECK_GE(i, 0);
337cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
338cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        mSessionURL = response->mHeaders.valueAt(i);
339cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
340cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        AString request;
341cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request = "DESCRIBE ";
342cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append(mSessionURL);
343cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append(" RTSP/1.0\r\n");
344cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append("Accept: application/sdp\r\n");
345cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        request.append("\r\n");
346cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
347cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        sp<AMessage> reply = new AMessage('desc', id());
348cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        mConn->sendRequest(request.c_str(), reply);
349cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        break;
350cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    }
351cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
352e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    if (response->mStatusCode != 200) {
353e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        result = UNKNOWN_ERROR;
354e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    } else {
355e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        mSessionDesc = new ASessionDescription;
356cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
357e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        mSessionDesc->setTo(
358e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                response->mContent->data(),
359e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                response->mContent->size());
360cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
3616f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        if (!mSessionDesc->isValid()) {
3626f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                            result = ERROR_MALFORMED;
363cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        } else {
3646f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                            ssize_t i = response->mHeaders.indexOfKey("content-base");
365e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            if (i >= 0) {
366e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                mBaseURL = response->mHeaders.valueAt(i);
367e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            } else {
3686f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                i = response->mHeaders.indexOfKey("content-location");
3696f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                if (i >= 0) {
3706f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                    mBaseURL = response->mHeaders.valueAt(i);
3716f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                } else {
3726f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                    mBaseURL = mSessionURL;
3736f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                                }
374e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            }
375e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
3766f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                            CHECK_GT(mSessionDesc->countTracks(), 1u);
3776f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                            setupTrack(1);
3786f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        }
379cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    }
380e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                }
381cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
382e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (result != OK) {
383cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
384cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->disconnect(reply);
385cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
386cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
387cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
388cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
389cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'setu':
390cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
391cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                size_t index;
392cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findSize("index", &index));
393cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
39439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                TrackInfo *track = NULL;
395cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                size_t trackIndex;
39639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                if (msg->findSize("track-index", &trackIndex)) {
39739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                    track = &mTracks.editItemAt(trackIndex);
39839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                }
399cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
400cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
401cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
402cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
4036e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("SETUP(%d) completed with result %d (%s)",
4046e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     index, result, strerror(-result));
405cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
406e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (result == OK) {
40739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                    CHECK(track != NULL);
408cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
409cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<RefBase> obj;
410cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(msg->findObject("response", &obj));
411cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<ARTSPResponse> response =
412cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
413cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
414e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    if (response->mStatusCode != 200) {
415e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        result = UNKNOWN_ERROR;
416e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    } else {
417e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        ssize_t i = response->mHeaders.indexOfKey("session");
418e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        CHECK_GE(i, 0);
419cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
420cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        mSessionID = response->mHeaders.valueAt(i);
421cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        i = mSessionID.find(";");
422cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        if (i >= 0) {
423cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                            // Remove options, i.e. ";timeout=90"
424cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                            mSessionID.erase(i, mSessionID.size() - i);
425cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        }
426cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
427e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        sp<AMessage> notify = new AMessage('accu', id());
428e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        notify->setSize("track-index", trackIndex);
429cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
4302bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        i = response->mHeaders.indexOfKey("transport");
4312bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        CHECK_GE(i, 0);
4322bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
4332bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        if (!track->mUsingInterleavedTCP) {
4342bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                            AString transport = response->mHeaders.valueAt(i);
4352bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
4362bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                            pokeAHole(track->mRTPSocket,
4372bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                                      track->mRTCPSocket,
4382bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                                      transport);
4392bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber                        }
4402bc940b4f961e588459c83862b2c6bea314a4027Andreas Huber
441e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        mRTPConn->addStream(
442e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                track->mRTPSocket, track->mRTCPSocket,
443e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                mSessionDesc, index,
444e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                                notify, track->mUsingInterleavedTCP);
445cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
446e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        mSetupTracksSuccessful = true;
447e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    }
448e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                }
449e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
450e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (result != OK) {
451e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    if (track) {
452e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        if (!track->mUsingInterleavedTCP) {
453e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            close(track->mRTPSocket);
454e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                            close(track->mRTCPSocket);
455e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        }
456e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
457e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                        mTracks.removeItemsAt(trackIndex);
458e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    }
459cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
460cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
46139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                ++index;
46239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                if (index < mSessionDesc->countTracks()) {
46339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                    setupTrack(index);
46439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                } else if (mSetupTracksSuccessful) {
465cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    AString request = "PLAY ";
466cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(mSessionURL);
467cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(" RTSP/1.0\r\n");
468cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
469cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("Session: ");
470cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(mSessionID);
471cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("\r\n");
472cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
473cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("\r\n");
474cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
475cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('play', id());
476cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->sendRequest(request.c_str(), reply);
477cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                } else {
478cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
479cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->disconnect(reply);
480cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
481cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
482cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
483cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
484cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'play':
485cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
486cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
487cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
488cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
4896e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("PLAY completed with result %d (%s)",
4906e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
491cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
492cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
493cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<RefBase> obj;
494cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(msg->findObject("response", &obj));
495cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<ARTSPResponse> response =
496cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
497cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
4986f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    if (response->mStatusCode != 200) {
4996f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        result = UNKNOWN_ERROR;
5006f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    } else {
5016f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        parsePlayResponse(response);
502cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
5036f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        sp<AMessage> timeout = new AMessage('tiou', id());
5046f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        timeout->post(kStartupTimeoutUs);
5056f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    }
5066f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
5078d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
5086f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (result != OK) {
509cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
510cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->disconnect(reply);
511cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
512cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
513cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
514cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
515cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
516cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'abor':
517cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
518cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
5197aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    TrackInfo *info = &mTracks.editItemAt(i);
5207aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
5217aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    info->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
5227aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
5237aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    if (!info->mUsingInterleavedTCP) {
5247aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket);
5257aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
5267aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        close(info->mRTPSocket);
5277aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        close(info->mRTCPSocket);
5287aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    }
529cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
5307aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                mTracks.clear();
531e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mSetupTracksSuccessful = false;
532e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mSeekPending = false;
533e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mFirstAccessUnit = true;
534e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mFirstAccessUnitNTP = 0;
535e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mNumAccessUnitsReceived = 0;
536e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                mReceivedFirstRTCPPacket = false;
5370dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                mSeekable = false;
538cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
539cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<AMessage> reply = new AMessage('tear', id());
540cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
5417aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                int32_t reconnect;
5427aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
5437aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    reply->setInt32("reconnect", true);
5447aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
5457aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
546cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                AString request;
547cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request = "TEARDOWN ";
548cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
549cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                // XXX should use aggregate url from SDP here...
550cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mSessionURL);
551cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(" RTSP/1.0\r\n");
552cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
553cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("Session: ");
554cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mSessionID);
555cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
556cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
557cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
558cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
559cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConn->sendRequest(request.c_str(), reply);
560cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
561cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
562cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
563cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'tear':
564cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
565cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
566cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
567cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
5686e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("TEARDOWN completed with result %d (%s)",
5696e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
570cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
571cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<AMessage> reply = new AMessage('disc', id());
5727aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
5737aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                int32_t reconnect;
5747aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
5757aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    reply->setInt32("reconnect", true);
5767aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
5777aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
578cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConn->disconnect(reply);
579cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
580cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
581cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
582cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'quit':
583cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
5841b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber                if (mDoneMsg != NULL) {
5851b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber                    mDoneMsg->setInt32("result", UNKNOWN_ERROR);
5861b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber                    mDoneMsg->post();
5871b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber                    mDoneMsg = NULL;
5881b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber                }
589cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
590cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
591cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
5928d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            case 'chek':
5938d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            {
594a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                int32_t generation;
595a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                CHECK(msg->findInt32("generation", &generation));
596a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                if (generation != mCheckGeneration) {
597a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                    // This is an outdated message. Ignore.
598a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                    break;
599a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                }
600a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
6018d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                if (mNumAccessUnitsReceived == 0) {
6026e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGI("stream ended? aborting.");
6038d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    (new AMessage('abor', id()))->post();
6048d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    break;
6058d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
6068d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
6078d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                mNumAccessUnitsReceived = 0;
608e56121bc4cb29c91d736eab181b1f51c4f125e78Andreas Huber                msg->post(kAccessUnitTimeoutUs);
6098d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                break;
6108d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            }
6118d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
612cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'accu':
613cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
614e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                int32_t firstRTCP;
615e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (msg->findInt32("first-rtcp", &firstRTCP)) {
616e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    mReceivedFirstRTCPPacket = true;
617e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                    break;
618e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                }
619e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber
6208d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                ++mNumAccessUnitsReceived;
621a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                postAccessUnitTimeoutCheck();
6228d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
623cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                size_t trackIndex;
624cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findSize("track-index", &trackIndex));
625cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
6267aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                if (trackIndex >= mTracks.size()) {
6276e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGV("late packets ignored.");
6287aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    break;
6297aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                }
6307aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
6318d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                TrackInfo *track = &mTracks.editItemAt(trackIndex);
6328d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
633ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                int32_t eos;
634ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                if (msg->findInt32("eos", &eos)) {
6356e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGI("received BYE on track index %d", trackIndex);
636ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber#if 0
637ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                    track->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
638ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber#endif
639ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                    return;
640ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber                }
641ef7af7fec702db2fde72b16dedf9064585e6db77Andreas Huber
642cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<RefBase> obj;
643cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findObject("access-unit", &obj));
644cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
645cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());
646cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
6478d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                uint32_t seqNum = (uint32_t)accessUnit->int32Data();
6488d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
6496f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (mSeekPending) {
6506e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGV("we're seeking, dropping stale packet.");
6516f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    break;
6526f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
6536f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber
6548d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                if (seqNum < track->mFirstSeqNumInSegment) {
6556e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGV("dropping stale access-unit (%d < %d)",
6566e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                         seqNum, track->mFirstSeqNumInSegment);
6578d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    break;
6588d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
6598d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
660cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                uint64_t ntpTime;
661cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(accessUnit->meta()->findInt64(
662cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                            "ntp-time", (int64_t *)&ntpTime));
663cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
6648d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                uint32_t rtpTime;
6658d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                CHECK(accessUnit->meta()->findInt32(
6668d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                            "rtp-time", (int32_t *)&rtpTime));
6678d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
6688d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                if (track->mNewSegment) {
6698d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    track->mNewSegment = false;
6708d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
6716e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGV("first segment unit ntpTime=0x%016llx rtpTime=%u seq=%d",
6726e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                         ntpTime, rtpTime, seqNum);
6738d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
6748d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
675cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                if (mFirstAccessUnit) {
6767aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    mDoneMsg->setInt32("result", OK);
6777aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    mDoneMsg->post();
6787aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    mDoneMsg = NULL;
6797aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
680cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                    mFirstAccessUnit = false;
681cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                    mFirstAccessUnitNTP = ntpTime;
682cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                }
683cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
684cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                if (ntpTime >= mFirstAccessUnitNTP) {
685cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                    ntpTime -= mFirstAccessUnitNTP;
686cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                } else {
687cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                    ntpTime = 0;
688cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                }
689cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
690cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
691cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
692cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                accessUnit->meta()->setInt64("timeUs", timeUs);
693cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
694348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber#if 0
695348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                int32_t damaged;
696348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                if (accessUnit->meta()->findInt32("damaged", &damaged)
697348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                        && damaged != 0) {
6986e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGI("ignoring damaged AU");
699348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                } else
700348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber#endif
701348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                {
702348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                    TrackInfo *track = &mTracks.editItemAt(trackIndex);
703348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                    track->mPacketSource->queueAccessUnit(accessUnit);
704348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber                }
705cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
706cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
707cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
708cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            case 'seek':
709cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            {
7100dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                sp<AMessage> doneMsg;
7110dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                CHECK(msg->findMessage("doneMsg", &doneMsg));
7120dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
713cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                if (mSeekPending) {
7140dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                    doneMsg->post();
7150dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                    break;
7160dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                }
7170dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
7180dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                if (!mSeekable) {
7190dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                    LOGW("This is a live stream, ignoring seek request.");
7200dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                    doneMsg->post();
721cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                    break;
722cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                }
723cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
724cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                int64_t timeUs;
725cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(msg->findInt64("time", &timeUs));
726cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
727cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                mSeekPending = true;
728cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
729a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                // Disable the access unit timeout until we resumed
730a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                // playback again.
731a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                mCheckPending = true;
732a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                ++mCheckGeneration;
733a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
734cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                AString request = "PAUSE ";
735cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionURL);
736cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(" RTSP/1.0\r\n");
737cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
738cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("Session: ");
739cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionID);
740cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
741cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
742cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
743cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
744cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                sp<AMessage> reply = new AMessage('see1', id());
745cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                reply->setInt64("time", timeUs);
7460dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                reply->setMessage("doneMsg", doneMsg);
747cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                mConn->sendRequest(request.c_str(), reply);
748cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                break;
749cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            }
750cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
751cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            case 'see1':
752cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            {
7538d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                // Session is paused now.
7548d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
7558d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    mTracks.editItemAt(i).mPacketSource->flushQueue();
7568d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                }
7578d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
758cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                int64_t timeUs;
759cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(msg->findInt64("time", &timeUs));
760cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
761cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                AString request = "PLAY ";
762cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionURL);
763cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(" RTSP/1.0\r\n");
764cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
765cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("Session: ");
766cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(mSessionID);
767cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
768cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
769cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append(
770cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                        StringPrintf(
771cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                            "Range: npt=%lld-\r\n", timeUs / 1000000ll));
772cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
773cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                request.append("\r\n");
774cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
7750dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                sp<AMessage> doneMsg;
7760dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                CHECK(msg->findMessage("doneMsg", &doneMsg));
7770dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
778cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                sp<AMessage> reply = new AMessage('see2', id());
7790dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                reply->setMessage("doneMsg", doneMsg);
780cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                mConn->sendRequest(request.c_str(), reply);
781cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                break;
782cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            }
783cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
784cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            case 'see2':
785cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            {
786cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(mSeekPending);
787cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
788cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                int32_t result;
789cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                CHECK(msg->findInt32("result", &result));
7908d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
7916e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                LOGI("PLAY completed with result %d (%s)",
7926e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                     result, strerror(-result));
7938d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
794a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                mCheckPending = false;
795a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber                postAccessUnitTimeoutCheck();
796a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
7976f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (result == OK) {
7986f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    sp<RefBase> obj;
7996f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    CHECK(msg->findObject("response", &obj));
8006f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    sp<ARTSPResponse> response =
8016f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
802cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
8036f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    if (response->mStatusCode != 200) {
8046f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        result = UNKNOWN_ERROR;
8056f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    } else {
8066f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                        parsePlayResponse(response);
807cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
8086e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                        LOGI("seek completed.");
8096f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    }
8106f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
811cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
8126f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                if (result != OK) {
8136e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                    LOGE("seek failed, aborting.");
8146f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                    (new AMessage('abor', id()))->post();
8156f85dba3768089679ff5e35ad2f1841918d0adb2Andreas Huber                }
8168d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
8178d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                mSeekPending = false;
8180dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
8190dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                sp<AMessage> doneMsg;
8200dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                CHECK(msg->findMessage("doneMsg", &doneMsg));
8210dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
8220dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber                doneMsg->post();
823cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber                break;
824cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber            }
825cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber
8260792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            case 'biny':
8270792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            {
8280792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                sp<RefBase> obj;
8290792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                CHECK(msg->findObject("buffer", &obj));
8300792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
8310792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
8320792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                int32_t index;
8330792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                CHECK(buffer->meta()->findInt32("index", &index));
8340792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
8350792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                mRTPConn->injectPacket(index, buffer);
8360792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                break;
8370792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            }
8380792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
8390792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            case 'tiou':
8400792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            {
841e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber                if (!mReceivedFirstRTCPPacket) {
8427aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    if (mTryTCPInterleaving) {
8436e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                        LOGW("Never received any data, disconnecting.");
8447aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        (new AMessage('abor', id()))->post();
8457aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    } else {
8466e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber                        LOGW("Never received any data, switching transports.");
8477aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
8487aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        mTryTCPInterleaving = true;
8497aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
8507aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        sp<AMessage> msg = new AMessage('abor', id());
8517aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        msg->setInt32("reconnect", true);
8527aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                        msg->post();
8537aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    }
8540792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                }
8550792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber                break;
8560792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber            }
8570792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
858cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            default:
859cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                TRESPASS();
860cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
861cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
862cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
863cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
864a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber    void postAccessUnitTimeoutCheck() {
865a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        if (mCheckPending) {
866a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber            return;
867a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        }
868a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
869a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        mCheckPending = true;
870a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        sp<AMessage> check = new AMessage('chek', id());
871a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        check->setInt32("generation", mCheckGeneration);
872a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber        check->post(kAccessUnitTimeoutUs);
873a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber    }
874a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber
8758d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    static void SplitString(
8768d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            const AString &s, const char *separator, List<AString> *items) {
8778d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        items->clear();
8788d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        size_t start = 0;
8798d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        while (start < s.size()) {
8808d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            ssize_t offset = s.find(separator, start);
8818d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
8828d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            if (offset < 0) {
8838d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                items->push_back(AString(s, start, s.size() - start));
8848d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                break;
8858d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            }
8868d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
8878d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            items->push_back(AString(s, start, offset - start));
8888d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            start = offset + strlen(separator);
8898d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
8908d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    }
8918d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
8928d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    void parsePlayResponse(const sp<ARTSPResponse> &response) {
8930dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber        mSeekable = false;
8940dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
8958d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        ssize_t i = response->mHeaders.indexOfKey("range");
8968d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        if (i < 0) {
8978d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            // Server doesn't even tell use what range it is going to
8988d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            // play, therefore we won't support seeking.
8998d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            return;
9008d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
9018d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9028d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        AString range = response->mHeaders.valueAt(i);
9036e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber        LOGV("Range: %s", range.c_str());
9048d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9058d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        AString val;
9068d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        CHECK(GetAttribute(range.c_str(), "npt", &val));
9078d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        float npt1, npt2;
9088d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9098d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        if (val == "now-") {
9108d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            // This is a live stream and therefore not seekable.
9118d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            return;
9128d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        } else {
9138d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK_EQ(sscanf(val.c_str(), "%f-%f", &npt1, &npt2), 2);
9148d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
9158d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9168d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        i = response->mHeaders.indexOfKey("rtp-info");
9178d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        CHECK_GE(i, 0);
9188d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9198d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        AString rtpInfo = response->mHeaders.valueAt(i);
9208d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        List<AString> streamInfos;
9218d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        SplitString(rtpInfo, ",", &streamInfos);
9228d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9238d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        int n = 1;
9248d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        for (List<AString>::iterator it = streamInfos.begin();
9258d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber             it != streamInfos.end(); ++it) {
9268d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            (*it).trim();
9276e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber            LOGV("streamInfo[%d] = %s", n, (*it).c_str());
9288d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9298d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK(GetAttribute((*it).c_str(), "url", &val));
9308d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9318d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            size_t trackIndex = 0;
9328d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            while (trackIndex < mTracks.size()
9338d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    && !(val == mTracks.editItemAt(trackIndex).mURL)) {
9348d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                ++trackIndex;
9358d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            }
9368d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK_LT(trackIndex, mTracks.size());
9378d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9388d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK(GetAttribute((*it).c_str(), "seq", &val));
9398d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9408d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            char *end;
9418d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            unsigned long seq = strtoul(val.c_str(), &end, 10);
9428d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9438d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            TrackInfo *info = &mTracks.editItemAt(trackIndex);
9448d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            info->mFirstSeqNumInSegment = seq;
9458d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            info->mNewSegment = true;
9468d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9478d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            CHECK(GetAttribute((*it).c_str(), "rtptime", &val));
9488d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9498d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            uint32_t rtpTime = strtoul(val.c_str(), &end, 10);
9508d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9516e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber            LOGV("track #%d: rtpTime=%u <=> ntp=%.2f", n, rtpTime, npt1);
9528d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9538d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            info->mPacketSource->setNormalPlayTimeMapping(
9548d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber                    rtpTime, (int64_t)(npt1 * 1E6));
9558d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
9568d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber            ++n;
9578d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        }
9580dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber
9590dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber        mSeekable = true;
9608d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    }
9618d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
962cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<APacketSource> getPacketSource(size_t index) {
963cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK_GE(index, 0u);
964cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK_LT(index, mTracks.size());
965cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
966cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        return mTracks.editItemAt(index).mPacketSource;
967cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
968cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
969cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    size_t countTracks() const {
970cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        return mTracks.size();
971cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
972cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
973cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huberprivate:
974cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ALooper> mLooper;
975348a8eab84f4bba76c04ca83b2f5418467aa1a48Andreas Huber    sp<ALooper> mNetLooper;
976cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ARTSPConnection> mConn;
977cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ARTPConnection> mRTPConn;
978cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ASessionDescription> mSessionDesc;
979cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mSessionURL;
980cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mBaseURL;
981cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mSessionID;
982cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    bool mSetupTracksSuccessful;
983cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber    bool mSeekPending;
984cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber    bool mFirstAccessUnit;
985cce326fe43411855aca2f719e505b051bc4b61b3Andreas Huber    uint64_t mFirstAccessUnitNTP;
9868d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    int64_t mNumAccessUnitsReceived;
9878d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber    bool mCheckPending;
988a9d9dd2425c32f6868c35f49a3e8f29aafba931aAndreas Huber    int32_t mCheckGeneration;
9897aef03379179c109c2547c33c410bfc93c8db576Andreas Huber    bool mTryTCPInterleaving;
990e7d3e90d8761f52a6acfdcd926f0392aca8ebb52Andreas Huber    bool mReceivedFirstRTCPPacket;
9910dcd837af4169bdb6fb2a0c384722dc4f57433c6Andreas Huber    bool mSeekable;
992cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
993cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    struct TrackInfo {
9948d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        AString mURL;
995cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        int mRTPSocket;
996cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        int mRTCPSocket;
9970792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber        bool mUsingInterleavedTCP;
9988d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        uint32_t mFirstSeqNumInSegment;
9998d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        bool mNewSegment;
1000cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1001cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sp<APacketSource> mPacketSource;
1002cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    };
1003cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    Vector<TrackInfo> mTracks;
1004cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
10051b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber    sp<AMessage> mDoneMsg;
10061b543242102ef3c28145c6ad50ee8e8ce2fb26d3Andreas Huber
1007cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    void setupTrack(size_t index) {
100839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        sp<APacketSource> source =
100939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            new APacketSource(mSessionDesc, index);
10107aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
101139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (source->initCheck() != OK) {
10126e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber            LOGW("Unsupported format. Ignoring track #%d.", index);
101339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
101439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            sp<AMessage> reply = new AMessage('setu', id());
101539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            reply->setSize("index", index);
101639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            reply->setInt32("result", ERROR_UNSUPPORTED);
101739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            reply->post();
101839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            return;
101939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
102039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
1021cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString url;
1022cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK(mSessionDesc->findAttribute(index, "a=control", &url));
1023cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1024cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString trackURL;
1025cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK(MakeURL(mBaseURL.c_str(), url.c_str(), &trackURL));
1026cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1027cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mTracks.push(TrackInfo());
1028cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1);
10298d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        info->mURL = trackURL;
103039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        info->mPacketSource = source;
10310792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber        info->mUsingInterleavedTCP = false;
10328d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        info->mFirstSeqNumInSegment = 0;
10338d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber        info->mNewSegment = true;
10348d342970108926c4ea355c90d26a2a353ec0fd47Andreas Huber
10356e4c5c499999c04c2477b987f9e64f3ff2bf1a06Andreas Huber        LOGV("track #%d URL=%s", mTracks.size(), trackURL.c_str());
1036cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1037cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString request = "SETUP ";
1038cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append(trackURL);
1039cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append(" RTSP/1.0\r\n");
1040cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
10417aef03379179c109c2547c33c410bfc93c8db576Andreas Huber        if (mTryTCPInterleaving) {
10427aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            size_t interleaveIndex = 2 * (mTracks.size() - 1);
10437aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            info->mUsingInterleavedTCP = true;
10447aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            info->mRTPSocket = interleaveIndex;
10457aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            info->mRTCPSocket = interleaveIndex + 1;
10467aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
10477aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("Transport: RTP/AVP/TCP;interleaved=");
10487aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(interleaveIndex);
10497aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("-");
10507aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(interleaveIndex + 1);
10517aef03379179c109c2547c33c410bfc93c8db576Andreas Huber        } else {
10527aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            unsigned rtpPort;
10537aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            ARTPConnection::MakePortPair(
10547aef03379179c109c2547c33c410bfc93c8db576Andreas Huber                    &info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
10557aef03379179c109c2547c33c410bfc93c8db576Andreas Huber
10567aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
10577aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(rtpPort);
10587aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append("-");
10597aef03379179c109c2547c33c410bfc93c8db576Andreas Huber            request.append(rtpPort + 1);
10607aef03379179c109c2547c33c410bfc93c8db576Andreas Huber        }
10610792ce7e0924ebb0dbe7b7cfcd79d12cbdb03ed2Andreas Huber
1062cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append("\r\n");
1063cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1064cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (index > 1) {
1065cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            request.append("Session: ");
1066cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            request.append(mSessionID);
1067cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            request.append("\r\n");
1068cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1069cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1070cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append("\r\n");
1071cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1072cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sp<AMessage> reply = new AMessage('setu', id());
1073cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        reply->setSize("index", index);
1074cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        reply->setSize("track-index", mTracks.size() - 1);
1075cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mConn->sendRequest(request.c_str(), reply);
1076cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
1077cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1078cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    static bool MakeURL(const char *baseURL, const char *url, AString *out) {
1079cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        out->clear();
1080cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1081cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (strncasecmp("rtsp://", baseURL, 7)) {
1082cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            // Base URL must be absolute
1083cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            return false;
1084cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1085cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1086cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (!strncasecmp("rtsp://", url, 7)) {
1087cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            // "url" is already an absolute URL, ignore base URL.
1088cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->setTo(url);
1089cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            return true;
1090cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1091cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1092cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        size_t n = strlen(baseURL);
1093cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (baseURL[n - 1] == '/') {
1094cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->setTo(baseURL);
1095cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->append(url);
1096cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        } else {
1097cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            char *slashPos = strrchr(baseURL, '/');
1098cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1099cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            if (slashPos > &baseURL[6]) {
1100cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                out->setTo(baseURL, slashPos - baseURL);
1101cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            } else {
1102cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                out->setTo(baseURL);
1103cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
1104cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1105cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->append("/");
1106cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->append(url);
1107cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
1108cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1109cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        return true;
1110cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
1111cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1112cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    DISALLOW_EVIL_CONSTRUCTORS(MyHandler);
1113cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber};
1114cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1115cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber}  // namespace android
1116cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
1117cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif  // MY_HANDLER_H_
1118