Mercurial > mplayer.hg
annotate libmpdemux/realrtsp/rtsp.c @ 10560:11826d9f90c7
this patch fixes
1) some bugs introduced in the tuner autodetection and in the channel-parsing functions,
3) retries reading when the mplayer/mencoder don't read fast enough (sooner it exited)
but especially
4) makes the stream compliant with the new, modular stream api (the one
currently in CVS is not and is totally unreachable).
[and maybe more, next time please include cvslog in patch! -- A'rpi]
patch by Nico <nsabbi@libero.it>
author | arpi |
---|---|
date | Mon, 11 Aug 2003 00:02:46 +0000 |
parents | 54bcbf28698a |
children | 6e35326c742f |
rev | line source |
---|---|
9922 | 1 /* |
2 * This file was ported to MPlayer from xine CVS rtsp.c,v 1.9 2003/04/10 02:30:48 | |
3 */ | |
4 | |
5 /* | |
6 * Copyright (C) 2000-2002 the xine project | |
7 * | |
8 * This file is part of xine, a free video player. | |
9 * | |
10 * xine is free software; you can redistribute it and/or modify | |
11 * it under the terms of the GNU General Public License as published by | |
12 * the Free Software Foundation; either version 2 of the License, or | |
13 * (at your option) any later version. | |
14 * | |
15 * xine is distributed in the hope that it will be useful, | |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 * GNU General Public License for more details. | |
19 * | |
20 * You should have received a copy of the GNU General Public License | |
21 * along with this program; if not, write to the Free Software | |
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | |
23 * | |
24 * | |
25 * a minimalistic implementation of rtsp protocol, | |
26 * *not* RFC 2326 compilant yet. | |
27 */ | |
28 | |
29 #include <unistd.h> | |
30 #include <stdio.h> | |
31 #include <assert.h> | |
10281 | 32 #include "config.h" |
33 #ifndef HAVE_WINSOCK2 | |
34 #define closesocket close | |
9922 | 35 #include <sys/socket.h> |
36 #include <netinet/in.h> | |
37 #include <netdb.h> | |
10281 | 38 #else |
39 #include <winsock2.h> | |
40 #endif | |
9922 | 41 #include <string.h> |
42 #include <sys/stat.h> | |
43 #include <fcntl.h> | |
44 #include <errno.h> | |
45 #include <stdlib.h> | |
46 #include <time.h> | |
47 #include <sys/time.h> | |
48 #include <sys/types.h> | |
9939
6b88f67564ce
Fix compilation for *BSD, Mac OS X and maybe others (info by Steven M. Schultz and Dan Christiansen)
rtognimp
parents:
9922
diff
changeset
|
49 #include <inttypes.h> |
9922 | 50 |
51 #include "rtsp.h" | |
52 | |
53 /* | |
54 #define LOG | |
55 */ | |
56 | |
57 #define BUF_SIZE 4096 | |
58 #define HEADER_SIZE 1024 | |
59 #define MAX_FIELDS 256 | |
60 | |
61 struct rtsp_s { | |
62 | |
63 int s; | |
64 | |
65 char *host; | |
66 int port; | |
67 char *path; | |
68 char *mrl; | |
69 char *user_agent; | |
70 | |
71 char *server; | |
72 unsigned int server_state; | |
73 uint32_t server_caps; | |
74 | |
75 char buffer[BUF_SIZE]; /* scratch buffer */ | |
76 | |
77 unsigned int cseq; | |
78 char *session; | |
79 | |
80 char *answers[MAX_FIELDS]; /* data of last message */ | |
81 char *scheduled[MAX_FIELDS]; /* will be sent with next message */ | |
82 }; | |
83 | |
84 /* | |
85 * constants | |
86 */ | |
87 | |
88 const char rtsp_protocol_version[]="RTSP/1.0"; | |
89 | |
90 /* server states */ | |
91 #define RTSP_CONNECTED 1 | |
92 #define RTSP_INIT 2 | |
93 #define RTSP_READY 4 | |
94 #define RTSP_PLAYING 8 | |
95 #define RTSP_RECORDING 16 | |
96 | |
97 /* server capabilities */ | |
98 #define RTSP_OPTIONS 0x001 | |
99 #define RTSP_DESCRIBE 0x002 | |
100 #define RTSP_ANNOUNCE 0x004 | |
101 #define RTSP_SETUP 0x008 | |
102 #define RTSP_GET_PARAMETER 0x010 | |
103 #define RTSP_SET_PARAMETER 0x020 | |
104 #define RTSP_TEARDOWN 0x040 | |
105 #define RTSP_PLAY 0x080 | |
106 #define RTSP_RECORD 0x100 | |
107 | |
108 /* | |
109 * network utilities | |
110 */ | |
111 | |
112 static int host_connect_attempt(struct in_addr ia, int port) { | |
113 | |
114 int s; | |
115 struct sockaddr_in sin; | |
116 | |
117 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); | |
118 if (s == -1) { | |
119 printf ("rtsp: socket(): %s\n", strerror(errno)); | |
120 return -1; | |
121 } | |
122 | |
123 sin.sin_family = AF_INET; | |
124 sin.sin_addr = ia; | |
125 sin.sin_port = htons(port); | |
126 | |
127 if (connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1 | |
10281 | 128 #ifndef HAVE_WINSOCK2 |
9922 | 129 && errno != EINPROGRESS) { |
10281 | 130 #else |
131 && WSAGetLastError() == WSAEINPROGRESS) { | |
132 #endif | |
9922 | 133 printf ("rtsp: connect(): %s\n", strerror(errno)); |
10281 | 134 closesocket(s); |
9922 | 135 return -1; |
136 } | |
137 | |
138 return s; | |
139 } | |
140 | |
141 static int host_connect(const char *host, int port) { | |
142 | |
143 struct hostent *h; | |
144 int i, s; | |
145 | |
146 h = gethostbyname(host); | |
147 if (h == NULL) { | |
148 printf ("rtsp: unable to resolve '%s'.\n", host); | |
149 return -1; | |
150 } | |
151 | |
152 for (i = 0; h->h_addr_list[i]; i++) { | |
153 struct in_addr ia; | |
154 | |
155 memcpy (&ia, h->h_addr_list[i], 4); | |
156 s = host_connect_attempt(ia, port); | |
157 if(s != -1) | |
158 return s; | |
159 } | |
160 printf ("rtsp: unable to connect to '%s'.\n", host); | |
161 return -1; | |
162 } | |
163 | |
164 static int write_stream(int s, const char *buf, int len) { | |
165 int total, timeout; | |
166 | |
167 total = 0; timeout = 30; | |
168 while (total < len){ | |
169 int n; | |
170 | |
10206
35e306346e59
Using recv/send instead read/write for proper MinGW support (it's a 4.2BSD standard). Patch by FloDt <flodt8@yahoo.de>
alex
parents:
9939
diff
changeset
|
171 n = send (s, &buf[total], len - total, 0); |
9922 | 172 |
173 if (n > 0) | |
174 total += n; | |
175 else if (n < 0) { | |
10281 | 176 #ifndef HAVE_WINSOCK2 |
9922 | 177 if ((timeout>0) && ((errno == EAGAIN) || (errno == EINPROGRESS))) { |
10281 | 178 #else |
179 if ((timeout>0) && ((errno == EAGAIN) || (WSAGetLastError() == WSAEINPROGRESS))) { | |
180 #endif | |
9922 | 181 sleep (1); timeout--; |
182 } else | |
183 return -1; | |
184 } | |
185 } | |
186 | |
187 return total; | |
188 } | |
189 | |
190 static ssize_t read_stream(int fd, void *buf, size_t count) { | |
191 | |
192 ssize_t ret, total; | |
193 | |
194 total = 0; | |
195 | |
196 while (total < count) { | |
197 | |
10206
35e306346e59
Using recv/send instead read/write for proper MinGW support (it's a 4.2BSD standard). Patch by FloDt <flodt8@yahoo.de>
alex
parents:
9939
diff
changeset
|
198 ret=recv (fd, ((uint8_t*)buf)+total, count-total, 0); |
9922 | 199 |
200 if (ret<0) { | |
201 if(errno == EAGAIN) { | |
202 fd_set rset; | |
203 struct timeval timeout; | |
204 | |
205 FD_ZERO (&rset); | |
206 FD_SET (fd, &rset); | |
207 | |
208 timeout.tv_sec = 30; | |
209 timeout.tv_usec = 0; | |
210 | |
211 if (select (fd+1, &rset, NULL, NULL, &timeout) <= 0) { | |
212 return -1; | |
213 } | |
214 continue; | |
215 } | |
216 | |
217 printf ("rtsp: read error.\n"); | |
218 return ret; | |
219 } else | |
220 total += ret; | |
221 | |
222 /* end of stream */ | |
223 if (!ret) break; | |
224 } | |
225 | |
226 return total; | |
227 } | |
228 | |
229 /* | |
230 * debugging utilities | |
231 */ | |
232 #if 0 | |
233 static void hexdump (char *buf, int length) { | |
234 | |
235 int i; | |
236 | |
237 printf ("rtsp: ascii>"); | |
238 for (i = 0; i < length; i++) { | |
239 unsigned char c = buf[i]; | |
240 | |
241 if ((c >= 32) && (c <= 128)) | |
242 printf ("%c", c); | |
243 else | |
244 printf ("."); | |
245 } | |
246 printf ("\n"); | |
247 | |
248 printf ("rtsp: hexdump> "); | |
249 for (i = 0; i < length; i++) { | |
250 unsigned char c = buf[i]; | |
251 | |
252 printf ("%02x", c); | |
253 | |
254 if ((i % 16) == 15) | |
255 printf ("\nrtsp: "); | |
256 | |
257 if ((i % 2) == 1) | |
258 printf (" "); | |
259 | |
260 } | |
261 printf ("\n"); | |
262 } | |
263 #endif | |
264 | |
265 /* | |
266 * rtsp_get gets a line from stream | |
267 * and returns a null terminated string. | |
268 */ | |
269 | |
270 static char *rtsp_get(rtsp_t *s) { | |
271 | |
272 int n=0; | |
273 char *string; | |
274 | |
275 while (n<BUF_SIZE) { | |
276 read_stream(s->s, &s->buffer[n], 1); | |
277 if ((s->buffer[n-1]==0x0d)&&(s->buffer[n]==0x0a)) break; | |
278 n++; | |
279 } | |
280 | |
281 if (n>=BUF_SIZE) { | |
282 printf("librtsp: buffer overflow in rtsp_get\n"); | |
283 exit(1); | |
284 } | |
285 string=malloc(sizeof(char)*n); | |
286 memcpy(string,s->buffer,n-1); | |
287 string[n-1]=0; | |
288 | |
289 #ifdef LOG | |
290 printf("librtsp: << '%s'\n", string); | |
291 #endif | |
292 | |
293 | |
294 return string; | |
295 } | |
296 | |
297 /* | |
298 * rtsp_put puts a line on stream | |
299 */ | |
300 | |
301 static void rtsp_put(rtsp_t *s, const char *string) { | |
302 | |
303 int len=strlen(string); | |
304 char *buf=malloc(sizeof(char)*len+2); | |
305 | |
306 #ifdef LOG | |
307 printf("librtsp: >> '%s'", string); | |
308 #endif | |
309 | |
310 memcpy(buf,string,len); | |
311 buf[len]=0x0d; | |
312 buf[len+1]=0x0a; | |
313 | |
314 write_stream(s->s, buf, len+2); | |
315 | |
316 #ifdef LOG | |
317 printf(" done.\n"); | |
318 #endif | |
319 | |
320 free(buf); | |
321 } | |
322 | |
323 /* | |
324 * extract server status code | |
325 */ | |
326 | |
327 static int rtsp_get_code(const char *string) { | |
328 | |
329 char buf[4]; | |
330 int code=0; | |
331 | |
332 if (!strncmp(string, rtsp_protocol_version, strlen(rtsp_protocol_version))) | |
333 { | |
334 memcpy(buf, string+strlen(rtsp_protocol_version)+1, 3); | |
335 buf[3]=0; | |
336 code=atoi(buf); | |
337 } else if (!strncmp(string, "SET_PARAMETER",8)) | |
338 { | |
339 return RTSP_STATUS_SET_PARAMETER; | |
340 } | |
341 | |
342 if(code != 200) printf("librtsp: server responds: '%s'\n",string); | |
343 | |
344 return code; | |
345 } | |
346 | |
347 /* | |
348 * send a request | |
349 */ | |
350 | |
351 static void rtsp_send_request(rtsp_t *s, const char *type, const char *what) { | |
352 | |
353 char **payload=s->scheduled; | |
354 sprintf(s->buffer,"%s %s %s",type, what, rtsp_protocol_version); | |
355 rtsp_put(s,s->buffer); | |
356 if (payload) | |
357 while (*payload) { | |
358 rtsp_put(s,*payload); | |
359 payload++; | |
360 } | |
361 rtsp_put(s,""); | |
362 rtsp_unschedule_all(s); | |
363 } | |
364 | |
365 /* | |
366 * schedule standard fields | |
367 */ | |
368 | |
369 static void rtsp_schedule_standard(rtsp_t *s) { | |
370 | |
371 sprintf(s->buffer, "Cseq: %u", s->cseq); | |
372 rtsp_schedule_field(s, s->buffer); | |
373 if (s->session) { | |
374 sprintf(s->buffer, "Session: %s", s->session); | |
375 rtsp_schedule_field(s, s->buffer); | |
376 } | |
377 } | |
378 /* | |
379 * get the answers, if server responses with something != 200, return NULL | |
380 */ | |
381 | |
382 static int rtsp_get_answers(rtsp_t *s) { | |
383 | |
384 char *answer=NULL; | |
385 unsigned int answer_seq; | |
386 char **answer_ptr=s->answers; | |
387 int code; | |
388 | |
389 answer=rtsp_get(s); | |
390 code=rtsp_get_code(answer); | |
391 free(answer); | |
392 | |
393 rtsp_free_answers(s); | |
394 | |
395 do { /* while we get answer lines */ | |
396 | |
397 answer=rtsp_get(s); | |
398 | |
399 if (!strncmp(answer,"Cseq:",5)) { | |
400 sscanf(answer,"Cseq: %u",&answer_seq); | |
401 if (s->cseq != answer_seq) { | |
402 #ifdef LOG | |
403 printf("librtsp: warning: Cseq mismatch. got %u, assumed %u", answer_seq, s->cseq); | |
404 #endif | |
405 s->cseq=answer_seq; | |
406 } | |
407 } | |
408 if (!strncmp(answer,"Server:",7)) { | |
409 sscanf(answer,"Server: %s",s->buffer); | |
410 if (s->server) free(s->server); | |
411 s->server=strdup(s->buffer); | |
412 } | |
413 if (!strncmp(answer,"Session:",8)) { | |
414 memset(s->buffer,0, BUF_SIZE); | |
415 sscanf(answer,"Session: %s",s->buffer); | |
416 if (s->session) { | |
417 if (strcmp(s->buffer, s->session)) { | |
418 printf("rtsp: warning: setting NEW session: %s\n", s->buffer); | |
419 free(s->session); | |
420 s->session=strdup(s->buffer); | |
421 } | |
422 } else | |
423 { | |
424 #ifdef LOG | |
425 printf("rtsp: setting session id to: %s\n", s->buffer); | |
426 #endif | |
427 s->session=strdup(s->buffer); | |
428 } | |
429 } | |
430 *answer_ptr=answer; | |
431 answer_ptr++; | |
432 } while (strlen(answer)!=0); | |
433 | |
434 s->cseq++; | |
435 | |
436 *answer_ptr=NULL; | |
437 rtsp_schedule_standard(s); | |
438 | |
439 return code; | |
440 } | |
441 | |
442 /* | |
443 * send an ok message | |
444 */ | |
445 | |
446 int rtsp_send_ok(rtsp_t *s) { | |
447 char cseq[16]; | |
448 | |
449 rtsp_put(s, "RTSP/1.0 200 OK"); | |
450 sprintf(cseq,"CSeq: %u", s->cseq); | |
451 rtsp_put(s, cseq); | |
452 rtsp_put(s, ""); | |
453 return 0; | |
454 } | |
455 | |
456 /* | |
457 * implementation of must-have rtsp requests; functions return | |
458 * server status code. | |
459 */ | |
460 | |
461 int rtsp_request_options(rtsp_t *s, const char *what) { | |
462 | |
463 char *buf; | |
464 | |
465 if (what) { | |
466 buf=strdup(what); | |
467 } else | |
468 { | |
469 buf=malloc(sizeof(char)*(strlen(s->host)+16)); | |
470 sprintf(buf,"rtsp://%s:%i", s->host, s->port); | |
471 } | |
472 rtsp_send_request(s,"OPTIONS",buf); | |
473 free(buf); | |
474 | |
475 return rtsp_get_answers(s); | |
476 } | |
477 | |
478 int rtsp_request_describe(rtsp_t *s, const char *what) { | |
479 | |
480 char *buf; | |
481 | |
482 if (what) { | |
483 buf=strdup(what); | |
484 } else | |
485 { | |
486 buf=malloc(sizeof(char)*(strlen(s->host)+strlen(s->path)+16)); | |
487 sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); | |
488 } | |
489 rtsp_send_request(s,"DESCRIBE",buf); | |
490 free(buf); | |
491 | |
492 return rtsp_get_answers(s); | |
493 } | |
494 | |
495 int rtsp_request_setup(rtsp_t *s, const char *what) { | |
496 | |
497 rtsp_send_request(s,"SETUP",what); | |
498 | |
499 return rtsp_get_answers(s); | |
500 } | |
501 | |
502 int rtsp_request_setparameter(rtsp_t *s, const char *what) { | |
503 | |
504 char *buf; | |
505 | |
506 if (what) { | |
507 buf=strdup(what); | |
508 } else | |
509 { | |
510 buf=malloc(sizeof(char)*(strlen(s->host)+strlen(s->path)+16)); | |
511 sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); | |
512 } | |
513 rtsp_send_request(s,"SET_PARAMETER",buf); | |
514 free(buf); | |
515 | |
516 return rtsp_get_answers(s); | |
517 } | |
518 | |
519 int rtsp_request_play(rtsp_t *s, const char *what) { | |
520 | |
521 char *buf; | |
522 | |
523 if (what) { | |
524 buf=strdup(what); | |
525 } else | |
526 { | |
527 buf=malloc(sizeof(char)*(strlen(s->host)+strlen(s->path)+16)); | |
528 sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); | |
529 } | |
530 rtsp_send_request(s,"PLAY",buf); | |
531 free(buf); | |
532 | |
533 return rtsp_get_answers(s); | |
534 } | |
535 | |
536 int rtsp_request_tearoff(rtsp_t *s, const char *what) { | |
537 | |
538 rtsp_send_request(s,"TEAROFF",what); | |
539 | |
540 return rtsp_get_answers(s); | |
541 } | |
542 | |
543 /* | |
544 * read opaque data from stream | |
545 */ | |
546 | |
547 int rtsp_read_data(rtsp_t *s, char *buffer, unsigned int size) { | |
548 | |
549 int i,seq; | |
550 | |
551 if (size>=4) { | |
552 i=read_stream(s->s, buffer, 4); | |
553 if (i<4) return i; | |
554 if ((buffer[0]=='S')&&(buffer[1]=='E')&&(buffer[2]=='T')&&(buffer[3]=='_')) | |
555 { | |
556 char *rest=rtsp_get(s); | |
557 /* a real server wanna play table tennis? */ | |
558 memcpy(s->buffer, buffer, 4); | |
559 strcpy(s->buffer+4, rest); | |
560 seq=-1; | |
561 do { | |
562 free(rest); | |
563 rest=rtsp_get(s); | |
564 if (!strncmp(rest,"Cseq:",5)) | |
565 sscanf(rest,"Cseq: %u",&seq); | |
566 } while (strlen(rest)!=0); | |
567 free(rest); | |
568 if (seq<0) { | |
569 #ifdef LOG | |
570 printf("rtsp: warning: cseq not recognized!\n"); | |
571 #endif | |
572 seq=1; | |
573 } | |
574 /* lets make the server happy */ | |
575 rtsp_put(s, "RTSP/1.0 451 Parameter Not Understood"); | |
576 rest=malloc(sizeof(char)*16); | |
577 sprintf(rest,"CSeq: %u", seq); | |
578 rtsp_put(s, rest); | |
579 rtsp_put(s, ""); | |
580 i=read_stream(s->s, buffer, size); | |
581 } else | |
582 { | |
583 i=read_stream(s->s, buffer+4, size-4); | |
584 i+=4; | |
585 } | |
586 } else | |
587 i=read_stream(s->s, buffer, size); | |
588 #ifdef LOG | |
589 printf("librtsp: << %d of %d bytes\n", i, size); | |
590 #endif | |
591 | |
592 return i; | |
593 } | |
594 | |
595 /* | |
596 * connect to a rtsp server | |
597 */ | |
598 | |
599 //rtsp_t *rtsp_connect(const char *mrl, const char *user_agent) { | |
600 rtsp_t *rtsp_connect(int fd, char* mrl, char *path, char *host, int port, char *user_agent) { | |
601 | |
602 rtsp_t *s=malloc(sizeof(rtsp_t)); | |
603 int i; | |
604 | |
605 for (i=0; i<MAX_FIELDS; i++) { | |
606 s->answers[i]=NULL; | |
607 s->scheduled[i]=NULL; | |
608 } | |
609 | |
610 s->server=NULL; | |
611 s->server_state=0; | |
612 s->server_caps=0; | |
613 | |
614 s->cseq=0; | |
615 s->session=NULL; | |
616 | |
617 if (user_agent) | |
618 s->user_agent=strdup(user_agent); | |
619 else | |
620 s->user_agent=strdup("User-Agent: RealMedia Player Version 6.0.9.1235 (linux-2.0-libc6-i386-gcc2.95)"); | |
621 | |
622 s->mrl = strdup(mrl); | |
623 s->host = strdup(host); | |
624 s->port = port; | |
625 s->path = strdup(path); | |
626 s->s = fd; | |
627 | |
628 if (s->s < 0) { | |
629 printf ("rtsp: failed to connect to '%s'\n", s->host); | |
630 rtsp_close(s); | |
631 return NULL; | |
632 } | |
633 | |
634 s->server_state=RTSP_CONNECTED; | |
635 | |
636 /* now lets send an options request. */ | |
637 rtsp_schedule_field(s, "CSeq: 1"); | |
638 rtsp_schedule_field(s, s->user_agent); | |
639 rtsp_schedule_field(s, "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7"); | |
640 rtsp_schedule_field(s, "PlayerStarttime: [28/03/2003:22:50:23 00:00]"); | |
641 rtsp_schedule_field(s, "CompanyID: KnKV4M4I/B2FjJ1TToLycw=="); | |
642 rtsp_schedule_field(s, "GUID: 00000000-0000-0000-0000-000000000000"); | |
643 rtsp_schedule_field(s, "RegionData: 0"); | |
644 rtsp_schedule_field(s, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586"); | |
645 /*rtsp_schedule_field(s, "Pragma: initiate-session");*/ | |
646 rtsp_request_options(s, NULL); | |
647 | |
648 return s; | |
649 } | |
650 | |
651 | |
652 /* | |
653 * closes an rtsp connection | |
654 */ | |
655 | |
656 void rtsp_close(rtsp_t *s) { | |
657 | |
10281 | 658 if (s->server_state) closesocket(s->s); /* TODO: send a TEAROFF */ |
9922 | 659 if (s->path) free(s->path); |
660 if (s->host) free(s->host); | |
661 if (s->mrl) free(s->mrl); | |
662 if (s->session) free(s->session); | |
663 if (s->user_agent) free(s->user_agent); | |
664 rtsp_free_answers(s); | |
665 rtsp_unschedule_all(s); | |
666 free(s); | |
667 } | |
668 | |
669 /* | |
670 * search in answers for tags. returns a pointer to the content | |
671 * after the first matched tag. returns NULL if no match found. | |
672 */ | |
673 | |
674 char *rtsp_search_answers(rtsp_t *s, const char *tag) { | |
675 | |
676 char **answer; | |
677 char *ptr; | |
678 | |
679 if (!s->answers) return NULL; | |
680 answer=s->answers; | |
681 | |
682 while (*answer) { | |
683 if (!strncasecmp(*answer,tag,strlen(tag))) { | |
684 ptr=strchr(*answer,':'); | |
685 ptr++; | |
686 while(*ptr==' ') ptr++; | |
687 return ptr; | |
688 } | |
689 answer++; | |
690 } | |
691 | |
692 return NULL; | |
693 } | |
694 | |
695 /* | |
696 * session id management | |
697 */ | |
698 | |
699 void rtsp_set_session(rtsp_t *s, const char *id) { | |
700 | |
701 if (s->session) free(s->session); | |
702 | |
703 s->session=strdup(id); | |
704 | |
705 } | |
706 | |
707 char *rtsp_get_session(rtsp_t *s) { | |
708 | |
709 return s->session; | |
710 | |
711 } | |
712 | |
713 char *rtsp_get_mrl(rtsp_t *s) { | |
714 | |
715 return s->mrl; | |
716 | |
717 } | |
718 | |
719 /* | |
720 * schedules a field for transmission | |
721 */ | |
722 | |
723 void rtsp_schedule_field(rtsp_t *s, const char *string) { | |
724 | |
725 int i=0; | |
726 | |
727 if (!string) return; | |
728 | |
729 while(s->scheduled[i]) { | |
730 i++; | |
731 } | |
732 s->scheduled[i]=strdup(string); | |
733 } | |
734 | |
735 /* | |
736 * removes the first scheduled field which prefix matches string. | |
737 */ | |
738 | |
739 void rtsp_unschedule_field(rtsp_t *s, const char *string) { | |
740 | |
741 char **ptr=s->scheduled; | |
742 | |
743 if (!string) return; | |
744 | |
745 while(*ptr) { | |
746 if (!strncmp(*ptr, string, strlen(string))) | |
747 break; | |
748 } | |
749 if (*ptr) free(*ptr); | |
750 ptr++; | |
751 do { | |
752 *(ptr-1)=*ptr; | |
753 } while(*ptr); | |
754 } | |
755 | |
756 /* | |
757 * unschedule all fields | |
758 */ | |
759 | |
760 void rtsp_unschedule_all(rtsp_t *s) { | |
761 | |
762 char **ptr; | |
763 | |
764 if (!s->scheduled) return; | |
765 ptr=s->scheduled; | |
766 | |
767 while (*ptr) { | |
768 free(*ptr); | |
769 *ptr=NULL; | |
770 ptr++; | |
771 } | |
772 } | |
773 /* | |
774 * free answers | |
775 */ | |
776 | |
777 void rtsp_free_answers(rtsp_t *s) { | |
778 | |
779 char **answer; | |
780 | |
781 if (!s->answers) return; | |
782 answer=s->answers; | |
783 | |
784 while (*answer) { | |
785 free(*answer); | |
786 *answer=NULL; | |
787 answer++; | |
788 } | |
789 } |