1 /*****************************************************************************
2 * real.c: real rtsp input
3 *****************************************************************************
4 * Copyright (C) 2002-2004 the xine project
5 * Copyright (C) 2005 VideoLAN
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 );