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