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>
34 #include "real_sdpplin.h"
36 #define XOR_TABLE_LEN 37
37 static const unsigned char xor_table[] = {
38 0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
39 0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
40 0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
41 0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
42 0x10, 0x57, 0x05, 0x18, 0x54, 0x00, 0x00, 0x00 };
44 #define BE_32(x) GetDWBE(x)
45 #define LE_32(x) GetDWLE(x)
46 #define BE_16(x) GetWBE(x)
47 #define LE_16(x) GetWLE(x)
48 #define BE_32C(x,y) do {uint32_t in=y; *(uint32_t *)(x)=GetDWBE(&in);} while(0)
49 #define LE_32C(x,y) do {uint32_t in=y; *(uint32_t *)(x)=GetDWLE(&in);} while(0)
50 #define MAX(x,y) ((x>y) ? x : y)
52 /* XXX find a better place for this */
53 static inline void *realloc_(void *p, size_t sz)
55 void *n = realloc(p, sz);
61 static void hash(char *field, char *param)
71 lprintf("hash input: %x %x %x %x\n", a, b, c, d);
72 lprintf("hash parameter:\n");
74 a = ((b & c) | (~b & d)) + LE_32((param+0x00)) + a - 0x28955B88;
75 a = ((a << 0x07) | (a >> 0x19)) + b;
76 d = ((a & b) | (~a & c)) + LE_32((param+0x04)) + d - 0x173848AA;
77 d = ((d << 0x0c) | (d >> 0x14)) + a;
78 c = ((d & a) | (~d & b)) + LE_32((param+0x08)) + c + 0x242070DB;
79 c = ((c << 0x11) | (c >> 0x0f)) + d;
80 b = ((c & d) | (~c & a)) + LE_32((param+0x0c)) + b - 0x3E423112;
81 b = ((b << 0x16) | (b >> 0x0a)) + c;
82 a = ((b & c) | (~b & d)) + LE_32((param+0x10)) + a - 0x0A83F051;
83 a = ((a << 0x07) | (a >> 0x19)) + b;
84 d = ((a & b) | (~a & c)) + LE_32((param+0x14)) + d + 0x4787C62A;
85 d = ((d << 0x0c) | (d >> 0x14)) + a;
86 c = ((d & a) | (~d & b)) + LE_32((param+0x18)) + c - 0x57CFB9ED;
87 c = ((c << 0x11) | (c >> 0x0f)) + d;
88 b = ((c & d) | (~c & a)) + LE_32((param+0x1c)) + b - 0x02B96AFF;
89 b = ((b << 0x16) | (b >> 0x0a)) + c;
90 a = ((b & c) | (~b & d)) + LE_32((param+0x20)) + a + 0x698098D8;
91 a = ((a << 0x07) | (a >> 0x19)) + b;
92 d = ((a & b) | (~a & c)) + LE_32((param+0x24)) + d - 0x74BB0851;
93 d = ((d << 0x0c) | (d >> 0x14)) + a;
94 c = ((d & a) | (~d & b)) + LE_32((param+0x28)) + c - 0x0000A44F;
95 c = ((c << 0x11) | (c >> 0x0f)) + d;
96 b = ((c & d) | (~c & a)) + LE_32((param+0x2C)) + b - 0x76A32842;
97 b = ((b << 0x16) | (b >> 0x0a)) + c;
98 a = ((b & c) | (~b & d)) + LE_32((param+0x30)) + a + 0x6B901122;
99 a = ((a << 0x07) | (a >> 0x19)) + b;
100 d = ((a & b) | (~a & c)) + LE_32((param+0x34)) + d - 0x02678E6D;
101 d = ((d << 0x0c) | (d >> 0x14)) + a;
102 c = ((d & a) | (~d & b)) + LE_32((param+0x38)) + c - 0x5986BC72;
103 c = ((c << 0x11) | (c >> 0x0f)) + d;
104 b = ((c & d) | (~c & a)) + LE_32((param+0x3c)) + b + 0x49B40821;
105 b = ((b << 0x16) | (b >> 0x0a)) + c;
107 a = ((b & d) | (~d & c)) + LE_32((param+0x04)) + a - 0x09E1DA9E;
108 a = ((a << 0x05) | (a >> 0x1b)) + b;
109 d = ((a & c) | (~c & b)) + LE_32((param+0x18)) + d - 0x3FBF4CC0;
110 d = ((d << 0x09) | (d >> 0x17)) + a;
111 c = ((d & b) | (~b & a)) + LE_32((param+0x2c)) + c + 0x265E5A51;
112 c = ((c << 0x0e) | (c >> 0x12)) + d;
113 b = ((c & a) | (~a & d)) + LE_32((param+0x00)) + b - 0x16493856;
114 b = ((b << 0x14) | (b >> 0x0c)) + c;
115 a = ((b & d) | (~d & c)) + LE_32((param+0x14)) + a - 0x29D0EFA3;
116 a = ((a << 0x05) | (a >> 0x1b)) + b;
117 d = ((a & c) | (~c & b)) + LE_32((param+0x28)) + d + 0x02441453;
118 d = ((d << 0x09) | (d >> 0x17)) + a;
119 c = ((d & b) | (~b & a)) + LE_32((param+0x3c)) + c - 0x275E197F;
120 c = ((c << 0x0e) | (c >> 0x12)) + d;
121 b = ((c & a) | (~a & d)) + LE_32((param+0x10)) + b - 0x182C0438;
122 b = ((b << 0x14) | (b >> 0x0c)) + c;
123 a = ((b & d) | (~d & c)) + LE_32((param+0x24)) + a + 0x21E1CDE6;
124 a = ((a << 0x05) | (a >> 0x1b)) + b;
125 d = ((a & c) | (~c & b)) + LE_32((param+0x38)) + d - 0x3CC8F82A;
126 d = ((d << 0x09) | (d >> 0x17)) + a;
127 c = ((d & b) | (~b & a)) + LE_32((param+0x0c)) + c - 0x0B2AF279;
128 c = ((c << 0x0e) | (c >> 0x12)) + d;
129 b = ((c & a) | (~a & d)) + LE_32((param+0x20)) + b + 0x455A14ED;
130 b = ((b << 0x14) | (b >> 0x0c)) + c;
131 a = ((b & d) | (~d & c)) + LE_32((param+0x34)) + a - 0x561C16FB;
132 a = ((a << 0x05) | (a >> 0x1b)) + b;
133 d = ((a & c) | (~c & b)) + LE_32((param+0x08)) + d - 0x03105C08;
134 d = ((d << 0x09) | (d >> 0x17)) + a;
135 c = ((d & b) | (~b & a)) + LE_32((param+0x1c)) + c + 0x676F02D9;
136 c = ((c << 0x0e) | (c >> 0x12)) + d;
137 b = ((c & a) | (~a & d)) + LE_32((param+0x30)) + b - 0x72D5B376;
138 b = ((b << 0x14) | (b >> 0x0c)) + c;
140 a = (b ^ c ^ d) + LE_32((param+0x14)) + a - 0x0005C6BE;
141 a = ((a << 0x04) | (a >> 0x1c)) + b;
142 d = (a ^ b ^ c) + LE_32((param+0x20)) + d - 0x788E097F;
143 d = ((d << 0x0b) | (d >> 0x15)) + a;
144 c = (d ^ a ^ b) + LE_32((param+0x2c)) + c + 0x6D9D6122;
145 c = ((c << 0x10) | (c >> 0x10)) + d;
146 b = (c ^ d ^ a) + LE_32((param+0x38)) + b - 0x021AC7F4;
147 b = ((b << 0x17) | (b >> 0x09)) + c;
148 a = (b ^ c ^ d) + LE_32((param+0x04)) + a - 0x5B4115BC;
149 a = ((a << 0x04) | (a >> 0x1c)) + b;
150 d = (a ^ b ^ c) + LE_32((param+0x10)) + d + 0x4BDECFA9;
151 d = ((d << 0x0b) | (d >> 0x15)) + a;
152 c = (d ^ a ^ b) + LE_32((param+0x1c)) + c - 0x0944B4A0;
153 c = ((c << 0x10) | (c >> 0x10)) + d;
154 b = (c ^ d ^ a) + LE_32((param+0x28)) + b - 0x41404390;
155 b = ((b << 0x17) | (b >> 0x09)) + c;
156 a = (b ^ c ^ d) + LE_32((param+0x34)) + a + 0x289B7EC6;
157 a = ((a << 0x04) | (a >> 0x1c)) + b;
158 d = (a ^ b ^ c) + LE_32((param+0x00)) + d - 0x155ED806;
159 d = ((d << 0x0b) | (d >> 0x15)) + a;
160 c = (d ^ a ^ b) + LE_32((param+0x0c)) + c - 0x2B10CF7B;
161 c = ((c << 0x10) | (c >> 0x10)) + d;
162 b = (c ^ d ^ a) + LE_32((param+0x18)) + b + 0x04881D05;
163 b = ((b << 0x17) | (b >> 0x09)) + c;
164 a = (b ^ c ^ d) + LE_32((param+0x24)) + a - 0x262B2FC7;
165 a = ((a << 0x04) | (a >> 0x1c)) + b;
166 d = (a ^ b ^ c) + LE_32((param+0x30)) + d - 0x1924661B;
167 d = ((d << 0x0b) | (d >> 0x15)) + a;
168 c = (d ^ a ^ b) + LE_32((param+0x3c)) + c + 0x1fa27cf8;
169 c = ((c << 0x10) | (c >> 0x10)) + d;
170 b = (c ^ d ^ a) + LE_32((param+0x08)) + b - 0x3B53A99B;
171 b = ((b << 0x17) | (b >> 0x09)) + c;
173 a = ((~d | b) ^ c) + LE_32((param+0x00)) + a - 0x0BD6DDBC;
174 a = ((a << 0x06) | (a >> 0x1a)) + b;
175 d = ((~c | a) ^ b) + LE_32((param+0x1c)) + d + 0x432AFF97;
176 d = ((d << 0x0a) | (d >> 0x16)) + a;
177 c = ((~b | d) ^ a) + LE_32((param+0x38)) + c - 0x546BDC59;
178 c = ((c << 0x0f) | (c >> 0x11)) + d;
179 b = ((~a | c) ^ d) + LE_32((param+0x14)) + b - 0x036C5FC7;
180 b = ((b << 0x15) | (b >> 0x0b)) + c;
181 a = ((~d | b) ^ c) + LE_32((param+0x30)) + a + 0x655B59C3;
182 a = ((a << 0x06) | (a >> 0x1a)) + b;
183 d = ((~c | a) ^ b) + LE_32((param+0x0C)) + d - 0x70F3336E;
184 d = ((d << 0x0a) | (d >> 0x16)) + a;
185 c = ((~b | d) ^ a) + LE_32((param+0x28)) + c - 0x00100B83;
186 c = ((c << 0x0f) | (c >> 0x11)) + d;
187 b = ((~a | c) ^ d) + LE_32((param+0x04)) + b - 0x7A7BA22F;
188 b = ((b << 0x15) | (b >> 0x0b)) + c;
189 a = ((~d | b) ^ c) + LE_32((param+0x20)) + a + 0x6FA87E4F;
190 a = ((a << 0x06) | (a >> 0x1a)) + b;
191 d = ((~c | a) ^ b) + LE_32((param+0x3c)) + d - 0x01D31920;
192 d = ((d << 0x0a) | (d >> 0x16)) + a;
193 c = ((~b | d) ^ a) + LE_32((param+0x18)) + c - 0x5CFEBCEC;
194 c = ((c << 0x0f) | (c >> 0x11)) + d;
195 b = ((~a | c) ^ d) + LE_32((param+0x34)) + b + 0x4E0811A1;
196 b = ((b << 0x15) | (b >> 0x0b)) + c;
197 a = ((~d | b) ^ c) + LE_32((param+0x10)) + a - 0x08AC817E;
198 a = ((a << 0x06) | (a >> 0x1a)) + b;
199 d = ((~c | a) ^ b) + LE_32((param+0x2c)) + d - 0x42C50DCB;
200 d = ((d << 0x0a) | (d >> 0x16)) + a;
201 c = ((~b | d) ^ a) + LE_32((param+0x08)) + c + 0x2AD7D2BB;
202 c = ((c << 0x0f) | (c >> 0x11)) + d;
203 b = ((~a | c) ^ d) + LE_32((param+0x24)) + b - 0x14792C6F;
204 b = ((b << 0x15) | (b >> 0x0b)) + c;
206 lprintf("hash output: %x %x %x %x\n", a, b, c, d);
211 d += LE_32(field+12);
219 static void call_hash (char *key, char *challenge, unsigned int len) {
220 uint8_t *ptr1, *ptr2;
221 uint32_t a, b, c, d, tmp;
223 ptr1=(uint8_t*)(key+16);
224 ptr2=(uint8_t*)(key+20);
233 lprintf("not verified: (len << 3) > a true\n");
237 tmp = LE_32(ptr2) + (len >> 0x1d);
243 memcpy(key+b+24, challenge, a);
249 lprintf("not verified: while ( d < len )\n");
250 hash(key, challenge+d-0x3f);
257 memcpy(key+b+24, challenge+c, len-c);
260 static void calc_response (char *result, char *field) {
265 memset (buf1, 0, 64);
268 memcpy (buf2, field+16, 8);
269 i = ( LE_32((buf2)) >> 3 ) & 0x3f;
276 lprintf("not verified: ! (i < 56)\n");
280 call_hash (field, buf1, i);
281 call_hash (field, buf2, 8);
282 memcpy (result, field, 16);
285 static void calc_response_string (char *result, char *challenge) {
288 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
289 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
296 /* calculate response */
297 call_hash(field, challenge, 64);
298 calc_response(zres,field);
300 /* convert zres to ascii string */
301 for (i=0; i<16; i++ ) {
304 a = (zres[i] >> 4) & 15;
307 result[i*2] = ((a<10) ? (a+48) : (a+87)) & 255;
308 result[i*2+1] = ((b<10) ? (b+48) : (b+87)) & 255;
312 static void real_calc_response_and_checksum (char *response, char *chksum, char *challenge) {
314 int ch_len, resp_len;
319 /* initialize return values */
320 memset(response, 0, 64);
321 memset(chksum, 0, 34);
323 /* initialize buffer */
326 BE_32C(ptr, 0xa1e9149d);
328 BE_32C(ptr, 0x0e6b3b59);
331 /* some (length) checks */
332 if (challenge != NULL)
334 ch_len = strlen (challenge);
336 if (ch_len == 40) /* what a hack... */
341 if ( ch_len > 56 ) ch_len=56;
343 /* copy challenge to buf */
344 memcpy(ptr, challenge, ch_len);
347 /* xor challenge bytewise with xor_table */
348 for (i=0; i<XOR_TABLE_LEN; i++)
349 ptr[i] = ptr[i] ^ xor_table[i];
351 calc_response_string (response, buf);
354 resp_len = strlen (response);
355 strcpy (&response[resp_len], "01d0a8e3");
357 /* calculate checksum */
358 for (i=0; i<resp_len/4; i++)
359 chksum[i] = response[i*4];
364 * takes a MLTI-Chunk and a rule number got from match_asm_rule,
365 * returns a pointer to selected data and number of bytes in that.
367 static int select_mlti_data(const char *mlti_chunk, int mlti_size, int selection, char **out) {
369 int numrules, codec, size;
372 /* MLTI chunk should begin with MLTI */
373 if ((mlti_chunk[0] != 'M')
374 ||(mlti_chunk[1] != 'L')
375 ||(mlti_chunk[2] != 'T')
376 ||(mlti_chunk[3] != 'I'))
378 lprintf("MLTI tag not detected, copying data\n");
379 memcpy(*out, mlti_chunk, mlti_size);
385 /* next 16 bits are the number of rules */
386 numrules=BE_16(mlti_chunk);
387 if (selection >= numrules) return 0;
389 /* now <numrules> indices of codecs follows */
390 /* we skip to selection */
391 mlti_chunk+=(selection+1)*2;
394 codec=BE_16(mlti_chunk);
396 /* skip to number of codecs */
397 mlti_chunk+=(numrules-selection)*2;
399 /* get number of codecs */
400 numrules=BE_16(mlti_chunk);
402 if (codec >= numrules) {
403 lprintf("codec index >= number of codecs. %i %i\n", codec, numrules);
409 /* now seek to selected codec */
410 for (i=0; i<codec; i++) {
411 size=BE_32(mlti_chunk);
414 size=BE_32(mlti_chunk);
416 memcpy(*out, mlti_chunk+4, size);
421 * looking at stream description.
424 static rmff_header_t *real_parse_sdp(char *data, char **stream_rules, uint32_t bandwidth) {
426 sdpplin_t *desc = NULL;
427 rmff_header_t *header = NULL;
432 int max_packet_size=0;
433 int avg_packet_size=0;
436 if( !data ) return NULL;
438 desc=sdpplin_parse(data);
439 if( !desc ) return NULL;
441 buf= (char *)malloc(2048);
442 if( !buf ) goto error;
444 header = calloc( 1, sizeof(rmff_header_t) );
445 if( !header ) goto error;
447 header->fileheader=rmff_new_fileheader(4+desc->stream_count);
448 header->cont=rmff_new_cont(
454 header->data=rmff_new_dataheader(0,0);
455 if( !header->data ) goto error;
457 header->streams = calloc( desc->stream_count+1, sizeof(rmff_mdpr_t*) );
458 if( !header->streams ) goto error;
460 lprintf("number of streams: %u\n", desc->stream_count);
462 for (i=0; i<desc->stream_count; i++) {
469 lprintf("calling asmrp_match with:\n%s\n%u\n", desc->stream[i]->asm_rule_book, bandwidth);
471 n=asmrp_match(desc->stream[i]->asm_rule_book, bandwidth, rulematches, sizeof(rulematches)/sizeof(rulematches[0]));
472 for (j=0; j<n; j++) {
473 lprintf("asmrp rule match: %u for stream %u\n", rulematches[j], desc->stream[i]->stream_id);
474 sprintf(b,"stream=%u;rule=%u,", desc->stream[i]->stream_id, rulematches[j]);
475 strcat(*stream_rules, b);
478 if (!desc->stream[i]->mlti_data) {
483 len=select_mlti_data(desc->stream[i]->mlti_data,
484 desc->stream[i]->mlti_data_size, rulematches[0], &buf);
486 header->streams[i]=rmff_new_mdpr(
487 desc->stream[i]->stream_id,
488 desc->stream[i]->max_bit_rate,
489 desc->stream[i]->avg_bit_rate,
490 desc->stream[i]->max_packet_size,
491 desc->stream[i]->avg_packet_size,
492 desc->stream[i]->start_time,
493 desc->stream[i]->preroll,
494 desc->stream[i]->duration,
495 desc->stream[i]->stream_name,
496 desc->stream[i]->mime_type,
499 if( !header->streams[i] ) goto error;
501 duration=MAX(duration,desc->stream[i]->duration);
502 max_bit_rate+=desc->stream[i]->max_bit_rate;
503 avg_bit_rate+=desc->stream[i]->avg_bit_rate;
504 max_packet_size=MAX(max_packet_size, desc->stream[i]->max_packet_size);
506 avg_packet_size=(avg_packet_size + desc->stream[i]->avg_packet_size) / 2;
508 avg_packet_size=desc->stream[i]->avg_packet_size;
511 if (*stream_rules && strlen(*stream_rules) && (*stream_rules)[strlen(*stream_rules)-1] == ',')
512 (*stream_rules)[strlen(*stream_rules)-1]=0; /* delete last ',' in stream_rules */
514 header->prop=rmff_new_prop(
526 if( !header->prop ) goto error;
528 rmff_fix_header(header);
530 sdpplin_free( desc );
535 sdpplin_free( desc );
536 rmff_free_header( header );
541 int real_get_rdt_chunk_header(rtsp_client_t *rtsp_session, rmff_pheader_t *ph) {
550 n=rtsp_read_data(rtsp_session, header, 8);
552 if (header[0] != 0x24)
554 lprintf("rdt chunk not recognized: got 0x%02x\n", header[0]);
557 size=(header[1]<<16)+(header[2]<<8)+(header[3]);
559 if ((flags1!=0x40)&&(flags1!=0x42))
561 lprintf("got flags1: 0x%02x\n",flags1);
564 lprintf("got end of stream packet\n");
570 n=rtsp_read_data(rtsp_session, header+3, 5);
572 lprintf("ignoring bytes:\n");
573 n=rtsp_read_data(rtsp_session, header+4, 4);
578 unknown1=(header[5]<<16)+(header[6]<<8)+(header[7]);
579 n=rtsp_read_data(rtsp_session, header, 6);
584 lprintf("ts: %u size: %u, flags: 0x%02x, unknown values: %u 0x%02x 0x%02x\n",
585 ts, size, flags1, unknown1, header[4], header[5]);
589 ph->object_version=0;
591 ph->stream_number=(flags1>>1)&1;
594 ph->flags=0; /* TODO: determine keyframe flag and insert here? */
598 int real_get_rdt_chunk(rtsp_client_t *rtsp_session, rmff_pheader_t *ph,
599 unsigned char **buffer) {
602 rmff_dump_pheader(ph, (char*)*buffer);
603 if (ph->length<12) return 0;
604 n=rtsp_read_data(rtsp_session, (uint8_t*)(*buffer + 12), ph->length - 12);
605 return (n <= 0) ? 0 : n+12;
608 //! maximum size of the rtsp description, must be < INT_MAX
609 #define MAX_DESC_BUF (20 * 1024 * 1024)
610 rmff_header_t *real_setup_and_get_header(rtsp_client_t *rtsp_session, int bandwidth) {
612 char *description=NULL;
613 char *session_id=NULL;
614 rmff_header_t *h=NULL;
615 char *challenge1 = NULL;
618 char *subscribe=NULL;
619 char *buf = malloc(256);
622 char *mrl=rtsp_get_mrl(rtsp_session);
627 challenge1=strdup(rtsp_search_answers(rtsp_session,"RealChallenge1"));
628 lprintf("Challenge1: %s\n", challenge1);
630 /* request stream description */
631 rtsp_schedule_field(rtsp_session, "Accept: application/sdp");
632 sprintf(buf, "Bandwidth: %u", bandwidth);
633 rtsp_schedule_field(rtsp_session, buf);
634 rtsp_schedule_field(rtsp_session, "GUID: 00000000-0000-0000-0000-000000000000");
635 rtsp_schedule_field(rtsp_session, "RegionData: 0");
636 rtsp_schedule_field(rtsp_session, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586");
637 rtsp_schedule_field(rtsp_session, "SupportsMaximumASMBandwidth: 1");
638 rtsp_schedule_field(rtsp_session, "Language: en-US");
639 rtsp_schedule_field(rtsp_session, "Require: com.real.retain-entity-for-setup");
641 status=rtsp_request_describe(rtsp_session,NULL);
642 if ( status<200 || status>299 ) {
643 char *alert=rtsp_search_answers(rtsp_session,"Alert");
645 lprintf("real: got message from server:\n%s\n", alert);
647 rtsp_send_ok( rtsp_session );
654 /* receive description */
656 if (!rtsp_search_answers(rtsp_session,"Content-length"))
657 lprintf("real: got no Content-length!\n");
659 size=atoi(rtsp_search_answers(rtsp_session,"Content-length"));
661 if (size > MAX_DESC_BUF) {
662 printf("real: Content-length for description too big (> %uMB)!\n",
663 MAX_DESC_BUF/(1024*1024) );
667 if (!rtsp_search_answers(rtsp_session,"ETag"))
668 lprintf("real: got no ETag!\n");
670 session_id=strdup(rtsp_search_answers(rtsp_session,"ETag"));
672 lprintf("Stream description size: %i\n", size);
674 description = malloc(size+1);
677 if( rtsp_read_data(rtsp_session, (uint8_t*)description, size) <= 0)
680 //fprintf(stderr, "%s", description);
682 /* parse sdp (sdpplin) and create a header and a subscribe string */
683 subscribe = malloc(256);
687 strcpy(subscribe, "Subscribe: ");
688 h=real_parse_sdp(description, &subscribe, bandwidth);
695 fprintf("Title: %s\nCopyright: %s\nAuthor: %s\nStreams: %i\n",
696 h->cont->title, h->cont->copyright, h->cont->author, h->prop->num_streams);
699 /* setup our streams */
700 real_calc_response_and_checksum (challenge2, checksum, challenge1);
701 buf = realloc_(buf, strlen(challenge2) + strlen(checksum) + 32);
702 if( !buf ) goto error;
703 sprintf(buf, "RealChallenge2: %s, sd=%s", challenge2, checksum);
704 rtsp_schedule_field(rtsp_session, buf);
705 buf = realloc_(buf, strlen(session_id) + 32);
706 if( !buf ) goto error;
707 sprintf(buf, "If-Match: %s", session_id);
708 rtsp_schedule_field(rtsp_session, buf);
709 rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
710 buf = realloc_(buf, strlen(mrl) + 32);
711 if( !buf ) goto error;
712 sprintf(buf, "%s/streamid=0", mrl);
713 rtsp_request_setup(rtsp_session,buf);
715 if (h->prop->num_streams > 1) {
716 rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
717 buf = realloc_(buf, strlen(session_id) + 32);
718 if( !buf ) goto error;
719 sprintf(buf, "If-Match: %s", session_id);
720 rtsp_schedule_field(rtsp_session, buf);
721 buf = realloc_(buf, strlen(mrl) + 32);
722 if( !buf ) goto error;
723 sprintf(buf, "%s/streamid=1", mrl);
724 rtsp_request_setup(rtsp_session,buf);
726 /* set stream parameter (bandwidth) with our subscribe string */
727 rtsp_schedule_field(rtsp_session, subscribe);
728 rtsp_request_setparameter(rtsp_session,NULL);
730 /* and finally send a play request */
731 rtsp_schedule_field(rtsp_session, "Range: npt=0-");
732 rtsp_request_play(rtsp_session,NULL);
742 rmff_free_header( h );