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_TRANSMITTER_H_
18cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
19cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#define MY_TRANSMITTER_H_
20cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
21cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include "ARTPConnection.h"
22cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
23cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <arpa/inet.h>
24cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <sys/socket.h>
25cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
26cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <openssl/md5.h>
27cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
28cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/foundation/ADebug.h>
29cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/foundation/base64.h>
30cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/foundation/hexdump.h>
31cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
32cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#ifdef ANDROID
33cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include "VideoSource.h"
34cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
35cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/OMXClient.h>
36cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#include <media/stagefright/OMXCodec.h>
37cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif
38cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
39cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Hubernamespace android {
40cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
41cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#define TRACK_SUFFIX    "trackid=1"
42cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#define PT              96
43cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#define PT_STR          "96"
44cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
45cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#define USERNAME        "bcast"
46cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#define PASSWORD        "test"
47cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
48cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huberstatic int uniformRand(int limit) {
49cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    return ((double)rand() * limit) / RAND_MAX;
50cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber}
51cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
52cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huberstatic bool GetAttribute(const char *s, const char *key, AString *value) {
53cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    value->clear();
54cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
55cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    size_t keyLen = strlen(key);
56cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
57cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    for (;;) {
58cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        const char *colonPos = strchr(s, ';');
59cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
60cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        size_t len =
61cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            (colonPos == NULL) ? strlen(s) : colonPos - s;
62cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
63cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
64cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            value->setTo(&s[keyLen + 1], len - keyLen - 1);
65cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            return true;
66cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
67cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
68cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (colonPos == NULL) {
69cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            return false;
70cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
71cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
72cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        s = colonPos + 1;
73cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
74cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber}
75cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
76cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huberstruct MyTransmitter : public AHandler {
77cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    MyTransmitter(const char *url, const sp<ALooper> &looper)
78cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        : mServerURL(url),
79cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mLooper(looper),
80cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mConn(new ARTSPConnection),
81cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mConnected(false),
82cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mAuthType(NONE),
83cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mRTPSocket(-1),
84cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mRTCPSocket(-1),
85cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mSourceID(rand()),
86cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mSeqNo(uniformRand(65536)),
87cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mRTPTimeBase(rand()),
88cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mNumSamplesSent(0),
89cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mNumRTPSent(0),
90cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mNumRTPOctetsSent(0),
91cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mLastRTPTime(0),
92cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber          mLastNTPTime(0) {
93cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mStreamURL = mServerURL;
94cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mStreamURL.append("/bazong.sdp");
95cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
96cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mTrackURL = mStreamURL;
97cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mTrackURL.append("/");
98cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mTrackURL.append(TRACK_SUFFIX);
99cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
100cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mLooper->registerHandler(this);
101cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mLooper->registerHandler(mConn);
102cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
103cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sp<AMessage> reply = new AMessage('conn', id());
104cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mConn->connect(mServerURL.c_str(), reply);
105cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
106cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#ifdef ANDROID
107cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        int width = 640;
108cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        int height = 480;
109cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
110cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sp<MediaSource> source = new VideoSource(width, height);
111cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
112cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sp<MetaData> encMeta = new MetaData;
113cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        encMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
114cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        encMeta->setInt32(kKeyWidth, width);
115cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        encMeta->setInt32(kKeyHeight, height);
116cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
117cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        OMXClient client;
118cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        client.connect();
119cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
120cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mEncoder = OMXCodec::Create(
121cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                client.interface(), encMeta,
122cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                true /* createEncoder */, source);
123cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
124cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mEncoder->start();
125cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
126cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        MediaBuffer *buffer;
127cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK_EQ(mEncoder->read(&buffer), (status_t)OK);
128cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK(buffer != NULL);
129cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
130cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        makeH264SPropParamSets(buffer);
131cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
132cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        buffer->release();
133cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        buffer = NULL;
134cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif
135cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
136cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
137cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    uint64_t ntpTime() {
138cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        struct timeval tv;
139cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        gettimeofday(&tv, NULL);
140cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
141cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        uint64_t nowUs = tv.tv_sec * 1000000ll + tv.tv_usec;
142cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
143cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        nowUs += ((70ll * 365 + 17) * 24) * 60 * 60 * 1000000ll;
144cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
145cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        uint64_t hi = nowUs / 1000000ll;
146cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        uint64_t lo = ((1ll << 32) * (nowUs % 1000000ll)) / 1000000ll;
147cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
148cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        return (hi << 32) | lo;
149cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
150cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
151cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    void issueAnnounce() {
152cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString sdp;
153cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp = "v=0\r\n";
154cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
155cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append("o=- ");
156cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
157cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        uint64_t ntp = ntpTime();
158cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(ntp);
159cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(" ");
160cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(ntp);
161cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(" IN IP4 127.0.0.0\r\n");
162cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
163cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(
164cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber              "s=Sample\r\n"
165cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber              "i=Playing around with ANNOUNCE\r\n"
166cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber              "c=IN IP4 ");
167cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
168cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        struct in_addr addr;
169cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        addr.s_addr = htonl(mServerIP);
170cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
171cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(inet_ntoa(addr));
172cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
173cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(
174cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber              "\r\n"
175cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber              "t=0 0\r\n"
176cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber              "a=range:npt=now-\r\n");
177cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
178cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#ifdef ANDROID
179cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sp<MetaData> meta = mEncoder->getFormat();
180cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        int32_t width, height;
181cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK(meta->findInt32(kKeyWidth, &width));
182cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK(meta->findInt32(kKeyHeight, &height));
183cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
184cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(
185cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber              "m=video 0 RTP/AVP " PT_STR "\r\n"
186cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber              "b=AS 320000\r\n"
187cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber              "a=rtpmap:" PT_STR " H264/90000\r\n");
188cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
189cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append("a=cliprect 0,0,");
190cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(height);
191cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(",");
192cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(width);
193cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append("\r\n");
194cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
195cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(
196cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber              "a=framesize:" PT_STR " ");
197cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(width);
198cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append("-");
199cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(height);
200cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append("\r\n");
201cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
202cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(
203cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber              "a=fmtp:" PT_STR " profile-level-id=42C015;sprop-parameter-sets=");
204cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
205cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(mSeqParamSet);
206cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(",");
207cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(mPicParamSet);
208cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(";packetization-mode=1\r\n");
209cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#else
210cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append(
211cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                "m=audio 0 RTP/AVP " PT_STR "\r\n"
212cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                "a=rtpmap:" PT_STR " L8/8000/1\r\n");
213cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif
214cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
215cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sdp.append("a=control:" TRACK_SUFFIX "\r\n");
216cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
217cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString request;
218cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append("ANNOUNCE ");
219cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append(mStreamURL);
220cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append(" RTSP/1.0\r\n");
221cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
222cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        addAuthentication(&request, "ANNOUNCE", mStreamURL.c_str());
223cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
224cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append("Content-Type: application/sdp\r\n");
225cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append("Content-Length: ");
226cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append(sdp.size());
227cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append("\r\n");
228cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
229cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append("\r\n");
230cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request.append(sdp);
231cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
232cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        sp<AMessage> reply = new AMessage('anno', id());
233cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        mConn->sendRequest(request.c_str(), reply);
234cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
235cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
236cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    void H(const AString &s, AString *out) {
237cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        out->clear();
238cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
239cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        MD5_CTX m;
240cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        MD5_Init(&m);
241cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        MD5_Update(&m, s.c_str(), s.size());
242cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
243cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        uint8_t key[16];
244cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        MD5_Final(key, &m);
245cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
246cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        for (size_t i = 0; i < 16; ++i) {
247cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            char nibble = key[i] >> 4;
248cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            if (nibble <= 9) {
249cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                nibble += '0';
250cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            } else {
251cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                nibble += 'a' - 10;
252cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
253cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->append(&nibble, 1);
254cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
255cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            nibble = key[i] & 0x0f;
256cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            if (nibble <= 9) {
257cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                nibble += '0';
258cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            } else {
259cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                nibble += 'a' - 10;
260cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
261cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            out->append(&nibble, 1);
262cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
263cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
264cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
265cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    void authenticate(const sp<ARTSPResponse> &response) {
266cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        ssize_t i = response->mHeaders.indexOfKey("www-authenticate");
267cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK_GE(i, 0);
268cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
269cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString value = response->mHeaders.valueAt(i);
270cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
271cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (!strncmp(value.c_str(), "Basic", 5)) {
272cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            mAuthType = BASIC;
273cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        } else {
274cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            CHECK(!strncmp(value.c_str(), "Digest", 6));
275cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            mAuthType = DIGEST;
276cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
277cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            i = value.find("nonce=");
278cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            CHECK_GE(i, 0);
279cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            CHECK_EQ(value.c_str()[i + 6], '\"');
280cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            ssize_t j = value.find("\"", i + 7);
281cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            CHECK_GE(j, 0);
282cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
283cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            mNonce.setTo(value, i + 7, j - i - 7);
284cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
285cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
286cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        issueAnnounce();
287cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
288cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
289cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    void addAuthentication(
290cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            AString *request, const char *method, const char *url) {
291cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (mAuthType == NONE) {
292cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            return;
293cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
294cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
295cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if (mAuthType == BASIC) {
296cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            request->append("Authorization: Basic YmNhc3Q6dGVzdAo=\r\n");
297cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            return;
298cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
299cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
300cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK_EQ((int)mAuthType, (int)DIGEST);
301cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
302cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString A1;
303cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        A1.append(USERNAME);
304cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        A1.append(":");
305cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        A1.append("Streaming Server");
306cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        A1.append(":");
307cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        A1.append(PASSWORD);
308cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
309cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString A2;
310cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        A2.append(method);
311cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        A2.append(":");
312cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        A2.append(url);
313cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
314cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString HA1, HA2;
315cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        H(A1, &HA1);
316cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        H(A2, &HA2);
317cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
318cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString tmp;
319cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        tmp.append(HA1);
320cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        tmp.append(":");
321cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        tmp.append(mNonce);
322cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        tmp.append(":");
323cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        tmp.append(HA2);
324cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
325cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        AString digest;
326cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        H(tmp, &digest);
327cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
328cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append("Authorization: Digest ");
329cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append("nonce=\"");
330cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append(mNonce);
331cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append("\", ");
332cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append("username=\"" USERNAME "\", ");
333cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append("uri=\"");
334cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append(url);
335cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append("\", ");
336cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append("response=\"");
337cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append(digest);
338cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append("\"");
339cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        request->append("\r\n");
340cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
341cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
342cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    virtual void onMessageReceived(const sp<AMessage> &msg) {
343cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        switch (msg->what()) {
344cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'conn':
345cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
346cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
347cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
348cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
349cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                LOG(INFO) << "connection request completed with result "
350cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << result << " (" << strerror(-result) << ")";
351cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
352cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result != OK) {
353cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    (new AMessage('quit', id()))->post();
354cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    break;
355cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
356cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
357cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConnected = true;
358cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
359cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("server-ip", (int32_t *)&mServerIP));
360cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
361cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                issueAnnounce();
362cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
363cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
364cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
365cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'anno':
366cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
367cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
368cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
369cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
370cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                LOG(INFO) << "ANNOUNCE completed with result "
371cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << result << " (" << strerror(-result) << ")";
372cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
373cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<RefBase> obj;
374cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findObject("response", &obj));
375cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<ARTSPResponse> response;
376cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
377cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
378cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    response = static_cast<ARTSPResponse *>(obj.get());
379cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(response != NULL);
380cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
381cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    if (response->mStatusCode == 401) {
382cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        if (mAuthType != NONE) {
383cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                            LOG(INFO) << "FAILED to authenticate";
384cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                            (new AMessage('quit', id()))->post();
385cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                            break;
386cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        }
387cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
388cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        authenticate(response);
389cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        break;
390cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    }
391cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
392cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
393cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result != OK || response->mStatusCode != 200) {
394cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    (new AMessage('quit', id()))->post();
395cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    break;
396cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
397cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
398cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                unsigned rtpPort;
399cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                ARTPConnection::MakePortPair(&mRTPSocket, &mRTCPSocket, &rtpPort);
400cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
401cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                // (new AMessage('poll', id()))->post();
402cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
403cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                AString request;
404cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("SETUP ");
405cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mTrackURL);
406cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(" RTSP/1.0\r\n");
407cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
408cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                addAuthentication(&request, "SETUP", mTrackURL.c_str());
409cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
410cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("Transport: RTP/AVP;unicast;client_port=");
411cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(rtpPort);
412cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("-");
413cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(rtpPort + 1);
414cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(";mode=record\r\n");
415cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
416cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
417cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<AMessage> reply = new AMessage('setu', id());
418cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConn->sendRequest(request.c_str(), reply);
419cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
420cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
421cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
422cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#if 0
423cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'poll':
424cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
425cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                fd_set rs;
426cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                FD_ZERO(&rs);
427cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                FD_SET(mRTCPSocket, &rs);
428cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
429cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                struct timeval tv;
430cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                tv.tv_sec = 0;
431cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                tv.tv_usec = 0;
432cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
433cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int res = select(mRTCPSocket + 1, &rs, NULL, NULL, &tv);
434cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
435cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (res == 1) {
436cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<ABuffer> buffer = new ABuffer(65536);
437cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    ssize_t n = recv(mRTCPSocket, buffer->data(), buffer->size(), 0);
438cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
439cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    if (n <= 0) {
440cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        LOG(ERROR) << "recv returned " << n;
441cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    } else {
442cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        LOG(INFO) << "recv returned " << n << " bytes of data.";
443cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
444cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        hexdump(buffer->data(), n);
445cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    }
446cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
447cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
448cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                msg->post(50000);
449cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
450cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
451cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif
452cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
453cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'setu':
454cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
455cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
456cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
457cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
458cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                LOG(INFO) << "SETUP completed with result "
459cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << result << " (" << strerror(-result) << ")";
460cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
461cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<RefBase> obj;
462cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findObject("response", &obj));
463cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<ARTSPResponse> response;
464cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
465cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
466cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    response = static_cast<ARTSPResponse *>(obj.get());
467cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(response != NULL);
468cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
469cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
470cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result != OK || response->mStatusCode != 200) {
471cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    (new AMessage('quit', id()))->post();
472cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    break;
473cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
474cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
475cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                ssize_t i = response->mHeaders.indexOfKey("session");
476cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK_GE(i, 0);
477cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mSessionID = response->mHeaders.valueAt(i);
478cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                i = mSessionID.find(";");
479cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (i >= 0) {
480cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    // Remove options, i.e. ";timeout=90"
481cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mSessionID.erase(i, mSessionID.size() - i);
482cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
483cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
484cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                i = response->mHeaders.indexOfKey("transport");
485cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK_GE(i, 0);
486cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                AString transport = response->mHeaders.valueAt(i);
487cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
488cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                LOG(INFO) << "transport = '" << transport << "'";
489cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
490cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                AString value;
491cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(GetAttribute(transport.c_str(), "server_port", &value));
492cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
493cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                unsigned rtpPort, rtcpPort;
494cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK_EQ(sscanf(value.c_str(), "%u-%u", &rtpPort, &rtcpPort), 2);
495cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
496cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(GetAttribute(transport.c_str(), "source", &value));
497cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
498cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                memset(mRemoteAddr.sin_zero, 0, sizeof(mRemoteAddr.sin_zero));
499cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mRemoteAddr.sin_family = AF_INET;
500cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mRemoteAddr.sin_addr.s_addr = inet_addr(value.c_str());
501cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mRemoteAddr.sin_port = htons(rtpPort);
502cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
503cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mRemoteRTCPAddr = mRemoteAddr;
504cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mRemoteRTCPAddr.sin_port = htons(rtpPort + 1);
505cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
506cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK_EQ(0, connect(mRTPSocket,
507cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                                    (const struct sockaddr *)&mRemoteAddr,
508cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                                    sizeof(mRemoteAddr)));
509cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
510cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK_EQ(0, connect(mRTCPSocket,
511cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                                    (const struct sockaddr *)&mRemoteRTCPAddr,
512cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                                    sizeof(mRemoteRTCPAddr)));
513cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
514cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                uint32_t x = ntohl(mRemoteAddr.sin_addr.s_addr);
515cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                LOG(INFO) << "sending data to "
516cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << (x >> 24)
517cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << "."
518cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << ((x >> 16) & 0xff)
519cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << "."
520cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << ((x >> 8) & 0xff)
521cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << "."
522cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << (x & 0xff)
523cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << ":"
524cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << rtpPort;
525cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
526cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                AString request;
527cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("RECORD ");
528cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mStreamURL);
529cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(" RTSP/1.0\r\n");
530cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
531cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                addAuthentication(&request, "RECORD", mStreamURL.c_str());
532cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
533cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("Session: ");
534cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mSessionID);
535cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
536cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
537cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
538cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<AMessage> reply = new AMessage('reco', id());
539cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConn->sendRequest(request.c_str(), reply);
540cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
541cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
542cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
543cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'reco':
544cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
545cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
546cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
547cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
548cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                LOG(INFO) << "RECORD completed with result "
549cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << result << " (" << strerror(-result) << ")";
550cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
551cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<RefBase> obj;
552cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findObject("response", &obj));
553cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<ARTSPResponse> response;
554cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
555cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
556cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    response = static_cast<ARTSPResponse *>(obj.get());
557cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(response != NULL);
558cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
559cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
560cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result != OK) {
561cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    (new AMessage('quit', id()))->post();
562cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    break;
563cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
564cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
565cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                (new AMessage('more', id()))->post();
566cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                (new AMessage('sr  ', id()))->post();
567cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                (new AMessage('aliv', id()))->post(30000000ll);
568cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
569cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
570cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
571cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'aliv':
572cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
573cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (!mConnected) {
574cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    break;
575cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
576cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
577cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                AString request;
578cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("OPTIONS ");
579cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mStreamURL);
580cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(" RTSP/1.0\r\n");
581cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
582cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                addAuthentication(&request, "RECORD", mStreamURL.c_str());
583cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
584cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("Session: ");
585cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mSessionID);
586cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
587cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
588cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
589cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<AMessage> reply = new AMessage('opts', id());
590cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConn->sendRequest(request.c_str(), reply);
591cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
592cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
593cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
594cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'opts':
595cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
596cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
597cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
598cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
599cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                LOG(INFO) << "OPTIONS completed with result "
600cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << result << " (" << strerror(-result) << ")";
601cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
602cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (!mConnected) {
603cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    break;
604cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
605cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
606cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                (new AMessage('aliv', id()))->post(30000000ll);
607cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
608cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
609cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
610cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'more':
611cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
612cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (!mConnected) {
613cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    break;
614cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
615cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
616cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<ABuffer> buffer = new ABuffer(65536);
617cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                uint8_t *data = buffer->data();
618cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[0] = 0x80;
619cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[1] = (1 << 7) | PT;  // M-bit
620cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[2] = (mSeqNo >> 8) & 0xff;
621cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[3] = mSeqNo & 0xff;
622cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[8] = mSourceID >> 24;
623cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[9] = (mSourceID >> 16) & 0xff;
624cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[10] = (mSourceID >> 8) & 0xff;
625cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[11] = mSourceID & 0xff;
626cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
627cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#ifdef ANDROID
628cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                MediaBuffer *mediaBuf = NULL;
629cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                for (;;) {
630cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK_EQ(mEncoder->read(&mediaBuf), (status_t)OK);
631cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    if (mediaBuf->range_length() > 0) {
632cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        break;
633cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    }
634cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mediaBuf->release();
635cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mediaBuf = NULL;
636cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
637cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
638cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int64_t timeUs;
639cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(mediaBuf->meta_data()->findInt64(kKeyTime, &timeUs));
640cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
641cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100ll);
642cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
643cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                const uint8_t *mediaData =
644cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    (const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
645cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
646cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(!memcmp("\x00\x00\x00\x01", mediaData, 4));
647cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
648cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK_LE(mediaBuf->range_length() - 4 + 12, buffer->size());
649cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
650cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                memcpy(&data[12],
651cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                       mediaData + 4, mediaBuf->range_length() - 4);
652cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
653cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                buffer->setRange(0, mediaBuf->range_length() - 4 + 12);
654cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
655cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mediaBuf->release();
656cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mediaBuf = NULL;
657cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#else
658cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                uint32_t rtpTime = mRTPTimeBase + mNumRTPSent * 128;
659cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                memset(&data[12], 0, 128);
660cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                buffer->setRange(0, 12 + 128);
661cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif
662cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
663cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[4] = rtpTime >> 24;
664cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[5] = (rtpTime >> 16) & 0xff;
665cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[6] = (rtpTime >> 8) & 0xff;
666cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                data[7] = rtpTime & 0xff;
667cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
668cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                ssize_t n = send(
669cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        mRTPSocket, data, buffer->size(), 0);
670cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (n < 0) {
671cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    LOG(ERROR) << "send failed (" << strerror(errno) << ")";
672cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
673cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK_EQ(n, (ssize_t)buffer->size());
674cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
675cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                ++mSeqNo;
676cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
677cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                ++mNumRTPSent;
678cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mNumRTPOctetsSent += buffer->size() - 12;
679cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
680cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mLastRTPTime = rtpTime;
681cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mLastNTPTime = ntpTime();
682cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
683cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#ifdef ANDROID
684cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (mNumRTPSent < 60 * 25) {  // 60 secs worth
685cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    msg->post(40000);
686cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#else
687cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (mNumRTPOctetsSent < 8000 * 60) {
688cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    msg->post(1000000ll * 128 / 8000);
689cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif
690cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                } else {
691cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    LOG(INFO) << "That's enough, pausing.";
692cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
693cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    AString request;
694cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("PAUSE ");
695cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(mStreamURL);
696cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(" RTSP/1.0\r\n");
697cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
698cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    addAuthentication(&request, "PAUSE", mStreamURL.c_str());
699cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
700cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("Session: ");
701cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append(mSessionID);
702cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("\r\n");
703cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    request.append("\r\n");
704cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
705cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    sp<AMessage> reply = new AMessage('paus', id());
706cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->sendRequest(request.c_str(), reply);
707cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
708cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
709cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
710cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
711cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'sr  ':
712cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
713cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (!mConnected) {
714cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    break;
715cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
716cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
717cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<ABuffer> buffer = new ABuffer(65536);
718cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                buffer->setRange(0, 0);
719cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
720cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                addSR(buffer);
721cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                addSDES(buffer);
722cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
723cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                uint8_t *data = buffer->data();
724cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                ssize_t n = send(
725cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                        mRTCPSocket, data, buffer->size(), 0);
726cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK_EQ(n, (ssize_t)buffer->size());
727cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
728cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                msg->post(3000000);
729cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
730cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
731cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
732cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'paus':
733cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
734cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
735cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
736cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
737cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                LOG(INFO) << "PAUSE completed with result "
738cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << result << " (" << strerror(-result) << ")";
739cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
740cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<RefBase> obj;
741cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findObject("response", &obj));
742cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<ARTSPResponse> response;
743cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
744cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                AString request;
745cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("TEARDOWN ");
746cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mStreamURL);
747cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(" RTSP/1.0\r\n");
748cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
749cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                addAuthentication(&request, "TEARDOWN", mStreamURL.c_str());
750cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
751cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("Session: ");
752cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append(mSessionID);
753cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
754cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                request.append("\r\n");
755cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
756cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<AMessage> reply = new AMessage('tear', id());
757cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConn->sendRequest(request.c_str(), reply);
758cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
759cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
760cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
761cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'tear':
762cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
763cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                int32_t result;
764cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findInt32("result", &result));
765cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
766cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                LOG(INFO) << "TEARDOWN completed with result "
767cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     << result << " (" << strerror(-result) << ")";
768cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
769cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<RefBase> obj;
770cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                CHECK(msg->findObject("response", &obj));
771cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                sp<ARTSPResponse> response;
772cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
773cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (result == OK) {
774cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    response = static_cast<ARTSPResponse *>(obj.get());
775cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    CHECK(response != NULL);
776cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
777cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
778cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                (new AMessage('quit', id()))->post();
779cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
780cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
781cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
782cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'disc':
783cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
784cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                LOG(INFO) << "disconnect completed";
785cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
786cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mConnected = false;
787cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                (new AMessage('quit', id()))->post();
788cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
789cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
790cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
791cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            case 'quit':
792cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            {
793cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (mConnected) {
794cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mConn->disconnect(new AMessage('disc', id()));
795cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    break;
796cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
797cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
798cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (mRTPSocket >= 0) {
799cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    close(mRTPSocket);
800cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mRTPSocket = -1;
801cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
802cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
803cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                if (mRTCPSocket >= 0) {
804cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    close(mRTCPSocket);
805cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    mRTCPSocket = -1;
806cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                }
807cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
808cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#ifdef ANDROID
809cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mEncoder->stop();
810cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mEncoder.clear();
811cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif
812cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
813cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                mLooper->stop();
814cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                break;
815cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
816cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
817cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            default:
818cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                TRESPASS();
819cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
820cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
821cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
822cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huberprotected:
823cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    virtual ~MyTransmitter() {
824cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
825cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
826cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huberprivate:
827cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    enum AuthType {
828cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        NONE,
829cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        BASIC,
830cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        DIGEST
831cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    };
832cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
833cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mServerURL;
834cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mTrackURL;
835cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mStreamURL;
836cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
837cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ALooper> mLooper;
838cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<ARTSPConnection> mConn;
839cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    bool mConnected;
840cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    uint32_t mServerIP;
841cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AuthType mAuthType;
842cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mNonce;
843cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mSessionID;
844cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    int mRTPSocket, mRTCPSocket;
845cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    uint32_t mSourceID;
846cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    uint32_t mSeqNo;
847cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    uint32_t mRTPTimeBase;
848cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    struct sockaddr_in mRemoteAddr;
849cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    struct sockaddr_in mRemoteRTCPAddr;
850cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    size_t mNumSamplesSent;
851cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    uint32_t mNumRTPSent;
852cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    uint32_t mNumRTPOctetsSent;
853cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    uint32_t mLastRTPTime;
854cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    uint64_t mLastNTPTime;
855cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
856cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#ifdef ANDROID
857cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    sp<MediaSource> mEncoder;
858cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mSeqParamSet;
859cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    AString mPicParamSet;
860cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
861cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    void makeH264SPropParamSets(MediaBuffer *buffer) {
862cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        static const char kStartCode[] = "\x00\x00\x00\x01";
863cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
864cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        const uint8_t *data =
865cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            (const uint8_t *)buffer->data() + buffer->range_offset();
866cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        size_t size = buffer->range_length();
867cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
868cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK_GE(size, 0u);
869cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK(!memcmp(kStartCode, data, 4));
870cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
871cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data += 4;
872cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        size -= 4;
873cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
874cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        size_t startCodePos = 0;
875cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        while (startCodePos + 3 < size
876cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                && memcmp(kStartCode, &data[startCodePos], 4)) {
877cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            ++startCodePos;
878cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
879cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
880cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        CHECK_LT(startCodePos + 3, size);
881cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
882cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        encodeBase64(data, startCodePos, &mSeqParamSet);
883cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
884cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        encodeBase64(&data[startCodePos + 4], size - startCodePos - 4,
885cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                     &mPicParamSet);
886cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
887cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif
888cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
889cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    void addSR(const sp<ABuffer> &buffer) {
890cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        uint8_t *data = buffer->data() + buffer->size();
891cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
892cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[0] = 0x80 | 0;
893cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[1] = 200;  // SR
894cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[2] = 0;
895cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[3] = 6;
896cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[4] = mSourceID >> 24;
897cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[5] = (mSourceID >> 16) & 0xff;
898cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[6] = (mSourceID >> 8) & 0xff;
899cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[7] = mSourceID & 0xff;
900cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
901cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[8] = mLastNTPTime >> (64 - 8);
902cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[9] = (mLastNTPTime >> (64 - 16)) & 0xff;
903cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[10] = (mLastNTPTime >> (64 - 24)) & 0xff;
904cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[11] = (mLastNTPTime >> 32) & 0xff;
905cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[12] = (mLastNTPTime >> 24) & 0xff;
906cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[13] = (mLastNTPTime >> 16) & 0xff;
907cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[14] = (mLastNTPTime >> 8) & 0xff;
908cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[15] = mLastNTPTime & 0xff;
909cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
910cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[16] = (mLastRTPTime >> 24) & 0xff;
911cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[17] = (mLastRTPTime >> 16) & 0xff;
912cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[18] = (mLastRTPTime >> 8) & 0xff;
913cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[19] = mLastRTPTime & 0xff;
914cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
915cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[20] = mNumRTPSent >> 24;
916cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[21] = (mNumRTPSent >> 16) & 0xff;
917cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[22] = (mNumRTPSent >> 8) & 0xff;
918cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[23] = mNumRTPSent & 0xff;
919cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
920cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[24] = mNumRTPOctetsSent >> 24;
921cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[25] = (mNumRTPOctetsSent >> 16) & 0xff;
922cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[26] = (mNumRTPOctetsSent >> 8) & 0xff;
923cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[27] = mNumRTPOctetsSent & 0xff;
924cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
925cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        buffer->setRange(buffer->offset(), buffer->size() + 28);
926cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
927cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
928cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    void addSDES(const sp<ABuffer> &buffer) {
929cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        uint8_t *data = buffer->data() + buffer->size();
930cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[0] = 0x80 | 1;
931cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[1] = 202;  // SDES
932cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[4] = mSourceID >> 24;
933cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[5] = (mSourceID >> 16) & 0xff;
934cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[6] = (mSourceID >> 8) & 0xff;
935cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[7] = mSourceID & 0xff;
936cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
937cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        size_t offset = 8;
938cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
939cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[offset++] = 1;  // CNAME
940cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
941cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        static const char *kCNAME = "andih@laptop";
942cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[offset++] = strlen(kCNAME);
943cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
944cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        memcpy(&data[offset], kCNAME, strlen(kCNAME));
945cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        offset += strlen(kCNAME);
946cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
947cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[offset++] = 7;  // NOTE
948cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
949cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        static const char *kNOTE = "Hell's frozen over.";
950cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[offset++] = strlen(kNOTE);
951cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
952cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        memcpy(&data[offset], kNOTE, strlen(kNOTE));
953cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        offset += strlen(kNOTE);
954cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
955cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[offset++] = 0;
956cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
957cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        if ((offset % 4) > 0) {
958cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            size_t count = 4 - (offset % 4);
959cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            switch (count) {
960cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                case 3:
961cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    data[offset++] = 0;
962cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                case 2:
963cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    data[offset++] = 0;
964cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                case 1:
965cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber                    data[offset++] = 0;
966cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber            }
967cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        }
968cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
969cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        size_t numWords = (offset / 4) - 1;
970cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[2] = numWords >> 8;
971cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        data[3] = numWords & 0xff;
972cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
973cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber        buffer->setRange(buffer->offset(), buffer->size() + offset);
974cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    }
975cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
976cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber    DISALLOW_EVIL_CONSTRUCTORS(MyTransmitter);
977cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber};
978cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
979cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber}  // namespace android
980cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber
981cf7b9c7aae758ac0b99833915053c63c2ac46e09Andreas Huber#endif  // MY_TRANSMITTER_H_
982