00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028
00029 #include <vlc/vlc.h>
00030
00031 #include "rtsp.h"
00032
00033 #define BUF_SIZE 4096
00034 #define HEADER_SIZE 1024
00035 #define MAX_FIELDS 256
00036
00037 struct rtsp_s {
00038
00039 int s;
00040
00041 char *host;
00042 int port;
00043 char *path;
00044 char *mrl;
00045 char *user_agent;
00046
00047 char *server;
00048 unsigned int server_state;
00049 uint32_t server_caps;
00050
00051 unsigned int cseq;
00052 char *session;
00053
00054 char *answers[MAX_FIELDS];
00055 char *scheduled[MAX_FIELDS];
00056 };
00057
00058
00059
00060
00061
00062 const char rtsp_protocol_version[]="RTSP/1.0";
00063
00064
00065 #define RTSP_CONNECTED 1
00066 #define RTSP_INIT 2
00067 #define RTSP_READY 4
00068 #define RTSP_PLAYING 8
00069 #define RTSP_RECORDING 16
00070
00071
00072 #define RTSP_OPTIONS 0x001
00073 #define RTSP_DESCRIBE 0x002
00074 #define RTSP_ANNOUNCE 0x004
00075 #define RTSP_SETUP 0x008
00076 #define RTSP_GET_PARAMETER 0x010
00077 #define RTSP_SET_PARAMETER 0x020
00078 #define RTSP_TEARDOWN 0x040
00079 #define RTSP_PLAY 0x080
00080 #define RTSP_RECORD 0x100
00081
00082
00083
00084
00085
00086
00087 static char *rtsp_get( rtsp_client_t *rtsp )
00088 {
00089 char *psz_buffer = malloc( BUF_SIZE );
00090 char *psz_string = NULL;
00091
00092 if( rtsp->pf_read_line( rtsp->p_userdata, psz_buffer, BUF_SIZE ) >= 0 )
00093 {
00094
00095 psz_string = strdup( psz_buffer );
00096 }
00097
00098 free( psz_buffer );
00099 return psz_string;
00100 }
00101
00102
00103
00104
00105
00106
00107 static int rtsp_put( rtsp_client_t *rtsp, const char *psz_string )
00108 {
00109 int i_buffer = strlen( psz_string );
00110 char *psz_buffer = malloc( i_buffer + 3 );
00111 int i_ret;
00112
00113 strcpy( psz_buffer, psz_string );
00114 psz_buffer[i_buffer] = '\r'; psz_buffer[i_buffer+1] = '\n';
00115 psz_buffer[i_buffer+2] = 0;
00116
00117 i_ret = rtsp->pf_write( rtsp->p_userdata, psz_buffer, i_buffer + 2 );
00118
00119 free( psz_buffer );
00120 return i_ret;
00121 }
00122
00123
00124
00125
00126
00127 static int rtsp_get_status_code( rtsp_client_t *rtsp, const char *psz_string )
00128 {
00129 char psz_buffer[4];
00130 int i_code = 0;
00131
00132 if( !strncmp( psz_string, "RTSP/1.0", sizeof("RTSP/1.0") - 1 ) )
00133 {
00134 memcpy( psz_buffer, psz_string + sizeof("RTSP/1.0"), 3 );
00135 psz_buffer[3] = 0;
00136 i_code = atoi( psz_buffer );
00137 }
00138 else if( !strncmp( psz_string, "SET_PARAMETER", 8 ) )
00139 {
00140 return RTSP_STATUS_SET_PARAMETER;
00141 }
00142
00143 if( i_code != 200 )
00144 {
00145 fprintf( stderr, "librtsp: server responds: '%s'\n", psz_string );
00146 }
00147
00148 return i_code;
00149 }
00150
00151
00152
00153
00154
00155 static int rtsp_send_request( rtsp_client_t *rtsp, const char *psz_type,
00156 const char *psz_what )
00157 {
00158 char **ppsz_payload = rtsp->p_private->scheduled;
00159 char *psz_buffer;
00160 int i_ret;
00161
00162 psz_buffer = malloc( strlen(psz_type) + strlen(psz_what) +
00163 sizeof("RTSP/1.0") + 2 );
00164
00165 sprintf( psz_buffer, "%s %s %s", psz_type, psz_what, "RTSP/1.0" );
00166 i_ret = rtsp_put( rtsp, psz_buffer );
00167 free( psz_buffer );
00168
00169 if( ppsz_payload )
00170 while( *ppsz_payload )
00171 {
00172 rtsp_put( rtsp, *ppsz_payload );
00173 ppsz_payload++;
00174 }
00175 rtsp_put( rtsp, "" );
00176 rtsp_unschedule_all( rtsp );
00177
00178 return i_ret;
00179 }
00180
00181
00182
00183
00184
00185 static void rtsp_schedule_standard( rtsp_client_t *rtsp )
00186 {
00187 char tmp[17];
00188
00189 sprintf( tmp, "Cseq: %u", rtsp->p_private->cseq);
00190 rtsp_schedule_field( rtsp, tmp );
00191
00192 if( rtsp->p_private->session )
00193 {
00194 char *buf;
00195 buf = malloc( strlen(rtsp->p_private->session) + 15 );
00196 sprintf( buf, "Session: %s", rtsp->p_private->session );
00197 rtsp_schedule_field( rtsp, buf );
00198 free( buf );
00199 }
00200 }
00201
00202
00203
00204
00205
00206 static int rtsp_get_answers( rtsp_client_t *rtsp )
00207 {
00208 char *answer = NULL;
00209 unsigned int answer_seq;
00210 char **answer_ptr = rtsp->p_private->answers;
00211 int code;
00212 int ans_count = 0;
00213
00214 answer = rtsp_get( rtsp );
00215 if( !answer ) return 0;
00216 code = rtsp_get_status_code( rtsp, answer );
00217 free( answer );
00218
00219 rtsp_free_answers( rtsp );
00220
00221 do {
00222
00223 answer = rtsp_get( rtsp );
00224 if( !answer ) return 0;
00225
00226 if( !strncasecmp( answer, "Cseq:", 5 ) )
00227 {
00228 sscanf( answer, "%*s %u", &answer_seq );
00229 if( rtsp->p_private->cseq != answer_seq )
00230 {
00231
00232
00233
00234 rtsp->p_private->cseq = answer_seq;
00235 }
00236 }
00237 if( !strncasecmp( answer, "Server:", 7 ) )
00238 {
00239 char *buf = malloc( strlen(answer) );
00240 sscanf( answer, "%*s %s", buf );
00241 if( rtsp->p_private->server ) free( rtsp->p_private->server );
00242 rtsp->p_private->server = buf;
00243 }
00244 if( !strncasecmp( answer, "Session:", 8 ) )
00245 {
00246 char *buf = malloc( strlen(answer) );
00247 sscanf( answer, "%*s %s", buf );
00248 if( rtsp->p_private->session )
00249 {
00250 if( strcmp( buf, rtsp->p_private->session ) )
00251 {
00252 fprintf( stderr,
00253 "rtsp: warning: setting NEW session: %s\n", buf );
00254 free( rtsp->p_private->session );
00255 rtsp->p_private->session = strdup( buf );
00256 }
00257 }
00258 else
00259 {
00260 fprintf( stderr, "setting session id to: %s\n", buf );
00261 rtsp->p_private->session = strdup( buf );
00262 }
00263 free( buf );
00264 }
00265
00266 *answer_ptr = answer;
00267 answer_ptr++;
00268 } while( (strlen(answer) != 0) && (++ans_count < MAX_FIELDS) );
00269
00270 rtsp->p_private->cseq++;
00271
00272 *answer_ptr = NULL;
00273 rtsp_schedule_standard( rtsp );
00274
00275 return code;
00276 }
00277
00278
00279
00280
00281
00282 int rtsp_send_ok( rtsp_client_t *rtsp )
00283 {
00284 char cseq[16];
00285
00286 rtsp_put( rtsp, "RTSP/1.0 200 OK" );
00287 sprintf( cseq, "CSeq: %u", rtsp->p_private->cseq );
00288 rtsp_put( rtsp, cseq );
00289 rtsp_put( rtsp, "" );
00290 return 0;
00291 }
00292
00293
00294
00295
00296
00297
00298 int rtsp_request_options( rtsp_client_t *rtsp, const char *what )
00299 {
00300 char *buf;
00301
00302 if( what ) buf = strdup(what);
00303 else
00304 {
00305 buf = malloc( strlen(rtsp->p_private->host) + 16 );
00306 sprintf( buf, "rtsp://%s:%i", rtsp->p_private->host,
00307 rtsp->p_private->port );
00308 }
00309 rtsp_send_request( rtsp, "OPTIONS", buf );
00310 free( buf );
00311
00312 return rtsp_get_answers( rtsp );
00313 }
00314
00315 int rtsp_request_describe( rtsp_client_t *rtsp, const char *what )
00316 {
00317 char *buf;
00318
00319 if( what )
00320 {
00321 buf = strdup(what);
00322 }
00323 else
00324 {
00325 buf = malloc( strlen(rtsp->p_private->host) +
00326 strlen(rtsp->p_private->path) + 16 );
00327 sprintf( buf, "rtsp://%s:%i/%s", rtsp->p_private->host,
00328 rtsp->p_private->port, rtsp->p_private->path );
00329 }
00330 rtsp_send_request( rtsp, "DESCRIBE", buf );
00331 free( buf );
00332
00333 return rtsp_get_answers( rtsp );
00334 }
00335
00336 int rtsp_request_setup( rtsp_client_t *rtsp, const char *what )
00337 {
00338 rtsp_send_request( rtsp, "SETUP", what );
00339 return rtsp_get_answers( rtsp );
00340 }
00341
00342 int rtsp_request_setparameter( rtsp_client_t *rtsp, const char *what )
00343 {
00344 char *buf;
00345
00346 if( what )
00347 {
00348 buf = strdup(what);
00349 }
00350 else
00351 {
00352 buf = malloc( strlen(rtsp->p_private->host) +
00353 strlen(rtsp->p_private->path) + 16 );
00354 sprintf( buf, "rtsp://%s:%i/%s", rtsp->p_private->host,
00355 rtsp->p_private->port, rtsp->p_private->path );
00356 }
00357
00358 rtsp_send_request( rtsp, "SET_PARAMETER", buf );
00359 free( buf );
00360
00361 return rtsp_get_answers( rtsp );
00362 }
00363
00364 int rtsp_request_play( rtsp_client_t *rtsp, const char *what )
00365 {
00366 char *buf;
00367
00368 if( what )
00369 {
00370 buf = strdup( what );
00371 }
00372 else
00373 {
00374 buf = malloc( strlen(rtsp->p_private->host) +
00375 strlen(rtsp->p_private->path) + 16 );
00376 sprintf( buf, "rtsp://%s:%i/%s", rtsp->p_private->host,
00377 rtsp->p_private->port, rtsp->p_private->path );
00378 }
00379
00380 rtsp_send_request( rtsp, "PLAY", buf );
00381 free( buf );
00382
00383 return rtsp_get_answers( rtsp );
00384 }
00385
00386 int rtsp_request_tearoff( rtsp_client_t *rtsp, const char *what )
00387 {
00388 rtsp_send_request( rtsp, "TEAROFF", what );
00389 return rtsp_get_answers( rtsp );
00390 }
00391
00392
00393
00394
00395
00396 int rtsp_read_data( rtsp_client_t *rtsp, char *buffer, unsigned int size )
00397 {
00398 int i, seq;
00399
00400 if( size >= 4 )
00401 {
00402 i = rtsp->pf_read( rtsp->p_userdata, buffer, 4 );
00403 if( i < 4 ) return i;
00404
00405 if( buffer[0]=='S' && buffer[1]=='E' && buffer[2]=='T' &&
00406 buffer[3]=='_' )
00407 {
00408 char *rest = rtsp_get( rtsp );
00409 if( !rest ) return -1;
00410
00411 seq = -1;
00412 do
00413 {
00414 free( rest );
00415 rest = rtsp_get( rtsp );
00416 if( !rest ) return -1;
00417
00418 if( !strncasecmp( rest, "Cseq:", 5 ) )
00419 sscanf( rest, "%*s %u", &seq );
00420 } while( *rest );
00421 free( rest );
00422
00423 if( seq < 0 )
00424 {
00425 fprintf(stderr, "warning: cseq not recognized!\n");
00426 seq = 1;
00427 }
00428
00429
00430 rtsp_put( rtsp, "RTSP/1.0 451 Parameter Not Understood" );
00431 rest = malloc(17);
00432 sprintf( rest,"CSeq: %u", seq );
00433 rtsp_put( rtsp, rest );
00434 rtsp_put( rtsp, "" );
00435 free( rest );
00436 i = rtsp->pf_read( rtsp->p_userdata, buffer, size );
00437 }
00438 else
00439 {
00440 i = rtsp->pf_read( rtsp->p_userdata, buffer + 4, size - 4 );
00441 i += 4;
00442 }
00443 }
00444 else i = rtsp->pf_read( rtsp->p_userdata, buffer, size );
00445
00446
00447
00448 return i;
00449 }
00450
00451
00452
00453
00454
00455 int rtsp_connect( rtsp_client_t *rtsp, const char *psz_mrl,
00456 const char *psz_user_agent )
00457 {
00458 rtsp_t *s;
00459 char *mrl_ptr;
00460 char *slash, *colon;
00461 unsigned int hostend, pathbegin, i;
00462
00463 if( !psz_mrl ) return -1;
00464 s = malloc( sizeof(rtsp_t) );
00465 rtsp->p_private = s;
00466
00467 if( !strncmp( psz_mrl, "rtsp://", 7 ) ) psz_mrl += 7;
00468 mrl_ptr = strdup( psz_mrl );
00469
00470 for( i=0; i<MAX_FIELDS; i++ )
00471 {
00472 s->answers[i]=NULL;
00473 s->scheduled[i]=NULL;
00474 }
00475
00476 s->host = NULL;
00477 s->port = 554;
00478 s->path = NULL;
00479 s->mrl = strdup(psz_mrl);
00480
00481 s->server = NULL;
00482 s->server_state = 0;
00483 s->server_caps = 0;
00484
00485 s->cseq = 0;
00486 s->session = NULL;
00487
00488 if( psz_user_agent ) s->user_agent = strdup( psz_user_agent );
00489 else s->user_agent = strdup( "User-Agent: RealMedia Player Version "
00490 "6.0.9.1235 (linux-2.0-libc6-i386-gcc2.95)" );
00491
00492 slash = strchr( mrl_ptr, '/' );
00493 colon = strchr( mrl_ptr, ':' );
00494
00495 if( !slash ) slash = mrl_ptr + strlen(mrl_ptr) + 1;
00496 if( !colon ) colon = slash;
00497 if( colon > slash ) colon = slash;
00498
00499 pathbegin = slash - mrl_ptr;
00500 hostend = colon - mrl_ptr;
00501
00502 s->host = malloc(hostend+1);
00503 strncpy( s->host, mrl_ptr, hostend );
00504 s->host[hostend] = 0;
00505
00506 if( pathbegin < strlen(mrl_ptr) ) s->path = strdup(mrl_ptr+pathbegin+1);
00507 if( colon != slash )
00508 {
00509 char buffer[pathbegin-hostend];
00510
00511 strncpy( buffer, mrl_ptr+hostend+1, pathbegin-hostend-1 );
00512 buffer[pathbegin-hostend-1] = 0;
00513 s->port = atoi(buffer);
00514 if( s->port < 0 || s->port > 65535 ) s->port = 554;
00515 }
00516
00517 free( mrl_ptr );
00518 fprintf( stderr, "got mrl: %s %i %s\n", s->host, s->port, s->path );
00519
00520 s->s = rtsp->pf_connect( rtsp->p_userdata, s->host, s->port );
00521
00522 if( s->s < 0 )
00523 {
00524 fprintf(stderr, "rtsp: failed to connect to '%s'\n", s->host);
00525 rtsp_close( rtsp );
00526 return -1;
00527 }
00528
00529 s->server_state = RTSP_CONNECTED;
00530
00531
00532 rtsp_schedule_field( rtsp, "CSeq: 1");
00533 rtsp_schedule_field( rtsp, s->user_agent);
00534 rtsp_schedule_field( rtsp, "ClientChallenge: "
00535 "9e26d33f2984236010ef6253fb1887f7");
00536 rtsp_schedule_field( rtsp, "PlayerStarttime: [28/03/2003:22:50:23 00:00]");
00537 rtsp_schedule_field( rtsp, "CompanyID: KnKV4M4I/B2FjJ1TToLycw==" );
00538 rtsp_schedule_field( rtsp, "GUID: 00000000-0000-0000-0000-000000000000" );
00539 rtsp_schedule_field( rtsp, "RegionData: 0" );
00540 rtsp_schedule_field( rtsp, "ClientID: "
00541 "Linux_2.4_6.0.9.1235_play32_RN01_EN_586" );
00542
00543 rtsp_request_options( rtsp, NULL );
00544
00545 return 0;
00546 }
00547
00548
00549
00550
00551
00552 void rtsp_close( rtsp_client_t *rtsp )
00553 {
00554 if( rtsp->p_private->server_state )
00555 {
00556
00557 rtsp->pf_disconnect( rtsp->p_userdata );
00558 }
00559
00560 if( rtsp->p_private->path ) free( rtsp->p_private->path );
00561 if( rtsp->p_private->host ) free( rtsp->p_private->host );
00562 if( rtsp->p_private->mrl ) free( rtsp->p_private->mrl );
00563 if( rtsp->p_private->session ) free( rtsp->p_private->session );
00564 if( rtsp->p_private->user_agent ) free( rtsp->p_private->user_agent );
00565 if( rtsp->p_private->server ) free( rtsp->p_private->server );
00566 rtsp_free_answers( rtsp );
00567 rtsp_unschedule_all( rtsp );
00568 free( rtsp->p_private );
00569 }
00570
00571
00572
00573
00574
00575
00576 char *rtsp_search_answers( rtsp_client_t *rtsp, const char *tag )
00577 {
00578 char **answer;
00579 char *ptr;
00580
00581 if( !rtsp->p_private->answers ) return NULL;
00582 answer = rtsp->p_private->answers;
00583
00584 while(*answer)
00585 {
00586 if( !strncasecmp( *answer, tag, strlen(tag) ) )
00587 {
00588 ptr = strchr(*answer, ':');
00589 ptr++;
00590 while( *ptr == ' ' ) ptr++;
00591 return ptr;
00592 }
00593 answer++;
00594 }
00595
00596 return NULL;
00597 }
00598
00599
00600
00601
00602
00603 void rtsp_set_session( rtsp_client_t *rtsp, const char *id )
00604 {
00605 if( rtsp->p_private->session ) free( rtsp->p_private->session );
00606 rtsp->p_private->session = strdup(id);
00607 }
00608
00609 char *rtsp_get_session( rtsp_client_t *rtsp )
00610 {
00611 return rtsp->p_private->session;
00612 }
00613
00614 char *rtsp_get_mrl( rtsp_client_t *rtsp )
00615 {
00616 return rtsp->p_private->mrl;
00617 }
00618
00619
00620
00621
00622
00623 void rtsp_schedule_field( rtsp_client_t *rtsp, const char *string )
00624 {
00625 int i = 0;
00626
00627 if( !string ) return;
00628
00629 while( rtsp->p_private->scheduled[i] ) i++;
00630
00631 rtsp->p_private->scheduled[i] = strdup(string);
00632 }
00633
00634
00635
00636
00637
00638 void rtsp_unschedule_field( rtsp_client_t *rtsp, const char *string )
00639 {
00640 char **ptr = rtsp->p_private->scheduled;
00641
00642 if( !string ) return;
00643
00644 while( *ptr )
00645 {
00646 if( !strncmp(*ptr, string, strlen(string)) ) break;
00647 }
00648 if( *ptr ) free( *ptr );
00649 ptr++;
00650 do
00651 {
00652 *(ptr-1) = *ptr;
00653 } while( *ptr );
00654 }
00655
00656
00657
00658
00659
00660 void rtsp_unschedule_all( rtsp_client_t *rtsp )
00661 {
00662 char **ptr;
00663
00664 if( !rtsp->p_private->scheduled ) return;
00665 ptr = rtsp->p_private->scheduled;
00666
00667 while( *ptr )
00668 {
00669 free( *ptr );
00670 *ptr = NULL;
00671 ptr++;
00672 }
00673 }
00674
00675
00676
00677
00678 void rtsp_free_answers( rtsp_client_t *rtsp )
00679 {
00680 char **answer;
00681
00682 if( !rtsp->p_private->answers ) return;
00683 answer = rtsp->p_private->answers;
00684
00685 while( *answer )
00686 {
00687 free( *answer );
00688 *answer = NULL;
00689 answer++;
00690 }
00691 }