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];
356 * takes a MLTI-Chunk and a rule number got from match_asm_rule,
357 * returns a pointer to selected data and number of bytes in that.
359 static int select_mlti_data(const char *mlti_chunk, int mlti_size, int selection, char **out) {
361 int numrules, codec, size;
364 /* MLTI chunk should begin with MLTI */
365 if ((mlti_chunk[0] != 'M')
366 ||(mlti_chunk[1] != 'L')
367 ||(mlti_chunk[2] != 'T')
368 ||(mlti_chunk[3] != 'I'))
370 lprintf("MLTI tag not detected, copying data\n");
371 memcpy(*out, mlti_chunk, mlti_size);
377 /* next 16 bits are the number of rules */
378 numrules=BE_16(mlti_chunk);
379 if (selection >= numrules) return 0;
381 /* now <numrules> indices of codecs follows */
382 /* we skip to selection */
383 mlti_chunk+=(selection+1)*2;
386 codec=BE_16(mlti_chunk);
388 /* skip to number of codecs */
389 mlti_chunk+=(numrules-selection)*2;
391 /* get number of codecs */
392 numrules=BE_16(mlti_chunk);
394 if (codec >= numrules) {
395 lprintf("codec index >= number of codecs. %i %i\n", codec, numrules);
401 /* now seek to selected codec */
402 for (i=0; i<codec; i++) {
403 size=BE_32(mlti_chunk);
406 size=BE_32(mlti_chunk);
408 memcpy(*out, mlti_chunk+4, size);
413 * looking at stream description.
416 static rmff_header_t *real_parse_sdp(char *data, char **stream_rules, uint32_t bandwidth) {
418 sdpplin_t *desc = NULL;
419 rmff_header_t *header = NULL;
424 int max_packet_size=0;
425 int avg_packet_size=0;
428 if( !data ) return NULL;
430 desc=sdpplin_parse(data);
431 if( !desc ) return NULL;
433 buf= (char *)malloc(2048);
434 if( !buf ) goto error;
436 header = calloc( 1, sizeof(rmff_header_t) );
437 if( !header ) goto error;
439 header->fileheader=rmff_new_fileheader(4+desc->stream_count);
440 header->cont=rmff_new_cont(
446 header->data=rmff_new_dataheader(0,0);
447 if( !header->data ) goto error;
449 header->streams = calloc( desc->stream_count+1, sizeof(rmff_mdpr_t*) );
450 if( !header->streams ) goto error;
452 lprintf("number of streams: %u\n", desc->stream_count);
454 for (i=0; i<desc->stream_count; i++) {
461 lprintf("calling asmrp_match with:\n%s\n%u\n", desc->stream[i]->asm_rule_book, bandwidth);
463 n=asmrp_match(desc->stream[i]->asm_rule_book, bandwidth, rulematches, sizeof(rulematches)/sizeof(rulematches[0]));
464 for (j=0; j<n; j++) {
465 lprintf("asmrp rule match: %u for stream %u\n", rulematches[j], desc->stream[i]->stream_id);
466 sprintf(b,"stream=%u;rule=%u,", desc->stream[i]->stream_id, rulematches[j]);
467 strcat(*stream_rules, b);
470 if (!desc->stream[i]->mlti_data) {
475 len=select_mlti_data(desc->stream[i]->mlti_data,
476 desc->stream[i]->mlti_data_size, rulematches[0], &buf);
478 header->streams[i]=rmff_new_mdpr(
479 desc->stream[i]->stream_id,
480 desc->stream[i]->max_bit_rate,
481 desc->stream[i]->avg_bit_rate,
482 desc->stream[i]->max_packet_size,
483 desc->stream[i]->avg_packet_size,
484 desc->stream[i]->start_time,
485 desc->stream[i]->preroll,
486 desc->stream[i]->duration,
487 desc->stream[i]->stream_name,
488 desc->stream[i]->mime_type,
491 if( !header->streams[i] ) goto error;
493 duration=MAX(duration,desc->stream[i]->duration);
494 max_bit_rate+=desc->stream[i]->max_bit_rate;
495 avg_bit_rate+=desc->stream[i]->avg_bit_rate;
496 max_packet_size=MAX(max_packet_size, desc->stream[i]->max_packet_size);
498 avg_packet_size=(avg_packet_size + desc->stream[i]->avg_packet_size) / 2;
500 avg_packet_size=desc->stream[i]->avg_packet_size;
503 if (*stream_rules && strlen(*stream_rules) && (*stream_rules)[strlen(*stream_rules)-1] == ',')
504 (*stream_rules)[strlen(*stream_rules)-1]=0; /* delete last ',' in stream_rules */
506 header->prop=rmff_new_prop(
518 if( !header->prop ) goto error;
520 rmff_fix_header(header);
522 sdpplin_free( desc );
527 sdpplin_free( desc );
528 rmff_free_header( header );
533 int real_get_rdt_chunk_header(rtsp_client_t *rtsp_session, rmff_pheader_t *ph) {
542 n=rtsp_read_data(rtsp_session, header, 8);
544 if (header[0] != 0x24)
546 lprintf("rdt chunk not recognized: got 0x%02x\n", header[0]);
549 size=(header[1]<<16)+(header[2]<<8)+(header[3]);
551 if ((flags1!=0x40)&&(flags1!=0x42))
553 lprintf("got flags1: 0x%02x\n",flags1);
556 lprintf("got end of stream packet\n");
562 n=rtsp_read_data(rtsp_session, header+3, 5);
564 lprintf("ignoring bytes:\n");
565 n=rtsp_read_data(rtsp_session, header+4, 4);
570 unknown1=(header[5]<<16)+(header[6]<<8)+(header[7]);
571 n=rtsp_read_data(rtsp_session, header, 6);
576 lprintf("ts: %u size: %u, flags: 0x%02x, unknown values: %u 0x%02x 0x%02x\n",
577 ts, size, flags1, unknown1, header[4], header[5]);
581 ph->object_version=0;
583 ph->stream_number=(flags1>>1)&1;
586 ph->flags=0; /* TODO: determine keyframe flag and insert here? */
590 int real_get_rdt_chunk(rtsp_client_t *rtsp_session, rmff_pheader_t *ph,
591 unsigned char **buffer) {
594 rmff_dump_pheader(ph, (char*)*buffer);
595 if (ph->length<12) return 0;
596 n=rtsp_read_data(rtsp_session, (uint8_t*)(*buffer + 12), ph->length - 12);
597 return (n <= 0) ? 0 : n+12;
600 //! maximum size of the rtsp description, must be < INT_MAX
601 #define MAX_DESC_BUF (20 * 1024 * 1024)
602 rmff_header_t *real_setup_and_get_header(rtsp_client_t *rtsp_session, int bandwidth) {
604 char *description=NULL;
605 char *session_id=NULL;
606 rmff_header_t *h=NULL;
607 char *challenge1 = NULL;
610 char *subscribe=NULL;
611 char *buf = malloc(256);
614 char *mrl=rtsp_get_mrl(rtsp_session);
619 challenge1=strdup(rtsp_search_answers(rtsp_session,"RealChallenge1"));
620 lprintf("Challenge1: %s\n", challenge1);
622 /* request stream description */
623 rtsp_schedule_field(rtsp_session, "Accept: application/sdp");
624 sprintf(buf, "Bandwidth: %u", bandwidth);
625 rtsp_schedule_field(rtsp_session, buf);
626 rtsp_schedule_field(rtsp_session, "GUID: 00000000-0000-0000-0000-000000000000");
627 rtsp_schedule_field(rtsp_session, "RegionData: 0");
628 rtsp_schedule_field(rtsp_session, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586");
629 rtsp_schedule_field(rtsp_session, "SupportsMaximumASMBandwidth: 1");
630 rtsp_schedule_field(rtsp_session, "Language: en-US");
631 rtsp_schedule_field(rtsp_session, "Require: com.real.retain-entity-for-setup");
633 status=rtsp_request_describe(rtsp_session,NULL);
634 if ( status<200 || status>299 ) {
635 char *alert=rtsp_search_answers(rtsp_session,"Alert");
637 lprintf("real: got message from server:\n%s\n", alert);
639 rtsp_send_ok( rtsp_session );
646 /* receive description */
648 if (!rtsp_search_answers(rtsp_session,"Content-length"))
649 lprintf("real: got no Content-length!\n");
651 size=atoi(rtsp_search_answers(rtsp_session,"Content-length"));
653 if (size > MAX_DESC_BUF) {
654 printf("real: Content-length for description too big (> %uMB)!\n",
655 MAX_DESC_BUF/(1024*1024) );
659 if (!rtsp_search_answers(rtsp_session,"ETag"))
660 lprintf("real: got no ETag!\n");
662 session_id=strdup(rtsp_search_answers(rtsp_session,"ETag"));
664 lprintf("Stream description size: %i\n", size);
666 description = malloc(size+1);
669 if( rtsp_read_data(rtsp_session, (uint8_t*)description, size) <= 0)
672 //fprintf(stderr, "%s", description);
674 /* parse sdp (sdpplin) and create a header and a subscribe string */
675 subscribe = malloc(256);
679 strcpy(subscribe, "Subscribe: ");
680 h=real_parse_sdp(description, &subscribe, bandwidth);
687 fprintf("Title: %s\nCopyright: %s\nAuthor: %s\nStreams: %i\n",
688 h->cont->title, h->cont->copyright, h->cont->author, h->prop->num_streams);
691 /* setup our streams */
692 real_calc_response_and_checksum (challenge2, checksum, challenge1);
693 buf = realloc_or_free(buf, strlen(challenge2) + strlen(checksum) + 32);
694 if( !buf ) goto error;
695 sprintf(buf, "RealChallenge2: %s, sd=%s", challenge2, checksum);
696 rtsp_schedule_field(rtsp_session, buf);
697 buf = realloc_or_free(buf, strlen(session_id) + 32);
698 if( !buf ) goto error;
699 sprintf(buf, "If-Match: %s", session_id);
700 rtsp_schedule_field(rtsp_session, buf);
701 rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
702 buf = realloc_or_free(buf, strlen(mrl) + 32);
703 if( !buf ) goto error;
704 sprintf(buf, "%s/streamid=0", mrl);
705 rtsp_request_setup(rtsp_session,buf);
707 if (h->prop->num_streams > 1) {
708 rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
709 buf = realloc_or_free(buf, strlen(session_id) + 32);
710 if( !buf ) goto error;
711 sprintf(buf, "If-Match: %s", session_id);
712 rtsp_schedule_field(rtsp_session, buf);
713 buf = realloc_or_free(buf, strlen(mrl) + 32);
714 if( !buf ) goto error;
715 sprintf(buf, "%s/streamid=1", mrl);
716 rtsp_request_setup(rtsp_session,buf);
718 /* set stream parameter (bandwidth) with our subscribe string */
719 rtsp_schedule_field(rtsp_session, subscribe);
720 rtsp_request_setparameter(rtsp_session,NULL);
722 /* and finally send a play request */
723 rtsp_schedule_field(rtsp_session, "Range: npt=0-");
724 rtsp_request_play(rtsp_session,NULL);
734 rmff_free_header( h );