1
/*****************************************************************************
2
* real.c: real rtsp input
3
*****************************************************************************
4
* Copyright (C) 2002-2004 the xine project
5
* Copyright (C) 2005 VideoLAN
6
* $Id: 86eab8ca045453227745b4e6b3755a14cee5cf95 $
8
* Authors: Gildas Bazin <gbazin@videolan.org>
9
* Adapted from xine which itself adapted it from joschkas real tools.
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; either version 2 of the License, or
14
* (at your option) any later version.
16
* This program is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
21
* You should have received a copy of the GNU General Public License along
22
* with this program; if not, write to the Free Software Foundation, Inc.,
23
* 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24
*****************************************************************************/
30
#include <vlc_common.h>
31
#include <vlc_memory.h>
35
#include "real_sdpplin.h"
37
#define XOR_TABLE_LEN 37
38
static const unsigned char xor_table[] = {
39
0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
40
0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
41
0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
42
0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
43
0x10, 0x57, 0x05, 0x18, 0x54, 0x00, 0x00, 0x00 };
45
#define BE_32(x) GetDWBE(x)
46
#define LE_32(x) GetDWLE(x)
47
#define BE_16(x) GetWBE(x)
48
#define LE_16(x) GetWLE(x)
49
#define BE_32C(x,y) do {uint32_t in=y; *(uint32_t *)(x)=GetDWBE(&in);} while(0)
50
#define LE_32C(x,y) do {uint32_t in=y; *(uint32_t *)(x)=GetDWLE(&in);} while(0)
51
#define MAX(x,y) ((x>y) ? x : y)
53
static void hash(char *field, char *param)
63
lprintf("hash input: %x %x %x %x\n", a, b, c, d);
64
lprintf("hash parameter:\n");
66
a = ((b & c) | (~b & d)) + LE_32((param+0x00)) + a - 0x28955B88;
67
a = ((a << 0x07) | (a >> 0x19)) + b;
68
d = ((a & b) | (~a & c)) + LE_32((param+0x04)) + d - 0x173848AA;
69
d = ((d << 0x0c) | (d >> 0x14)) + a;
70
c = ((d & a) | (~d & b)) + LE_32((param+0x08)) + c + 0x242070DB;
71
c = ((c << 0x11) | (c >> 0x0f)) + d;
72
b = ((c & d) | (~c & a)) + LE_32((param+0x0c)) + b - 0x3E423112;
73
b = ((b << 0x16) | (b >> 0x0a)) + c;
74
a = ((b & c) | (~b & d)) + LE_32((param+0x10)) + a - 0x0A83F051;
75
a = ((a << 0x07) | (a >> 0x19)) + b;
76
d = ((a & b) | (~a & c)) + LE_32((param+0x14)) + d + 0x4787C62A;
77
d = ((d << 0x0c) | (d >> 0x14)) + a;
78
c = ((d & a) | (~d & b)) + LE_32((param+0x18)) + c - 0x57CFB9ED;
79
c = ((c << 0x11) | (c >> 0x0f)) + d;
80
b = ((c & d) | (~c & a)) + LE_32((param+0x1c)) + b - 0x02B96AFF;
81
b = ((b << 0x16) | (b >> 0x0a)) + c;
82
a = ((b & c) | (~b & d)) + LE_32((param+0x20)) + a + 0x698098D8;
83
a = ((a << 0x07) | (a >> 0x19)) + b;
84
d = ((a & b) | (~a & c)) + LE_32((param+0x24)) + d - 0x74BB0851;
85
d = ((d << 0x0c) | (d >> 0x14)) + a;
86
c = ((d & a) | (~d & b)) + LE_32((param+0x28)) + c - 0x0000A44F;
87
c = ((c << 0x11) | (c >> 0x0f)) + d;
88
b = ((c & d) | (~c & a)) + LE_32((param+0x2C)) + b - 0x76A32842;
89
b = ((b << 0x16) | (b >> 0x0a)) + c;
90
a = ((b & c) | (~b & d)) + LE_32((param+0x30)) + a + 0x6B901122;
91
a = ((a << 0x07) | (a >> 0x19)) + b;
92
d = ((a & b) | (~a & c)) + LE_32((param+0x34)) + d - 0x02678E6D;
93
d = ((d << 0x0c) | (d >> 0x14)) + a;
94
c = ((d & a) | (~d & b)) + LE_32((param+0x38)) + c - 0x5986BC72;
95
c = ((c << 0x11) | (c >> 0x0f)) + d;
96
b = ((c & d) | (~c & a)) + LE_32((param+0x3c)) + b + 0x49B40821;
97
b = ((b << 0x16) | (b >> 0x0a)) + c;
99
a = ((b & d) | (~d & c)) + LE_32((param+0x04)) + a - 0x09E1DA9E;
100
a = ((a << 0x05) | (a >> 0x1b)) + b;
101
d = ((a & c) | (~c & b)) + LE_32((param+0x18)) + d - 0x3FBF4CC0;
102
d = ((d << 0x09) | (d >> 0x17)) + a;
103
c = ((d & b) | (~b & a)) + LE_32((param+0x2c)) + c + 0x265E5A51;
104
c = ((c << 0x0e) | (c >> 0x12)) + d;
105
b = ((c & a) | (~a & d)) + LE_32((param+0x00)) + b - 0x16493856;
106
b = ((b << 0x14) | (b >> 0x0c)) + c;
107
a = ((b & d) | (~d & c)) + LE_32((param+0x14)) + a - 0x29D0EFA3;
108
a = ((a << 0x05) | (a >> 0x1b)) + b;
109
d = ((a & c) | (~c & b)) + LE_32((param+0x28)) + d + 0x02441453;
110
d = ((d << 0x09) | (d >> 0x17)) + a;
111
c = ((d & b) | (~b & a)) + LE_32((param+0x3c)) + c - 0x275E197F;
112
c = ((c << 0x0e) | (c >> 0x12)) + d;
113
b = ((c & a) | (~a & d)) + LE_32((param+0x10)) + b - 0x182C0438;
114
b = ((b << 0x14) | (b >> 0x0c)) + c;
115
a = ((b & d) | (~d & c)) + LE_32((param+0x24)) + a + 0x21E1CDE6;
116
a = ((a << 0x05) | (a >> 0x1b)) + b;
117
d = ((a & c) | (~c & b)) + LE_32((param+0x38)) + d - 0x3CC8F82A;
118
d = ((d << 0x09) | (d >> 0x17)) + a;
119
c = ((d & b) | (~b & a)) + LE_32((param+0x0c)) + c - 0x0B2AF279;
120
c = ((c << 0x0e) | (c >> 0x12)) + d;
121
b = ((c & a) | (~a & d)) + LE_32((param+0x20)) + b + 0x455A14ED;
122
b = ((b << 0x14) | (b >> 0x0c)) + c;
123
a = ((b & d) | (~d & c)) + LE_32((param+0x34)) + a - 0x561C16FB;
124
a = ((a << 0x05) | (a >> 0x1b)) + b;
125
d = ((a & c) | (~c & b)) + LE_32((param+0x08)) + d - 0x03105C08;
126
d = ((d << 0x09) | (d >> 0x17)) + a;
127
c = ((d & b) | (~b & a)) + LE_32((param+0x1c)) + c + 0x676F02D9;
128
c = ((c << 0x0e) | (c >> 0x12)) + d;
129
b = ((c & a) | (~a & d)) + LE_32((param+0x30)) + b - 0x72D5B376;
130
b = ((b << 0x14) | (b >> 0x0c)) + c;
132
a = (b ^ c ^ d) + LE_32((param+0x14)) + a - 0x0005C6BE;
133
a = ((a << 0x04) | (a >> 0x1c)) + b;
134
d = (a ^ b ^ c) + LE_32((param+0x20)) + d - 0x788E097F;
135
d = ((d << 0x0b) | (d >> 0x15)) + a;
136
c = (d ^ a ^ b) + LE_32((param+0x2c)) + c + 0x6D9D6122;
137
c = ((c << 0x10) | (c >> 0x10)) + d;
138
b = (c ^ d ^ a) + LE_32((param+0x38)) + b - 0x021AC7F4;
139
b = ((b << 0x17) | (b >> 0x09)) + c;
140
a = (b ^ c ^ d) + LE_32((param+0x04)) + a - 0x5B4115BC;
141
a = ((a << 0x04) | (a >> 0x1c)) + b;
142
d = (a ^ b ^ c) + LE_32((param+0x10)) + d + 0x4BDECFA9;
143
d = ((d << 0x0b) | (d >> 0x15)) + a;
144
c = (d ^ a ^ b) + LE_32((param+0x1c)) + c - 0x0944B4A0;
145
c = ((c << 0x10) | (c >> 0x10)) + d;
146
b = (c ^ d ^ a) + LE_32((param+0x28)) + b - 0x41404390;
147
b = ((b << 0x17) | (b >> 0x09)) + c;
148
a = (b ^ c ^ d) + LE_32((param+0x34)) + a + 0x289B7EC6;
149
a = ((a << 0x04) | (a >> 0x1c)) + b;
150
d = (a ^ b ^ c) + LE_32((param+0x00)) + d - 0x155ED806;
151
d = ((d << 0x0b) | (d >> 0x15)) + a;
152
c = (d ^ a ^ b) + LE_32((param+0x0c)) + c - 0x2B10CF7B;
153
c = ((c << 0x10) | (c >> 0x10)) + d;
154
b = (c ^ d ^ a) + LE_32((param+0x18)) + b + 0x04881D05;
155
b = ((b << 0x17) | (b >> 0x09)) + c;
156
a = (b ^ c ^ d) + LE_32((param+0x24)) + a - 0x262B2FC7;
157
a = ((a << 0x04) | (a >> 0x1c)) + b;
158
d = (a ^ b ^ c) + LE_32((param+0x30)) + d - 0x1924661B;
159
d = ((d << 0x0b) | (d >> 0x15)) + a;
160
c = (d ^ a ^ b) + LE_32((param+0x3c)) + c + 0x1fa27cf8;
161
c = ((c << 0x10) | (c >> 0x10)) + d;
162
b = (c ^ d ^ a) + LE_32((param+0x08)) + b - 0x3B53A99B;
163
b = ((b << 0x17) | (b >> 0x09)) + c;
165
a = ((~d | b) ^ c) + LE_32((param+0x00)) + a - 0x0BD6DDBC;
166
a = ((a << 0x06) | (a >> 0x1a)) + b;
167
d = ((~c | a) ^ b) + LE_32((param+0x1c)) + d + 0x432AFF97;
168
d = ((d << 0x0a) | (d >> 0x16)) + a;
169
c = ((~b | d) ^ a) + LE_32((param+0x38)) + c - 0x546BDC59;
170
c = ((c << 0x0f) | (c >> 0x11)) + d;
171
b = ((~a | c) ^ d) + LE_32((param+0x14)) + b - 0x036C5FC7;
172
b = ((b << 0x15) | (b >> 0x0b)) + c;
173
a = ((~d | b) ^ c) + LE_32((param+0x30)) + a + 0x655B59C3;
174
a = ((a << 0x06) | (a >> 0x1a)) + b;
175
d = ((~c | a) ^ b) + LE_32((param+0x0C)) + d - 0x70F3336E;
176
d = ((d << 0x0a) | (d >> 0x16)) + a;
177
c = ((~b | d) ^ a) + LE_32((param+0x28)) + c - 0x00100B83;
178
c = ((c << 0x0f) | (c >> 0x11)) + d;
179
b = ((~a | c) ^ d) + LE_32((param+0x04)) + b - 0x7A7BA22F;
180
b = ((b << 0x15) | (b >> 0x0b)) + c;
181
a = ((~d | b) ^ c) + LE_32((param+0x20)) + a + 0x6FA87E4F;
182
a = ((a << 0x06) | (a >> 0x1a)) + b;
183
d = ((~c | a) ^ b) + LE_32((param+0x3c)) + d - 0x01D31920;
184
d = ((d << 0x0a) | (d >> 0x16)) + a;
185
c = ((~b | d) ^ a) + LE_32((param+0x18)) + c - 0x5CFEBCEC;
186
c = ((c << 0x0f) | (c >> 0x11)) + d;
187
b = ((~a | c) ^ d) + LE_32((param+0x34)) + b + 0x4E0811A1;
188
b = ((b << 0x15) | (b >> 0x0b)) + c;
189
a = ((~d | b) ^ c) + LE_32((param+0x10)) + a - 0x08AC817E;
190
a = ((a << 0x06) | (a >> 0x1a)) + b;
191
d = ((~c | a) ^ b) + LE_32((param+0x2c)) + d - 0x42C50DCB;
192
d = ((d << 0x0a) | (d >> 0x16)) + a;
193
c = ((~b | d) ^ a) + LE_32((param+0x08)) + c + 0x2AD7D2BB;
194
c = ((c << 0x0f) | (c >> 0x11)) + d;
195
b = ((~a | c) ^ d) + LE_32((param+0x24)) + b - 0x14792C6F;
196
b = ((b << 0x15) | (b >> 0x0b)) + c;
198
lprintf("hash output: %x %x %x %x\n", a, b, c, d);
203
d += LE_32(field+12);
211
static void call_hash (char *key, char *challenge, unsigned int len) {
212
uint8_t *ptr1, *ptr2;
213
uint32_t a, b, c, d, tmp;
215
ptr1=(uint8_t*)(key+16);
216
ptr2=(uint8_t*)(key+20);
225
lprintf("not verified: (len << 3) > a true\n");
229
tmp = LE_32(ptr2) + (len >> 0x1d);
235
memcpy(key+b+24, challenge, a);
241
lprintf("not verified: while ( d < len )\n");
242
hash(key, challenge+d-0x3f);
249
memcpy(key+b+24, challenge+c, len-c);
252
static void calc_response (char *result, char *field) {
257
memset (buf1, 0, 64);
260
memcpy (buf2, field+16, 8);
261
i = ( LE_32((buf2)) >> 3 ) & 0x3f;
268
lprintf("not verified: ! (i < 56)\n");
272
call_hash (field, buf1, i);
273
call_hash (field, buf2, 8);
274
memcpy (result, field, 16);
277
static void calc_response_string (char *result, char *challenge) {
280
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
281
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
282
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
288
/* calculate response */
289
call_hash(field, challenge, 64);
290
calc_response(zres,field);
292
/* convert zres to ascii string */
293
for (i=0; i<16; i++ ) {
296
a = (zres[i] >> 4) & 15;
299
result[i*2] = ((a<10) ? (a+48) : (a+87)) & 255;
300
result[i*2+1] = ((b<10) ? (b+48) : (b+87)) & 255;
304
static void real_calc_response_and_checksum (char *response, char *chksum, char *challenge) {
306
int ch_len, resp_len;
311
/* initialize return values */
312
memset(response, 0, 64);
313
memset(chksum, 0, 34);
315
/* initialize buffer */
318
BE_32C(ptr, 0xa1e9149d);
320
BE_32C(ptr, 0x0e6b3b59);
323
/* some (length) checks */
324
if (challenge != NULL)
326
ch_len = strlen (challenge);
328
if (ch_len == 40) /* what a hack... */
333
if ( ch_len > 56 ) ch_len=56;
335
/* copy challenge to buf */
336
memcpy(ptr, challenge, ch_len);
339
/* xor challenge bytewise with xor_table */
340
for (i=0; i<XOR_TABLE_LEN; i++)
341
ptr[i] = ptr[i] ^ xor_table[i];
343
calc_response_string (response, buf);
346
resp_len = strlen (response);
347
strcpy (&response[resp_len], "01d0a8e3");
349
/* calculate checksum */
350
for (i=0; i<resp_len/4; i++)
351
chksum[i] = response[i*4];
354
#define MLTI_BUF_MAX_SIZE 2048
357
* takes a MLTI-Chunk and a rule number got from match_asm_rule,
358
* returns a pointer to selected data and number of bytes in that.
360
static int select_mlti_data(const char *mlti_chunk, int mlti_size, int selection, char **out) {
362
int numrules, codec, size;
365
/* MLTI chunk should begin with MLTI */
366
if ((mlti_chunk[0] != 'M')
367
||(mlti_chunk[1] != 'L')
368
||(mlti_chunk[2] != 'T')
369
||(mlti_chunk[3] != 'I'))
371
lprintf("MLTI tag not detected, copying data\n");
372
memcpy(*out, mlti_chunk, __MIN(mlti_size,MLTI_BUF_MAX_SIZE));
378
/* next 16 bits are the number of rules */
379
numrules=BE_16(mlti_chunk);
380
if (selection >= numrules) return 0;
382
/* now <numrules> indices of codecs follows */
383
/* we skip to selection */
384
mlti_chunk+=(selection+1)*2;
387
codec=BE_16(mlti_chunk);
389
/* skip to number of codecs */
390
mlti_chunk+=(numrules-selection)*2;
392
/* get number of codecs */
393
numrules=BE_16(mlti_chunk);
395
if (codec >= numrules) {
396
lprintf("codec index >= number of codecs. %i %i\n", codec, numrules);
402
/* now seek to selected codec */
403
for (i=0; i<codec; i++) {
404
size=BE_32(mlti_chunk);
407
size=BE_32(mlti_chunk);
409
memcpy(*out, mlti_chunk+4, __MIN(size,MLTI_BUF_MAX_SIZE));
414
* looking at stream description.
417
static rmff_header_t *real_parse_sdp(char *data, char **stream_rules, uint32_t bandwidth) {
419
sdpplin_t *desc = NULL;
420
rmff_header_t *header = NULL;
425
int max_packet_size=0;
426
int avg_packet_size=0;
429
if( !data ) return NULL;
431
desc=sdpplin_parse(data);
432
if( !desc ) return NULL;
434
buf= (char *)malloc(MLTI_BUF_MAX_SIZE);
435
if( !buf ) goto error;
437
header = calloc( 1, sizeof(rmff_header_t) );
438
if( !header ) goto error;
440
header->fileheader=rmff_new_fileheader(4+desc->stream_count);
441
header->cont=rmff_new_cont(
447
header->data=rmff_new_dataheader(0,0);
448
if( !header->data ) goto error;
450
header->streams = calloc( desc->stream_count+1, sizeof(rmff_mdpr_t*) );
451
if( !header->streams ) goto error;
453
lprintf("number of streams: %u\n", desc->stream_count);
455
for (i=0; i<desc->stream_count; i++) {
462
lprintf("calling asmrp_match with:\n%s\n%u\n", desc->stream[i]->asm_rule_book, bandwidth);
464
n=asmrp_match(desc->stream[i]->asm_rule_book, bandwidth, rulematches, sizeof(rulematches)/sizeof(rulematches[0]));
465
for (j=0; j<n; j++) {
466
lprintf("asmrp rule match: %u for stream %u\n", rulematches[j], desc->stream[i]->stream_id);
467
sprintf(b,"stream=%u;rule=%u,", desc->stream[i]->stream_id, rulematches[j]);
468
strcat(*stream_rules, b);
471
if (!desc->stream[i]->mlti_data) {
476
len=select_mlti_data(desc->stream[i]->mlti_data,
477
desc->stream[i]->mlti_data_size, rulematches[0], &buf);
479
header->streams[i]=rmff_new_mdpr(
480
desc->stream[i]->stream_id,
481
desc->stream[i]->max_bit_rate,
482
desc->stream[i]->avg_bit_rate,
483
desc->stream[i]->max_packet_size,
484
desc->stream[i]->avg_packet_size,
485
desc->stream[i]->start_time,
486
desc->stream[i]->preroll,
487
desc->stream[i]->duration,
488
desc->stream[i]->stream_name,
489
desc->stream[i]->mime_type,
492
if( !header->streams[i] ) goto error;
494
duration=MAX(duration,desc->stream[i]->duration);
495
max_bit_rate+=desc->stream[i]->max_bit_rate;
496
avg_bit_rate+=desc->stream[i]->avg_bit_rate;
497
max_packet_size=MAX(max_packet_size, desc->stream[i]->max_packet_size);
499
avg_packet_size=(avg_packet_size + desc->stream[i]->avg_packet_size) / 2;
501
avg_packet_size=desc->stream[i]->avg_packet_size;
504
if (*stream_rules && strlen(*stream_rules) && (*stream_rules)[strlen(*stream_rules)-1] == ',')
505
(*stream_rules)[strlen(*stream_rules)-1]=0; /* delete last ',' in stream_rules */
507
header->prop=rmff_new_prop(
519
if( !header->prop ) goto error;
521
rmff_fix_header(header);
523
sdpplin_free( desc );
528
sdpplin_free( desc );
529
rmff_free_header( header );
534
int real_get_rdt_chunk_header(rtsp_client_t *rtsp_session, rmff_pheader_t *ph) {
543
n=rtsp_read_data(rtsp_session, header, 8);
545
if (header[0] != 0x24)
547
lprintf("rdt chunk not recognized: got 0x%02x\n", header[0]);
550
size=(header[1]<<16)+(header[2]<<8)+(header[3]);
552
if ((flags1!=0x40)&&(flags1!=0x42))
554
lprintf("got flags1: 0x%02x\n",flags1);
557
lprintf("got end of stream packet\n");
563
n=rtsp_read_data(rtsp_session, header+3, 5);
565
lprintf("ignoring bytes:\n");
566
n=rtsp_read_data(rtsp_session, header+4, 4);
571
unknown1=(header[5]<<16)+(header[6]<<8)+(header[7]);
572
n=rtsp_read_data(rtsp_session, header, 6);
577
lprintf("ts: %u size: %u, flags: 0x%02x, unknown values: %u 0x%02x 0x%02x\n",
578
ts, size, flags1, unknown1, header[4], header[5]);
582
ph->object_version=0;
584
ph->stream_number=(flags1>>1)&1;
587
ph->flags=0; /* TODO: determine keyframe flag and insert here? */
591
int real_get_rdt_chunk(rtsp_client_t *rtsp_session, rmff_pheader_t *ph,
592
unsigned char **buffer) {
595
rmff_dump_pheader(ph, (char*)*buffer);
596
if (ph->length<12) return 0;
597
n=rtsp_read_data(rtsp_session, (uint8_t*)(*buffer + 12), ph->length - 12);
598
return (n <= 0) ? 0 : n+12;
601
//! maximum size of the rtsp description, must be < INT_MAX
602
#define MAX_DESC_BUF (20 * 1024 * 1024)
603
rmff_header_t *real_setup_and_get_header(rtsp_client_t *rtsp_session, int bandwidth) {
605
char *description=NULL;
606
char *session_id=NULL;
607
rmff_header_t *h=NULL;
608
char *challenge1 = NULL;
611
char *subscribe=NULL;
612
char *buf = malloc(256);
615
char *mrl=rtsp_get_mrl(rtsp_session);
620
challenge1=strdup(rtsp_search_answers(rtsp_session,"RealChallenge1"));
621
lprintf("Challenge1: %s\n", challenge1);
623
/* request stream description */
624
rtsp_schedule_field(rtsp_session, "Accept: application/sdp");
625
sprintf(buf, "Bandwidth: %u", bandwidth);
626
rtsp_schedule_field(rtsp_session, buf);
627
rtsp_schedule_field(rtsp_session, "GUID: 00000000-0000-0000-0000-000000000000");
628
rtsp_schedule_field(rtsp_session, "RegionData: 0");
629
rtsp_schedule_field(rtsp_session, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586");
630
rtsp_schedule_field(rtsp_session, "SupportsMaximumASMBandwidth: 1");
631
rtsp_schedule_field(rtsp_session, "Language: en-US");
632
rtsp_schedule_field(rtsp_session, "Require: com.real.retain-entity-for-setup");
634
status=rtsp_request_describe(rtsp_session,NULL);
635
if ( status<200 || status>299 ) {
636
char *alert=rtsp_search_answers(rtsp_session,"Alert");
638
lprintf("real: got message from server:\n%s\n", alert);
640
rtsp_send_ok( rtsp_session );
647
/* receive description */
649
if (!rtsp_search_answers(rtsp_session,"Content-length"))
650
lprintf("real: got no Content-length!\n");
652
size=atoi(rtsp_search_answers(rtsp_session,"Content-length"));
654
if (size > MAX_DESC_BUF) {
655
printf("real: Content-length for description too big (> %uMB)!\n",
656
MAX_DESC_BUF/(1024*1024) );
660
if (!rtsp_search_answers(rtsp_session,"ETag"))
661
lprintf("real: got no ETag!\n");
663
session_id=strdup(rtsp_search_answers(rtsp_session,"ETag"));
665
lprintf("Stream description size: %i\n", size);
667
description = malloc(size+1);
670
if( rtsp_read_data(rtsp_session, (uint8_t*)description, size) <= 0)
673
//fprintf(stderr, "%s", description);
675
/* parse sdp (sdpplin) and create a header and a subscribe string */
676
subscribe = malloc(256);
680
strcpy(subscribe, "Subscribe: ");
681
h=real_parse_sdp(description, &subscribe, bandwidth);
688
fprintf("Title: %s\nCopyright: %s\nAuthor: %s\nStreams: %i\n",
689
h->cont->title, h->cont->copyright, h->cont->author, h->prop->num_streams);
692
/* setup our streams */
693
real_calc_response_and_checksum (challenge2, checksum, challenge1);
694
buf = realloc_or_free(buf, strlen(challenge2) + strlen(checksum) + 32);
695
if( !buf ) goto error;
696
sprintf(buf, "RealChallenge2: %s, sd=%s", challenge2, checksum);
697
rtsp_schedule_field(rtsp_session, buf);
698
buf = realloc_or_free(buf, strlen(session_id) + 32);
699
if( !buf ) goto error;
700
sprintf(buf, "If-Match: %s", session_id);
701
rtsp_schedule_field(rtsp_session, buf);
702
rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
703
buf = realloc_or_free(buf, strlen(mrl) + 32);
704
if( !buf ) goto error;
705
sprintf(buf, "%s/streamid=0", mrl);
706
rtsp_request_setup(rtsp_session,buf);
708
if (h->prop->num_streams > 1) {
709
rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
710
buf = realloc_or_free(buf, strlen(session_id) + 32);
711
if( !buf ) goto error;
712
sprintf(buf, "If-Match: %s", session_id);
713
rtsp_schedule_field(rtsp_session, buf);
714
buf = realloc_or_free(buf, strlen(mrl) + 32);
715
if( !buf ) goto error;
716
sprintf(buf, "%s/streamid=1", mrl);
717
rtsp_request_setup(rtsp_session,buf);
719
/* set stream parameter (bandwidth) with our subscribe string */
720
rtsp_schedule_field(rtsp_session, subscribe);
721
rtsp_request_setparameter(rtsp_session,NULL);
723
/* and finally send a play request */
724
rtsp_schedule_field(rtsp_session, "Range: npt=0-");
725
rtsp_request_play(rtsp_session,NULL);
735
rmff_free_header( h );