📄 rtsp.c
字号:
static int rtsp_udp_setup( struct session *s, int track, struct req *req, char *t ){ char *p, *end, trans[128]; int cport, server_port; if( ! ( p = strstr( t, "client_port" ) ) || *(p + 11) != '=' ) return -1; cport = strtol( p + 12, &end, 10 ); if( end == p + 12 ) return -1; spook_log( SL_DEBUG, "client requested UDP port %d", cport ); if( connect_udp_endpoint( s->ep[track], req->conn->client_addr.sin_addr, cport, &server_port ) < 0 ) return -1; spook_log( SL_VERBOSE, "our port is %d, client port is %d", server_port, cport ); sprintf( trans, "RTP/AVP;unicast;client_port=%d-%d;server_port=%d-%d", cport, cport + 1, server_port, server_port + 1 ); add_header( req->resp, "Transport", trans ); return 0;}static int rtsp_interleave_setup( struct session *s, int track, struct req *req, char *t ){ struct rtsp_conn *rc = (struct rtsp_conn *)req->conn->proto_state; char *p, *end, trans[128]; int rtp_chan = -1, rtcp_chan = -1, i; if( ( p = strstr( t, "interleaved" ) ) ) { if( *(p + 11) != '=' ) return -1; rtp_chan = strtol( p + 12, &end, 10 ); rtcp_chan = rtp_chan + 1; // XXX make better parser if( end == p + 12 ) return -1; if( rtp_chan < 0 || rtcp_chan < 0 || rtp_chan >= MAX_INTERLEAVE_CHANNELS || rtcp_chan >= MAX_INTERLEAVE_CHANNELS ) return -1; spook_log( SL_VERBOSE, "requested interleave channels %d-%d", rtp_chan, rtcp_chan ); if( rc && ( rc->ichan[rtp_chan].ep || rc->ichan[rtcp_chan].ep ) ) return -1; } else { spook_log( SL_VERBOSE, "requested any interleave channel" ); if( rc ) { for( i = 0; i < MAX_INTERLEAVE_CHANNELS; i += 2 ) if( ! rc->ichan[i].ep && ! rc->ichan[i + 1].ep ) break; if( i >= MAX_INTERLEAVE_CHANNELS ) return -1; rtp_chan = i; rtcp_chan = i + 1; } else { rtp_chan = 0; rtcp_chan = 1; } } if( ! rc ) { rc = (struct rtsp_conn *)malloc( sizeof( struct rtsp_conn ) ); if( ! rc ) { spook_log( SL_ERR, "out of memory on malloc rtsp_conn" ); return -1; } for( i = 0; i < MAX_INTERLEAVE_CHANNELS; ++i ) rc->ichan[i].ep = NULL; req->conn->proto_state = rc; } rc->ichan[rtp_chan].ep = s->ep[track]; rc->ichan[rtp_chan].rtcp = 0; rc->ichan[rtcp_chan].ep = s->ep[track]; rc->ichan[rtcp_chan].rtcp = 1; connect_interleaved_endpoint( s->ep[track], req->conn, rtp_chan, rtcp_chan ); sprintf( trans, "RTP/AVP/TCP;unicast;interleaved=%d-%d", rtp_chan, rtcp_chan ); add_header( req->resp, "Transport", trans ); return 0;}static int handle_SETUP( struct req *req ){ char *t, *sh, path[256]; int track, ret; struct session *s; struct rtsp_session *rs = NULL; struct rtsp_location *loc; if( ! ( loc = find_rtsp_location( req->req->sl.req.uri, path, &track ) ) || track < 0 || track >= MAX_TRACKS ) { rtsp_send_error( req, 404, "Not Found" ); return 0; } if( loc->realm[0] && rtsp_verify_auth( req, loc->realm, loc->username, loc->password ) < 0 ) return 0; if( ! ( t = get_header( req->req, "Transport" ) ) ) { // XXX better error reply rtsp_send_error( req, 461, "Unspecified Transport" ); return 0; } if( ! ( sh = get_header( req->req, "Session" ) ) ) { if( ! ( s = loc->open( path, loc->private ) ) ) { rtsp_send_error( req, 404, "Not Found" ); return 0; } sprintf( s->addr, "IP4 %s", inet_ntoa( req->conn->client_addr.sin_addr ) ); } else if( ! ( rs = get_session( sh ) ) ) { rtsp_send_error( req, 454, "Session Not Found" ); return 0; } else s = rs->sess; if( s->ep[track] ) { // XXX better error reply rtsp_send_error( req, 461, "Unsupported Transport" ); return 0; } if( s->setup( s, track ) < 0 ) { rtsp_send_error( req, 404, "Not Found" ); if( ! rs ) s->teardown( s, NULL ); return 0; } spook_log( SL_DEBUG, "setting up RTP (%s)", t ); rtsp_create_reply( req, 200, "OK" ); if( ! strncasecmp( t, "RTP/AVP/TCP", 11 ) ) ret = rtsp_interleave_setup( s, track, req, t ); else if( ( ! strncasecmp( t, "RTP/AVP", 7 ) && t[7] != '/' ) || ! strncasecmp( t, "RTP/AVP/UDP", 11 ) ) ret = rtsp_udp_setup( s, track, req, t ); else ret = -1; if( ret < 0 ) { free_pmsg( req->resp ); rtsp_send_error( req, 461, "Unsupported Transport" ); s->teardown( s, s->ep[track] ); } else { if( ! rs ) rs = new_rtsp_session( s ); add_header( req->resp, "Session", rs->id ); log_request( req, 200, 0 ); tcp_send_pmsg( req->conn, req->resp, -1 ); } return 0;}static int handle_PLAY( struct req *req ){ struct rtsp_session *rs; double start; int have_start = 0, i, p, ret; char *range, hdr[512]; if( ! ( rs = get_session( get_header( req->req, "Session" ) ) ) ) { rtsp_send_error( req, 454, "Session Not Found" ); return 0; } range = get_header( req->req, "Range" ); if( range && sscanf( range, "npt=%lf-", &start ) == 1 ) { have_start = 1; spook_log( SL_VERBOSE, "starting streaming for session %s at position %.4f", rs->id, start ); } else spook_log( SL_VERBOSE, "starting streaming for session %s", rs->id ); rs->sess->play( rs->sess, have_start ? &start : NULL ); rtsp_create_reply( req, 200, "OK" ); add_header( req->resp, "Session", rs->id ); if( have_start && start >= 0 ) { spook_log( SL_DEBUG, "backend seeked to %.4f", start ); sprintf( hdr, "npt=%.4f-", start ); add_header( req->resp, "Range", hdr ); p = 0; for( i = 0; i < MAX_TRACKS; ++i ) { if( ! rs->sess->ep[i] ) continue; ret = snprintf( hdr + p, sizeof( hdr ) - p, "url=%s/track%d;seq=%d;rtptime=%u,", req->req->sl.req.uri, i, rs->sess->ep[i]->seqnum, rs->sess->ep[i]->last_timestamp ); if( ret >= sizeof( hdr ) - p ) { p = -1; break; } p += ret; } if( p > 0 ) { hdr[p - 1] = 0; /* Kill last comma */ add_header( req->resp, "RTP-Info", hdr ); } } log_request( req, 200, 0 ); tcp_send_pmsg( req->conn, req->resp, -1 ); return 0;}static int handle_PAUSE( struct req *req ){ struct rtsp_session *rs; if( ! ( rs = get_session( get_header( req->req, "Session" ) ) ) ) { rtsp_send_error( req, 454, "Session Not Found" ); return 0; } if( ! rs->sess->pause ) { rtsp_send_error( req, 501, "Not Implemented" ); return 0; } spook_log( SL_VERBOSE, "pausing session %s", rs->id ); rs->sess->pause( rs->sess ); rtsp_create_reply( req, 200, "OK" ); add_header( req->resp, "Session", rs->id ); log_request( req, 200, 0 ); tcp_send_pmsg( req->conn, req->resp, -1 ); return 0;}static int handle_TEARDOWN( struct req *req ){ struct rtsp_location *loc; struct rtsp_session *rs; int track; if( ! ( loc = find_rtsp_location( req->req->sl.req.uri, NULL, &track ) ) || track >= MAX_TRACKS ) { rtsp_send_error( req, 404, "Not Found" ); return 0; } if( ! ( rs = get_session( get_header( req->req, "Session" ) ) ) ) { rtsp_send_error( req, 454, "Session Not Found" ); return 0; } spook_log( SL_VERBOSE, "tearing down %s in session %s", req->req->sl.req.uri, rs->id ); rtsp_create_reply( req, 200, "OK" ); add_header( req->resp, "Session", rs->id ); /* This might destroy the session, so do it after creating the reply */ rs->sess->teardown( rs->sess, track < 0 ? NULL : rs->sess->ep[track] ); log_request( req, 200, 0 ); tcp_send_pmsg( req->conn, req->resp, -1 ); return 0;}static int handle_unknown( struct req *req ){ rtsp_send_error( req, 501, "Not Implemented" ); return 0;}int rtsp_handle_msg( struct req *req ){ int ret; if( ! strcasecmp( req->req->sl.req.method, "OPTIONS" ) ) ret = handle_OPTIONS( req ); else if( ! strcasecmp( req->req->sl.req.method, "DESCRIBE" ) ) ret = handle_DESCRIBE( req ); else if( ! strcasecmp( req->req->sl.req.method, "SETUP" ) ) ret = handle_SETUP( req ); else if( ! strcasecmp( req->req->sl.req.method, "PLAY" ) ) ret = handle_PLAY( req ); else if( ! strcasecmp( req->req->sl.req.method, "PAUSE" ) ) ret = handle_PAUSE( req ); else if( ! strcasecmp( req->req->sl.req.method, "TEARDOWN" ) ) ret = handle_TEARDOWN( req ); else ret = handle_unknown( req ); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -