rmff_header_t *real_setup_and_get_header(rtsp_t *rtsp_session, uint32_t bandwidth, char *username, char *password) { char *description=NULL; char *session_id=NULL; rmff_header_t *h = NULL; char *challenge1 = NULL; char challenge2[41]; char checksum[9]; char *subscribe = NULL; char *buf = xbuffer_init(256); char *mrl=rtsp_get_mrl(rtsp_session); unsigned int size; int status; uint32_t maxbandwidth = bandwidth; char* authfield = NULL; int i; /* get challenge */ challenge1=rtsp_search_answers(rtsp_session,"RealChallenge1"); if (!challenge1) goto out; challenge1=strdup(challenge1); #ifdef LOG printf("real: Challenge1: %s\n", challenge1); #endif /* set a reasonable default to get the best stream, unless bandwidth given */ if (!bandwidth) bandwidth = 10485800; /* request stream description */ rtsp_send_describe: rtsp_schedule_field(rtsp_session, "Accept: application/sdp"); sprintf(buf, "Bandwidth: %u", bandwidth); rtsp_schedule_field(rtsp_session, buf); rtsp_schedule_field(rtsp_session, "GUID: 00000000-0000-0000-0000-000000000000"); rtsp_schedule_field(rtsp_session, "RegionData: 0"); rtsp_schedule_field(rtsp_session, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586"); rtsp_schedule_field(rtsp_session, "SupportsMaximumASMBandwidth: 1"); rtsp_schedule_field(rtsp_session, "Language: en-US"); rtsp_schedule_field(rtsp_session, "Require: com.real.retain-entity-for-setup"); if(authfield) rtsp_schedule_field(rtsp_session, authfield); status=rtsp_request_describe(rtsp_session,NULL); if (status == 401) { int authlen, b64_authlen; char *authreq; char* authstr = NULL; if (authfield) { mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: authorization failed, check your credentials\n"); goto autherr; } if (!(authreq = rtsp_search_answers(rtsp_session,"WWW-Authenticate"))) { mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: 401 but no auth request, aborting\n"); goto autherr; } if (!username) { mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: auth required but no username supplied\n"); goto autherr; } if (!strstr(authreq, "Basic")) { mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: authenticator not supported (%s)\n", authreq); goto autherr; } authlen = strlen(username) + (password ? strlen(password) : 0) + 2; authstr = malloc(authlen); sprintf(authstr, "%s:%s", username, password ? password : ""); authfield = malloc(authlen*2+22); strcpy(authfield, "Authorization: Basic "); b64_authlen = base64_encode(authstr, authlen, authfield+21, authlen*2); free(authstr); if (b64_authlen < 0) { mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: base64 output overflow, this should never happen\n"); goto autherr; } authfield[b64_authlen+21] = 0; goto rtsp_send_describe; } autherr: if (authfield) free(authfield); if ( status<200 || status>299 ) { char *alert=rtsp_search_answers(rtsp_session,"Alert"); if (alert) { mp_msg(MSGT_STREAM, MSGL_WARN, "realrtsp: got message from server:\n%s\n", alert); } rtsp_send_ok(rtsp_session); goto out; } /* receive description */ size=0; if (!rtsp_search_answers(rtsp_session,"Content-length")) mp_msg(MSGT_STREAM, MSGL_WARN, "real: got no Content-length!\n"); else size=atoi(rtsp_search_answers(rtsp_session,"Content-length")); // as size is unsigned this also catches the case (size < 0) if (size > MAX_DESC_BUF) { mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: Content-length for description too big (> %uMB)!\n", MAX_DESC_BUF/(1024*1024) ); goto out; } if (!rtsp_search_answers(rtsp_session,"ETag")) mp_msg(MSGT_STREAM, MSGL_WARN, "realrtsp: got no ETag!\n"); else session_id=strdup(rtsp_search_answers(rtsp_session,"ETag")); #ifdef LOG printf("real: Stream description size: %u\n", size); #endif description=malloc(size+1); if( rtsp_read_data(rtsp_session, description, size) <= 0) { goto out; } description[size]=0; /* parse sdp (sdpplin) and create a header and a subscribe string */ subscribe = xbuffer_init(256); strcpy(subscribe, "Subscribe: "); h=real_parse_sdp(description, &subscribe, bandwidth); if (!h) { goto out; } rmff_fix_header(h); #ifdef LOG printf("Title: %s\nCopyright: %s\nAuthor: %s\nStreams: %i\n", h->cont->title, h->cont->copyright, h->cont->author, h->prop->num_streams); #endif /* setup our streams */ real_calc_response_and_checksum (challenge2, checksum, challenge1); buf = xbuffer_ensure_size(buf, strlen(challenge2) + strlen(checksum) + 32); sprintf(buf, "RealChallenge2: %s, sd=%s", challenge2, checksum); rtsp_schedule_field(rtsp_session, buf); buf = xbuffer_ensure_size(buf, strlen(session_id) + 32); sprintf(buf, "If-Match: %s", session_id); rtsp_schedule_field(rtsp_session, buf); rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play"); buf = xbuffer_ensure_size(buf, strlen(mrl) + 32); sprintf(buf, "%s/streamid=0", mrl); rtsp_request_setup(rtsp_session,buf,NULL); /* Do setup for all the other streams we subscribed to */ for (i = 1; i < h->prop->num_streams; i++) { rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play"); buf = xbuffer_ensure_size(buf, strlen(session_id) + 32); sprintf(buf, "If-Match: %s", session_id); rtsp_schedule_field(rtsp_session, buf); buf = xbuffer_ensure_size(buf, strlen(mrl) + 32); sprintf(buf, "%s/streamid=%d", mrl, i); rtsp_request_setup(rtsp_session,buf,NULL); } /* set stream parameter (bandwidth) with our subscribe string */ rtsp_schedule_field(rtsp_session, subscribe); rtsp_request_setparameter(rtsp_session,NULL); /* set delivery bandwidth */ if (maxbandwidth) { sprintf(buf, "SetDeliveryBandwidth: Bandwidth=%u;BackOff=0", maxbandwidth); rtsp_schedule_field(rtsp_session, buf); rtsp_request_setparameter(rtsp_session,NULL); } { int s_ss = 0, s_ms = 0, e_ss = 0, e_ms = 0; char *str; if ((str = rtsp_get_param(rtsp_session, "start"))) { convert_timestamp(str, &s_ss, &s_ms); free(str); } if ((str = rtsp_get_param(rtsp_session, "end"))) { convert_timestamp(str, &e_ss, &e_ms); free(str); } str = buf + sprintf(buf, s_ms ? "%s%d.%d-" : "%s%d-", "Range: npt=", s_ss, s_ms); if (e_ss || e_ms) sprintf(str, e_ms ? "%d.%d" : "%d", e_ss, e_ms); } rtsp_schedule_field(rtsp_session, buf); /* and finally send a play request */ rtsp_request_play(rtsp_session,NULL); out: subscribe = xbuffer_free(subscribe); buf = xbuffer_free(buf); free(description); free(session_id); free(challenge1); return h; }
/***************************************************************************** * Open: open the rtsp connection *****************************************************************************/ static int Open( vlc_object_t *p_this ) { access_t *p_access = (access_t *)p_this; access_sys_t *p_sys; char* psz_server = NULL; int i_result; if( !p_access->psz_access || ( strncmp( p_access->psz_access, "rtsp", 4 ) && strncmp( p_access->psz_access, "pnm", 3 ) && strncmp( p_access->psz_access, "realrtsp", 8 ) )) { return VLC_EGENERIC; } p_access->pf_read = NULL; p_access->pf_block = BlockRead; p_access->pf_seek = Seek; p_access->pf_control = Control; p_access->info.i_pos = 0; p_access->info.b_eof = false; p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; p_sys->p_rtsp = malloc( sizeof( rtsp_client_t) ); if( !p_sys->p_rtsp ) { free( p_sys ); return VLC_ENOMEM; } p_sys->p_header = NULL; p_sys->p_rtsp->p_userdata = p_access; p_sys->p_rtsp->pf_connect = RtspConnect; p_sys->p_rtsp->pf_disconnect = RtspDisconnect; p_sys->p_rtsp->pf_read = RtspRead; p_sys->p_rtsp->pf_read_line = RtspReadLine; p_sys->p_rtsp->pf_write = RtspWrite; i_result = rtsp_connect( p_sys->p_rtsp, p_access->psz_location, 0 ); if( i_result ) { msg_Dbg( p_access, "could not connect to: %s", p_access->psz_location ); free( p_sys->p_rtsp ); p_sys->p_rtsp = NULL; goto error; } msg_Dbg( p_access, "rtsp connected" ); /* looking for server type */ if( rtsp_search_answers( p_sys->p_rtsp, "Server" ) ) psz_server = strdup( rtsp_search_answers( p_sys->p_rtsp, "Server" ) ); else { if( rtsp_search_answers( p_sys->p_rtsp, "RealChallenge1" ) ) psz_server = strdup("Real"); else psz_server = strdup("unknown"); } if( strstr( psz_server, "Real" ) || strstr( psz_server, "Helix" ) ) { uint32_t bandwidth = 10485800; rmff_header_t *h; msg_Dbg( p_access, "found a real/helix rtsp server" ); if( !(h = real_setup_and_get_header( p_sys->p_rtsp, bandwidth )) ) { /* Check if we got a redirect */ if( rtsp_search_answers( p_sys->p_rtsp, "Location" ) ) { msg_Dbg( p_access, "redirect: %s", rtsp_search_answers(p_sys->p_rtsp, "Location") ); msg_Warn( p_access, "redirect not supported" ); goto error; } msg_Err( p_access, "rtsp session can not be established" ); dialog_Fatal( p_access, _("Session failed"), "%s", _("The requested RTSP session could not be established.") ); goto error; } p_sys->p_header = block_Alloc( 4096 ); p_sys->p_header->i_buffer = rmff_dump_header( h, (char *)p_sys->p_header->p_buffer, 1024 ); rmff_free_header( h ); } else { msg_Warn( p_access, "only real/helix rtsp servers supported for now" ); goto error; } free( psz_server ); return VLC_SUCCESS; error: free( psz_server ); Close( p_this ); return VLC_EGENERIC; }
rtsp_session_t *rtsp_session_start(xine_stream_t *stream, char *mrl) { rtsp_session_t *rtsp_session = calloc(1, sizeof(rtsp_session_t)); xine_t *xine = stream->xine; char *server; char *mrl_line=strdup(mrl); rmff_header_t *h; int bandwidth_id; uint32_t bandwidth; bandwidth_id = xine->config->register_enum(xine->config, "media.network.bandwidth", 10, rtsp_bandwidth_strs, _("network bandwidth"), _("Specify the bandwidth of your internet connection here. " "This will be used when streaming servers offer different versions " "with different bandwidth requirements of the same stream."), 0, NULL, NULL); bandwidth = rtsp_bandwidths[bandwidth_id]; rtsp_session->recv = xine_buffer_init(BUF_SIZE); connect: /* connect to server */ rtsp_session->s=rtsp_connect(stream, mrl_line, NULL); if (!rtsp_session->s) { xprintf(stream->xine, XINE_VERBOSITY_LOG, _("rtsp_session: failed to connect to server %s\n"), mrl_line); xine_buffer_free(rtsp_session->recv); free(rtsp_session); return NULL; } /* looking for server type */ if (rtsp_search_answers(rtsp_session->s,"Server")) server=strdup(rtsp_search_answers(rtsp_session->s,"Server")); else { if (rtsp_search_answers(rtsp_session->s,"RealChallenge1")) server=strdup("Real"); else server=strdup("unknown"); } if (strstr(server,"Real") || strstr(server,"Helix")) { /* we are talking to a real server ... */ h=real_setup_and_get_header(rtsp_session->s, bandwidth); if (!h) { /* got an redirect? */ if (rtsp_search_answers(rtsp_session->s, "Location")) { free(mrl_line); mrl_line=strdup(rtsp_search_answers(rtsp_session->s, "Location")); xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "rtsp_session: redirected to %s\n", mrl_line); rtsp_close(rtsp_session->s); free(server); goto connect; /* *shudder* i made a design mistake somewhere */ } else { xprintf(stream->xine, XINE_VERBOSITY_LOG, _("rtsp_session: session can not be established.\n")); rtsp_close(rtsp_session->s); xine_buffer_free(rtsp_session->recv); free(rtsp_session); return NULL; } } rtsp_session->header_left = rtsp_session->header_len = rmff_dump_header(h,rtsp_session->header,HEADER_SIZE); if (rtsp_session->header_len < 0) { xprintf (stream->xine, XINE_VERBOSITY_LOG, _("rtsp_session: rtsp server returned overly-large headers, session can not be established.\n")); goto session_abort; } xine_buffer_copyin(rtsp_session->recv, 0, rtsp_session->header, rtsp_session->header_len); rtsp_session->recv_size = rtsp_session->header_len; rtsp_session->recv_read = 0; } else { xprintf(stream->xine, XINE_VERBOSITY_LOG, _("rtsp_session: rtsp server type '%s' not supported yet. sorry.\n"), server); session_abort: rtsp_close(rtsp_session->s); free(server); xine_buffer_free(rtsp_session->recv); free(rtsp_session); return NULL; } free(server); return rtsp_session; }