MyHandler.h revision f3d2bdf73c36be549f1ddff4238e97b3629c480d
17a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber/*
27a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * Copyright (C) 2010 The Android Open Source Project
37a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber *
47a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
57a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * you may not use this file except in compliance with the License.
67a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * You may obtain a copy of the License at
77a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber *
87a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
97a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber *
107a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * Unless required by applicable law or agreed to in writing, software
117a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
127a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * See the License for the specific language governing permissions and
147a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber * limitations under the License.
157a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber */
167a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
177a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#ifndef MY_HANDLER_H_
187a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
197a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#define MY_HANDLER_H_
207a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
217a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include "APacketSource.h"
227a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include "ARTPConnection.h"
237a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include "ARTSPConnection.h"
247a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include "ASessionDescription.h"
257a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
26eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber#include <ctype.h>
27eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
287a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include <media/stagefright/foundation/ABuffer.h>
297a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include <media/stagefright/foundation/ADebug.h>
307a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include <media/stagefright/foundation/ALooper.h>
317a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include <media/stagefright/foundation/AMessage.h>
327a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#include <media/stagefright/MediaErrors.h>
337a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
34f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber// If no access units are received within 3 secs, assume that the rtp
35f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber// stream has ended and signal end of stream.
36f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huberstatic int64_t kAccessUnitTimeoutUs = 3000000ll;
37f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber
38f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber// If no access units arrive for the first 10 secs after starting the
39f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber// stream, assume none ever will and signal EOS or switch transports.
40f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huberstatic int64_t kStartupTimeoutUs = 10000000ll;
41f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber
427a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Hubernamespace android {
437a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
44eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huberstatic bool GetAttribute(const char *s, const char *key, AString *value) {
45eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    value->clear();
46eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
47eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    size_t keyLen = strlen(key);
48eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
49eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    for (;;) {
50eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        while (isspace(*s)) {
51eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            ++s;
52eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
53eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
54eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        const char *colonPos = strchr(s, ';');
55eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
56eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        size_t len =
57eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            (colonPos == NULL) ? strlen(s) : colonPos - s;
58eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
59eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
60eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            value->setTo(&s[keyLen + 1], len - keyLen - 1);
61eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            return true;
62eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
63eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
64eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        if (colonPos == NULL) {
65eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            return false;
66eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
67eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
68eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        s = colonPos + 1;
69eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    }
70eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber}
71eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
727a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huberstruct MyHandler : public AHandler {
737a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    MyHandler(const char *url, const sp<ALooper> &looper)
747a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        : mLooper(looper),
754e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber          mNetLooper(new ALooper),
767a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber          mConn(new ARTSPConnection),
777a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber          mRTPConn(new ARTPConnection),
787a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber          mSessionURL(url),
79e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber          mSetupTracksSuccessful(false),
80e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber          mSeekPending(false),
81e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber          mFirstAccessUnit(true),
82eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber          mFirstAccessUnitNTP(0),
83eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber          mNumAccessUnitsReceived(0),
84f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber          mCheckPending(false),
853a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber          mTryTCPInterleaving(false),
863a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber          mReceivedFirstRTCPPacket(false) {
87c4e0b70a21fadb47d70955c71fc31ce1473da925Andreas Huber        mNetLooper->setName("rtsp net");
884e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber        mNetLooper->start(false /* runOnCallingThread */,
894e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                          false /* canCallJava */,
904e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                          PRIORITY_HIGHEST);
914e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber    }
924e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber
938370be11debc574b4a9fee62009009d999e29fa3Andreas Huber    void connect(const sp<AMessage> &doneMsg) {
948370be11debc574b4a9fee62009009d999e29fa3Andreas Huber        mDoneMsg = doneMsg;
958370be11debc574b4a9fee62009009d999e29fa3Andreas Huber
967a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        mLooper->registerHandler(this);
977a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        mLooper->registerHandler(mConn);
984e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber        (1 ? mNetLooper : mLooper)->registerHandler(mRTPConn);
994e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber
1000416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber        sp<AMessage> notify = new AMessage('biny', id());
1010416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber        mConn->observeBinaryData(notify);
1020416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
1038370be11debc574b4a9fee62009009d999e29fa3Andreas Huber        sp<AMessage> reply = new AMessage('conn', id());
1047a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        mConn->connect(mSessionURL.c_str(), reply);
1057a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
1067a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1078370be11debc574b4a9fee62009009d999e29fa3Andreas Huber    void disconnect(const sp<AMessage> &doneMsg) {
1088370be11debc574b4a9fee62009009d999e29fa3Andreas Huber        mDoneMsg = doneMsg;
1098370be11debc574b4a9fee62009009d999e29fa3Andreas Huber
1108370be11debc574b4a9fee62009009d999e29fa3Andreas Huber        (new AMessage('abor', id()))->post();
1114e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber    }
1124e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber
113e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber    void seek(int64_t timeUs) {
114e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber        sp<AMessage> msg = new AMessage('seek', id());
115e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber        msg->setInt64("time", timeUs);
116e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber        msg->post();
117e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber    }
118e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
119eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    int64_t getNormalPlayTimeUs() {
120eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        int64_t maxTimeUs = 0;
121eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        for (size_t i = 0; i < mTracks.size(); ++i) {
122eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            int64_t timeUs = mTracks.editItemAt(i).mPacketSource
123eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                ->getNormalPlayTimeUs();
124eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
125eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            if (i == 0 || timeUs > maxTimeUs) {
126eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                maxTimeUs = timeUs;
127eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            }
128eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
129eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
130eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        return maxTimeUs;
131eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    }
132eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
1337a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    virtual void onMessageReceived(const sp<AMessage> &msg) {
1347a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        switch (msg->what()) {
1357a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'conn':
1367a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
1377a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                int32_t result;
1387a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findInt32("result", &result));
1397a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1407a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                LOG(INFO) << "connection request completed with result "
1417a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                     << result << " (" << strerror(-result) << ")";
1427a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1437a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                if (result == OK) {
1447a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    AString request;
1457a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request = "DESCRIBE ";
1467a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append(mSessionURL);
1477a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append(" RTSP/1.0\r\n");
1487a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append("Accept: application/sdp\r\n");
1497a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append("\r\n");
1507a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1517a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<AMessage> reply = new AMessage('desc', id());
1527a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    mConn->sendRequest(request.c_str(), reply);
1530416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                } else {
1540416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                    (new AMessage('disc', id()))->post();
1557a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
1567a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
1577a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
1587a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1597a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'disc':
1607a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
161f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                int32_t reconnect;
162f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
163f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    sp<AMessage> reply = new AMessage('conn', id());
164f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    mConn->connect(mSessionURL.c_str(), reply);
165f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                } else {
166f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    (new AMessage('quit', id()))->post();
167f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                }
1687a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
1697a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
1707a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1717a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'desc':
1727a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
1737a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                int32_t result;
1747a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findInt32("result", &result));
1757a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1767a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                LOG(INFO) << "DESCRIBE completed with result "
1777a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                     << result << " (" << strerror(-result) << ")";
1787a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1797a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                if (result == OK) {
1807a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<RefBase> obj;
1817a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    CHECK(msg->findObject("response", &obj));
1827a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<ARTSPResponse> response =
1837a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
1847a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1857a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    if (response->mStatusCode == 302) {
1867a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        ssize_t i = response->mHeaders.indexOfKey("location");
1877a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        CHECK_GE(i, 0);
1887a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1897a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        mSessionURL = response->mHeaders.valueAt(i);
1907a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1917a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        AString request;
1927a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        request = "DESCRIBE ";
1937a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        request.append(mSessionURL);
1947a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        request.append(" RTSP/1.0\r\n");
1957a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        request.append("Accept: application/sdp\r\n");
1967a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        request.append("\r\n");
1977a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
1987a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        sp<AMessage> reply = new AMessage('desc', id());
1997a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        mConn->sendRequest(request.c_str(), reply);
2007a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        break;
2017a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    }
2027a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2033a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    if (response->mStatusCode != 200) {
2043a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        result = UNKNOWN_ERROR;
2053a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    } else {
2063a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        mSessionDesc = new ASessionDescription;
2077a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2083a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        mSessionDesc->setTo(
2093a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                                response->mContent->data(),
2103a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                                response->mContent->size());
2117a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
212f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        if (!mSessionDesc->isValid()) {
213f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                            result = ERROR_MALFORMED;
2147a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        } else {
215f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                            ssize_t i = response->mHeaders.indexOfKey("content-base");
2163a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                            if (i >= 0) {
2173a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                                mBaseURL = response->mHeaders.valueAt(i);
2183a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                            } else {
219f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                i = response->mHeaders.indexOfKey("content-location");
220f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                if (i >= 0) {
221f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                    mBaseURL = response->mHeaders.valueAt(i);
222f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                } else {
223f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                    mBaseURL = mSessionURL;
224f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                                }
2253a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                            }
2263a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber
227f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                            CHECK_GT(mSessionDesc->countTracks(), 1u);
228f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                            setupTrack(1);
229f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        }
2307a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    }
2313a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                }
2327a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2333a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                if (result != OK) {
2347a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
2357a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    mConn->disconnect(reply);
2367a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
2377a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
2387a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
2397a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2407a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'setu':
2417a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
2427a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                size_t index;
2437a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findSize("index", &index));
2447a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
24557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                TrackInfo *track = NULL;
2467a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                size_t trackIndex;
24757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                if (msg->findSize("track-index", &trackIndex)) {
24857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                    track = &mTracks.editItemAt(trackIndex);
24957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                }
2507a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2517a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                int32_t result;
2527a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findInt32("result", &result));
2537a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2547a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                LOG(INFO) << "SETUP(" << index << ") completed with result "
2557a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                     << result << " (" << strerror(-result) << ")";
2567a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2573a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                if (result == OK) {
25857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                    CHECK(track != NULL);
2597a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2607a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<RefBase> obj;
2617a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    CHECK(msg->findObject("response", &obj));
2627a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<ARTSPResponse> response =
2637a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
2647a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2653a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    if (response->mStatusCode != 200) {
2663a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        result = UNKNOWN_ERROR;
2673a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    } else {
2683a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        ssize_t i = response->mHeaders.indexOfKey("session");
2693a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        CHECK_GE(i, 0);
2707a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2717a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        mSessionID = response->mHeaders.valueAt(i);
2727a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        i = mSessionID.find(";");
2737a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        if (i >= 0) {
2747a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                            // Remove options, i.e. ";timeout=90"
2757a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                            mSessionID.erase(i, mSessionID.size() - i);
2767a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        }
2777a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2783a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        sp<AMessage> notify = new AMessage('accu', id());
2793a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        notify->setSize("track-index", trackIndex);
2807a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2813a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        mRTPConn->addStream(
2823a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                                track->mRTPSocket, track->mRTCPSocket,
2833a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                                mSessionDesc, index,
2843a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                                notify, track->mUsingInterleavedTCP);
2857a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
2863a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        mSetupTracksSuccessful = true;
2873a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    }
2883a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                }
2893a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber
2903a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                if (result != OK) {
2913a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    if (track) {
2923a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        if (!track->mUsingInterleavedTCP) {
2933a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                            close(track->mRTPSocket);
2943a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                            close(track->mRTCPSocket);
2953a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        }
2963a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber
2973a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                        mTracks.removeItemsAt(trackIndex);
2983a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    }
2997a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
3007a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
30157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                ++index;
30257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                if (index < mSessionDesc->countTracks()) {
30357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                    setupTrack(index);
30457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                } else if (mSetupTracksSuccessful) {
3057a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    AString request = "PLAY ";
3067a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append(mSessionURL);
3077a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append(" RTSP/1.0\r\n");
3087a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3097a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append("Session: ");
3107a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append(mSessionID);
3117a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append("\r\n");
3127a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3137a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    request.append("\r\n");
3147a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3157a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<AMessage> reply = new AMessage('play', id());
3167a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    mConn->sendRequest(request.c_str(), reply);
3177a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                } else {
3187a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
3197a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    mConn->disconnect(reply);
3207a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
3217a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
3227a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
3237a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3247a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'play':
3257a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
3267a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                int32_t result;
3277a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findInt32("result", &result));
3287a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3297a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                LOG(INFO) << "PLAY completed with result "
3307a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                     << result << " (" << strerror(-result) << ")";
3317a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3327a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                if (result == OK) {
3337a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<RefBase> obj;
3347a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    CHECK(msg->findObject("response", &obj));
3357a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<ARTSPResponse> response =
3367a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                        static_cast<ARTSPResponse *>(obj.get());
3377a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
338f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    if (response->mStatusCode != 200) {
339f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        result = UNKNOWN_ERROR;
340f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    } else {
341f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        parsePlayResponse(response);
3427a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
343f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        sp<AMessage> timeout = new AMessage('tiou', id());
344f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        timeout->post(kStartupTimeoutUs);
345f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    }
346f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                }
347eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
348f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                if (result != OK) {
3497a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    sp<AMessage> reply = new AMessage('disc', id());
3507a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                    mConn->disconnect(reply);
3517a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
3527a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3537a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
3547a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
3557a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3567a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'abor':
3577a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
3587a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
359f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    TrackInfo *info = &mTracks.editItemAt(i);
360f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
361f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    info->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
362f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
363f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    if (!info->mUsingInterleavedTCP) {
364f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket);
365f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
366f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        close(info->mRTPSocket);
367f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        close(info->mRTCPSocket);
368f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    }
3697a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                }
370f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                mTracks.clear();
3713a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                mSetupTracksSuccessful = false;
3723a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                mSeekPending = false;
3733a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                mFirstAccessUnit = true;
3743a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                mFirstAccessUnitNTP = 0;
3753a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                mNumAccessUnitsReceived = 0;
3763a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                mReceivedFirstRTCPPacket = false;
3777a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3787a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                sp<AMessage> reply = new AMessage('tear', id());
3797a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
380f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                int32_t reconnect;
381f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
382f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    reply->setInt32("reconnect", true);
383f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                }
384f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
3857a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                AString request;
3867a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request = "TEARDOWN ";
3877a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3887a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                // XXX should use aggregate url from SDP here...
3897a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append(mSessionURL);
3907a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append(" RTSP/1.0\r\n");
3917a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3927a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append("Session: ");
3937a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append(mSessionID);
3947a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append("\r\n");
3957a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3967a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                request.append("\r\n");
3977a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
3987a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                mConn->sendRequest(request.c_str(), reply);
3997a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
4007a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
4017a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4027a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'tear':
4037a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
4047a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                int32_t result;
4057a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findInt32("result", &result));
4067a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4077a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                LOG(INFO) << "TEARDOWN completed with result "
4087a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                     << result << " (" << strerror(-result) << ")";
4097a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4107a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                sp<AMessage> reply = new AMessage('disc', id());
411f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
412f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                int32_t reconnect;
413f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                if (msg->findInt32("reconnect", &reconnect) && reconnect) {
414f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    reply->setInt32("reconnect", true);
415f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                }
416f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
4177a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                mConn->disconnect(reply);
4187a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
4197a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
4207a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4217a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'quit':
4227a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
4238370be11debc574b4a9fee62009009d999e29fa3Andreas Huber                if (mDoneMsg != NULL) {
4248370be11debc574b4a9fee62009009d999e29fa3Andreas Huber                    mDoneMsg->setInt32("result", UNKNOWN_ERROR);
4258370be11debc574b4a9fee62009009d999e29fa3Andreas Huber                    mDoneMsg->post();
4268370be11debc574b4a9fee62009009d999e29fa3Andreas Huber                    mDoneMsg = NULL;
4278370be11debc574b4a9fee62009009d999e29fa3Andreas Huber                }
4287a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
4297a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
4307a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
431eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            case 'chek':
432eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            {
433eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                if (mNumAccessUnitsReceived == 0) {
434eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    LOG(INFO) << "stream ended? aborting.";
435eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    (new AMessage('abor', id()))->post();
436eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    break;
437eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                }
438eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
439eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                mNumAccessUnitsReceived = 0;
440f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber                msg->post(kAccessUnitTimeoutUs);
441eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                break;
442eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            }
443eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
4447a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            case 'accu':
4457a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            {
4463a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                int32_t firstRTCP;
4473a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                if (msg->findInt32("first-rtcp", &firstRTCP)) {
4483a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    mReceivedFirstRTCPPacket = true;
4493a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                    break;
4503a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                }
4513a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber
452eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                ++mNumAccessUnitsReceived;
453eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
454eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                if (!mCheckPending) {
455eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    mCheckPending = true;
456eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    sp<AMessage> check = new AMessage('chek', id());
457f6639c46e83a1ccab7b293192c208091d17c61beAndreas Huber                    check->post(kAccessUnitTimeoutUs);
458eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                }
459eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
4607a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                size_t trackIndex;
4617a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findSize("track-index", &trackIndex));
4627a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
463f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                if (trackIndex >= mTracks.size()) {
464f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    LOG(ERROR) << "late packets ignored.";
465f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    break;
466f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                }
467f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
468eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                TrackInfo *track = &mTracks.editItemAt(trackIndex);
469eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
470af063a67b291c4622321a35af6966b8568d5a564Andreas Huber                int32_t eos;
471af063a67b291c4622321a35af6966b8568d5a564Andreas Huber                if (msg->findInt32("eos", &eos)) {
472af063a67b291c4622321a35af6966b8568d5a564Andreas Huber                    LOG(INFO) << "received BYE on track index " << trackIndex;
473af063a67b291c4622321a35af6966b8568d5a564Andreas Huber#if 0
474af063a67b291c4622321a35af6966b8568d5a564Andreas Huber                    track->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
475af063a67b291c4622321a35af6966b8568d5a564Andreas Huber#endif
476af063a67b291c4622321a35af6966b8568d5a564Andreas Huber                    return;
477af063a67b291c4622321a35af6966b8568d5a564Andreas Huber                }
478af063a67b291c4622321a35af6966b8568d5a564Andreas Huber
4797a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                sp<RefBase> obj;
4807a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(msg->findObject("access-unit", &obj));
4817a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
4827a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());
4837a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
484eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                uint32_t seqNum = (uint32_t)accessUnit->int32Data();
485eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
486f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                if (mSeekPending) {
487f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    LOG(INFO) << "we're seeking, dropping stale packet.";
488f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    break;
489f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                }
490f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber
491eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                if (seqNum < track->mFirstSeqNumInSegment) {
492eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    LOG(INFO) << "dropping stale access-unit "
493eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                              << "(" << seqNum << " < "
494eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                              << track->mFirstSeqNumInSegment << ")";
495eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    break;
496eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                }
497eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
4987a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                uint64_t ntpTime;
4997a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                CHECK(accessUnit->meta()->findInt64(
5007a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                            "ntp-time", (int64_t *)&ntpTime));
5017a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
502eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                uint32_t rtpTime;
503eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                CHECK(accessUnit->meta()->findInt32(
504eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                            "rtp-time", (int32_t *)&rtpTime));
505eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
506eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                if (track->mNewSegment) {
507eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    track->mNewSegment = false;
508eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
509eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    LOG(VERBOSE) << "first segment unit ntpTime="
510eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                              << StringPrintf("0x%016llx", ntpTime)
511eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                              << " rtpTime=" << rtpTime
512eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                              << " seq=" << seqNum;
513eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                }
514eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
515e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                if (mFirstAccessUnit) {
516f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    mDoneMsg->setInt32("result", OK);
517f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    mDoneMsg->post();
518f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    mDoneMsg = NULL;
519f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
520e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                    mFirstAccessUnit = false;
521e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                    mFirstAccessUnitNTP = ntpTime;
522e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                }
523e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
524e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                if (ntpTime >= mFirstAccessUnitNTP) {
525e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                    ntpTime -= mFirstAccessUnitNTP;
526e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                } else {
527e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                    ntpTime = 0;
528e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                }
529e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
530e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
531e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
532e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                accessUnit->meta()->setInt64("timeUs", timeUs);
5337a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
5344e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber#if 0
5354e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                int32_t damaged;
5364e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                if (accessUnit->meta()->findInt32("damaged", &damaged)
5374e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                        && damaged != 0) {
5384e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                    LOG(INFO) << "ignoring damaged AU";
5394e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                } else
5404e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber#endif
5414e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                {
5424e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                    TrackInfo *track = &mTracks.editItemAt(trackIndex);
5434e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                    track->mPacketSource->queueAccessUnit(accessUnit);
5444e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber                }
5457a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
5467a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
5477a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
548e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            case 'seek':
549e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            {
550e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                if (mSeekPending) {
551e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                    break;
552e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                }
553e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
554e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                int64_t timeUs;
555e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                CHECK(msg->findInt64("time", &timeUs));
556e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
557e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                mSeekPending = true;
558e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
559e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                AString request = "PAUSE ";
560e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(mSessionURL);
561e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(" RTSP/1.0\r\n");
562e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
563e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("Session: ");
564e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(mSessionID);
565e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("\r\n");
566e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
567e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("\r\n");
568e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
569e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                sp<AMessage> reply = new AMessage('see1', id());
570e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                reply->setInt64("time", timeUs);
571e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                mConn->sendRequest(request.c_str(), reply);
572e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                break;
573e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            }
574e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
575e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            case 'see1':
576e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            {
577eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                // Session is paused now.
578eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                for (size_t i = 0; i < mTracks.size(); ++i) {
579eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    mTracks.editItemAt(i).mPacketSource->flushQueue();
580eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                }
581eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
582e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                int64_t timeUs;
583e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                CHECK(msg->findInt64("time", &timeUs));
584e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
585e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                AString request = "PLAY ";
586e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(mSessionURL);
587e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(" RTSP/1.0\r\n");
588e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
589e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("Session: ");
590e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(mSessionID);
591e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("\r\n");
592e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
593e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append(
594e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                        StringPrintf(
595e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                            "Range: npt=%lld-\r\n", timeUs / 1000000ll));
596e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
597e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                request.append("\r\n");
598e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
599e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                sp<AMessage> reply = new AMessage('see2', id());
600e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                mConn->sendRequest(request.c_str(), reply);
601e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                break;
602e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            }
603e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
604e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            case 'see2':
605e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            {
606e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                CHECK(mSeekPending);
607e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
608e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                int32_t result;
609e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                CHECK(msg->findInt32("result", &result));
610eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
611eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                LOG(INFO) << "PLAY completed with result "
612eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                     << result << " (" << strerror(-result) << ")";
613eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
614f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                if (result == OK) {
615f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    sp<RefBase> obj;
616f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    CHECK(msg->findObject("response", &obj));
617f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    sp<ARTSPResponse> response =
618f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        static_cast<ARTSPResponse *>(obj.get());
619e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
620f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    if (response->mStatusCode != 200) {
621f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        result = UNKNOWN_ERROR;
622f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    } else {
623f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        parsePlayResponse(response);
624e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
625f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                        LOG(INFO) << "seek completed.";
626f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    }
627f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                }
628e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
629f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                if (result != OK) {
630f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    LOG(ERROR) << "seek failed, aborting.";
631f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                    (new AMessage('abor', id()))->post();
632f3d2bdf73c36be549f1ddff4238e97b3629c480dAndreas Huber                }
633eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
634eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                mSeekPending = false;
635e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber                break;
636e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber            }
637e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber
6380416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            case 'biny':
6390416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            {
6400416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                sp<RefBase> obj;
6410416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                CHECK(msg->findObject("buffer", &obj));
6420416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
6430416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
6440416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                int32_t index;
6450416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                CHECK(buffer->meta()->findInt32("index", &index));
6460416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
6470416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                mRTPConn->injectPacket(index, buffer);
6480416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                break;
6490416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            }
6500416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
6510416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            case 'tiou':
6520416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            {
6533a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber                if (!mReceivedFirstRTCPPacket) {
654f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    if (mTryTCPInterleaving) {
655f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        LOG(WARNING) << "Never received any data, disconnecting.";
656f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        (new AMessage('abor', id()))->post();
657f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    } else {
658f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        LOG(WARNING)
659f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                            << "Never received any data, switching transports.";
660f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
661f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        mTryTCPInterleaving = true;
662f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
663f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        sp<AMessage> msg = new AMessage('abor', id());
664f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        msg->setInt32("reconnect", true);
665f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                        msg->post();
666f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    }
6670416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                }
6680416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber                break;
6690416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber            }
6700416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
6717a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            default:
6727a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                TRESPASS();
6737a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                break;
6747a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        }
6757a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
6767a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
677eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    static void SplitString(
678eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            const AString &s, const char *separator, List<AString> *items) {
679eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        items->clear();
680eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        size_t start = 0;
681eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        while (start < s.size()) {
682eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            ssize_t offset = s.find(separator, start);
683eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
684eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            if (offset < 0) {
685eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                items->push_back(AString(s, start, s.size() - start));
686eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                break;
687eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            }
688eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
689eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            items->push_back(AString(s, start, offset - start));
690eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            start = offset + strlen(separator);
691eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
692eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    }
693eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
694eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    void parsePlayResponse(const sp<ARTSPResponse> &response) {
695eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        ssize_t i = response->mHeaders.indexOfKey("range");
696eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        if (i < 0) {
697eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            // Server doesn't even tell use what range it is going to
698eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            // play, therefore we won't support seeking.
699eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            return;
700eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
701eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
702eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        AString range = response->mHeaders.valueAt(i);
703eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        LOG(VERBOSE) << "Range: " << range;
704eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
705eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        AString val;
706eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        CHECK(GetAttribute(range.c_str(), "npt", &val));
707eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        float npt1, npt2;
708eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
709eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        if (val == "now-") {
710eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            // This is a live stream and therefore not seekable.
711eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            return;
712eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        } else {
713eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            CHECK_EQ(sscanf(val.c_str(), "%f-%f", &npt1, &npt2), 2);
714eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
715eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
716eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        i = response->mHeaders.indexOfKey("rtp-info");
717eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        CHECK_GE(i, 0);
718eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
719eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        AString rtpInfo = response->mHeaders.valueAt(i);
720eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        List<AString> streamInfos;
721eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        SplitString(rtpInfo, ",", &streamInfos);
722eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
723eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        int n = 1;
724eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        for (List<AString>::iterator it = streamInfos.begin();
725eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber             it != streamInfos.end(); ++it) {
726eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            (*it).trim();
727eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            LOG(VERBOSE) << "streamInfo[" << n << "] = " << *it;
728eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
729eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            CHECK(GetAttribute((*it).c_str(), "url", &val));
730eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
731eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            size_t trackIndex = 0;
732eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            while (trackIndex < mTracks.size()
733eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    && !(val == mTracks.editItemAt(trackIndex).mURL)) {
734eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                ++trackIndex;
735eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            }
736eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            CHECK_LT(trackIndex, mTracks.size());
737eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
738eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            CHECK(GetAttribute((*it).c_str(), "seq", &val));
739eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
740eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            char *end;
741eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            unsigned long seq = strtoul(val.c_str(), &end, 10);
742eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
743eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            TrackInfo *info = &mTracks.editItemAt(trackIndex);
744eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            info->mFirstSeqNumInSegment = seq;
745eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            info->mNewSegment = true;
746eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
747eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            CHECK(GetAttribute((*it).c_str(), "rtptime", &val));
748eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
749eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            uint32_t rtpTime = strtoul(val.c_str(), &end, 10);
750eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
751eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            LOG(VERBOSE) << "track #" << n
752eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                      << ": rtpTime=" << rtpTime << " <=> npt=" << npt1;
753eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
754eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            info->mPacketSource->setNormalPlayTimeMapping(
755eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber                    rtpTime, (int64_t)(npt1 * 1E6));
756eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
757eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber            ++n;
758eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        }
759eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    }
760eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
7617a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    sp<APacketSource> getPacketSource(size_t index) {
7627a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        CHECK_GE(index, 0u);
7637a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        CHECK_LT(index, mTracks.size());
7647a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7657a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        return mTracks.editItemAt(index).mPacketSource;
7667a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
7677a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7687a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    size_t countTracks() const {
7697a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        return mTracks.size();
7707a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
7717a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7727a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huberprivate:
7737a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    sp<ALooper> mLooper;
7744e4173b0af52bdf2b5730a5837476e400c5b2040Andreas Huber    sp<ALooper> mNetLooper;
7757a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    sp<ARTSPConnection> mConn;
7767a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    sp<ARTPConnection> mRTPConn;
7777a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    sp<ASessionDescription> mSessionDesc;
7787a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    AString mSessionURL;
7797a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    AString mBaseURL;
7807a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    AString mSessionID;
7817a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    bool mSetupTracksSuccessful;
782e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber    bool mSeekPending;
783e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber    bool mFirstAccessUnit;
784e0dd7d396051942ccce0429d7a1fe968d63ac3f7Andreas Huber    uint64_t mFirstAccessUnitNTP;
785eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    int64_t mNumAccessUnitsReceived;
786eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber    bool mCheckPending;
787f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber    bool mTryTCPInterleaving;
7883a48d4d7269a37308eee4affd021adfcab7629a1Andreas Huber    bool mReceivedFirstRTCPPacket;
7897a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7907a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    struct TrackInfo {
791eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        AString mURL;
7927a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        int mRTPSocket;
7937a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        int mRTCPSocket;
7940416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber        bool mUsingInterleavedTCP;
795eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        uint32_t mFirstSeqNumInSegment;
796eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        bool mNewSegment;
7977a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
7987a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        sp<APacketSource> mPacketSource;
7997a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    };
8007a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    Vector<TrackInfo> mTracks;
8017a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8028370be11debc574b4a9fee62009009d999e29fa3Andreas Huber    sp<AMessage> mDoneMsg;
8038370be11debc574b4a9fee62009009d999e29fa3Andreas Huber
8047a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    void setupTrack(size_t index) {
80557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        sp<APacketSource> source =
80657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            new APacketSource(mSessionDesc, index);
807f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
80857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        if (source->initCheck() != OK) {
80957648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            LOG(WARNING) << "Unsupported format. Ignoring track #"
81057648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber                         << index << ".";
81157648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
81257648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            sp<AMessage> reply = new AMessage('setu', id());
81357648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            reply->setSize("index", index);
81457648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            reply->setInt32("result", ERROR_UNSUPPORTED);
81557648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            reply->post();
81657648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber            return;
81757648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        }
81857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber
8197a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        AString url;
8207a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        CHECK(mSessionDesc->findAttribute(index, "a=control", &url));
8217a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8227a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        AString trackURL;
8237a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        CHECK(MakeURL(mBaseURL.c_str(), url.c_str(), &trackURL));
8247a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8257a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        mTracks.push(TrackInfo());
8267a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1);
827eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        info->mURL = trackURL;
82857648e4eec7dd2593af467877bc7cce4aa654759Andreas Huber        info->mPacketSource = source;
8290416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber        info->mUsingInterleavedTCP = false;
830eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        info->mFirstSeqNumInSegment = 0;
831eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        info->mNewSegment = true;
832eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber
833eeb97d91b97f1fc0b26815f098515e9c06d219b8Andreas Huber        LOG(VERBOSE) << "track #" << mTracks.size() << " URL=" << trackURL;
8347a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8357a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        AString request = "SETUP ";
8367a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        request.append(trackURL);
8377a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        request.append(" RTSP/1.0\r\n");
8387a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
839f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber        if (mTryTCPInterleaving) {
840f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            size_t interleaveIndex = 2 * (mTracks.size() - 1);
841f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            info->mUsingInterleavedTCP = true;
842f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            info->mRTPSocket = interleaveIndex;
843f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            info->mRTCPSocket = interleaveIndex + 1;
844f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
845f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append("Transport: RTP/AVP/TCP;interleaved=");
846f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append(interleaveIndex);
847f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append("-");
848f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append(interleaveIndex + 1);
849f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber        } else {
850f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            unsigned rtpPort;
851f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            ARTPConnection::MakePortPair(
852f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber                    &info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
853f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber
854f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
855f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append(rtpPort);
856f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append("-");
857f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber            request.append(rtpPort + 1);
858f88ca7a0335c36732a5550c58c073e549c3cb0ddAndreas Huber        }
8590416da73a0addfc7b3eddfea4a6a0a0215e1dd0bAndreas Huber
8607a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        request.append("\r\n");
8617a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8627a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        if (index > 1) {
8637a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            request.append("Session: ");
8647a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            request.append(mSessionID);
8657a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            request.append("\r\n");
8667a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        }
8677a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8687a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        request.append("\r\n");
8697a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8707a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        sp<AMessage> reply = new AMessage('setu', id());
8717a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        reply->setSize("index", index);
8727a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        reply->setSize("track-index", mTracks.size() - 1);
8737a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        mConn->sendRequest(request.c_str(), reply);
8747a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
8757a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8767a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    static bool MakeURL(const char *baseURL, const char *url, AString *out) {
8777a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        out->clear();
8787a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8797a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        if (strncasecmp("rtsp://", baseURL, 7)) {
8807a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            // Base URL must be absolute
8817a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            return false;
8827a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        }
8837a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8847a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        if (!strncasecmp("rtsp://", url, 7)) {
8857a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            // "url" is already an absolute URL, ignore base URL.
8867a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            out->setTo(url);
8877a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            return true;
8887a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        }
8897a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8907a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        size_t n = strlen(baseURL);
8917a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        if (baseURL[n - 1] == '/') {
8927a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            out->setTo(baseURL);
8937a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            out->append(url);
8947a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        } else {
8957a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            char *slashPos = strrchr(baseURL, '/');
8967a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
8977a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            if (slashPos > &baseURL[6]) {
8987a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                out->setTo(baseURL, slashPos - baseURL);
8997a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            } else {
9007a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber                out->setTo(baseURL);
9017a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            }
9027a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
9037a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            out->append("/");
9047a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber            out->append(url);
9057a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        }
9067a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
9077a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber        return true;
9087a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    }
9097a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
9107a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber    DISALLOW_EVIL_CONSTRUCTORS(MyHandler);
9117a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber};
9127a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
9137a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber}  // namespace android
9147a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber
9157a747b8e0dadf909ea4ac0b67fd88fc14b4eb3f8Andreas Huber#endif  // MY_HANDLER_H_
916