#include "rtsp-client.h" #include "rtsp-client-internal.h" #include "rtp-profile.h" #include "sdp.h" #include #include #include #if defined(OS_WINDOWS) #define strncasecmp _strnicmp #endif struct rtsp_client_t* rtsp_client_create(const char* uri, const char* usr, const char* pwd, const struct rtsp_client_handler_t *handler, void* param) { struct rtsp_client_t *rtsp; rtsp = (struct rtsp_client_t*)calloc(1, sizeof(*rtsp)); if(NULL == rtsp) return NULL; snprintf(rtsp->uri, sizeof(rtsp->uri) - 1, "%s", uri); snprintf(rtsp->usr, sizeof(rtsp->usr) - 1, "%s", usr ? usr : ""); snprintf(rtsp->pwd, sizeof(rtsp->pwd) - 1, "%s", pwd ? pwd : ""); rtsp->parser = http_parser_create(HTTP_PARSER_RESPONSE, NULL, NULL); memcpy(&rtsp->handler, handler, sizeof(rtsp->handler)); rtsp->rtp.onrtp = rtsp->handler.onrtp; rtsp->rtp.param = param; rtsp->state = RTSP_INIT; rtsp->param = param; rtsp->cseq = 1; rtsp->auth_failed = 0; return rtsp; } void rtsp_client_destroy(struct rtsp_client_t *rtsp) { if (rtsp->parser) { http_parser_destroy(rtsp->parser); rtsp->parser = NULL; } if (rtsp->rtp.data) { assert(rtsp->rtp.capacity > 0); free(rtsp->rtp.data); rtsp->rtp.data = NULL; rtsp->rtp.capacity = 0; } free(rtsp); } static int rtsp_client_handle(struct rtsp_client_t* rtsp, http_parser_t* parser) { switch (rtsp->state) { case RTSP_DESCRIBE: return rtsp_client_describe_onreply(rtsp, parser); case RTSP_SETUP: return rtsp_client_setup_onreply(rtsp, parser); case RTSP_PLAY: return rtsp_client_play_onreply(rtsp, parser); case RTSP_PAUSE: return rtsp_client_pause_onreply(rtsp, parser); case RTSP_TEARDWON: return rtsp_client_teardown_onreply(rtsp, parser); case RTSP_OPTIONS: return rtsp_client_options_onreply(rtsp, parser); case RTSP_GET_PARAMETER: return rtsp_client_get_parameter_onreply(rtsp, parser); case RTSP_SET_PARAMETER: return rtsp_client_set_parameter_onreply(rtsp, parser); case RTSP_ANNOUNCE: return rtsp_client_announce_onreply(rtsp, parser); case RTSP_RECORD: return rtsp_client_record_onreply(rtsp, parser); default: assert(0); return -1; } } static int rtsp_check_response_line(const char* data, size_t bytes) { const char* line = "RTSP/1.0 "; assert(bytes > 0); if (bytes >= 9) bytes = 9; return strncasecmp(line, data, 9); } int rtsp_client_input(struct rtsp_client_t *rtsp, const void* data, size_t bytes) { int r; size_t remain; const uint8_t* p, *end; r = 0; p = (const uint8_t*)data; end = p + bytes; do { if(rtsp->parser_need_more_data || 0 == rtsp_check_response_line((const char*)p, (size_t)(end - p))) { // TODO: server->client Announce (update sdp) remain = (size_t)(end - p); r = http_parser_input(rtsp->parser, p, &remain); rtsp->parser_need_more_data = r; assert(r <= 2); // 1-need more data if (0 == r) { r = rtsp_client_handle(rtsp, rtsp->parser); http_parser_clear(rtsp->parser); // reset parser assert((size_t)remain < bytes); } p = end - remain; } else { //if (0 == rtsp->parser_need_more_data && (*p == '$' || 0 != rtsp->rtp.state)) p = rtp_over_rtsp(&rtsp->rtp, p, end); } } while (p < end && r >= 0); assert(r <= 2); return r >= 0 ? 0 : r; } const char* rtsp_client_get_header(struct rtsp_client_t* rtsp, const char* name) { return http_get_header_by_name(rtsp->parser, name); } int rtsp_client_media_count(struct rtsp_client_t *rtsp) { return rtsp->media_count; } const struct rtsp_header_transport_t* rtsp_client_get_media_transport(struct rtsp_client_t *rtsp, int media) { if(media < 0 || media >= rtsp->media_count) return NULL; return rtsp->transport + media; } const struct rtsp_media_t* rtsp_client_get_media(struct rtsp_client_t* rtsp, int media) { if (media < 0 || media >= rtsp->media_count) return NULL; return rtsp->media + media; } const char* rtsp_client_get_media_encoding(struct rtsp_client_t *rtsp, int media) { if (media < 0 || media >= rtsp->media_count) return NULL; return rtsp->media[media].avformats[0].encoding; } const char* rtsp_client_get_media_fmtp(struct rtsp_client_t *rtsp, int media) { if (media < 0 || media >= rtsp->media_count) return NULL; return rtsp->media[media].avformats[0].fmtp; } int rtsp_client_get_media_payload(struct rtsp_client_t *rtsp, int media) { if (media < 0 || media >= rtsp->media_count) return -1; return rtsp->media[media].avformats[0].fmt; } int rtsp_client_get_media_rate(struct rtsp_client_t *rtsp, int media) { int rate; if (media < 0 || media >= rtsp->media_count) return -1; rate = rtsp->media[media].avformats[0].rate; if (0 == rate) { const struct rtp_profile_t* profile; profile = rtp_profile_find(rtsp->media[media].avformats[0].fmt); rate = profile ? profile->frequency : 0; } return rate; } int rtsp_client_get_media_type(struct rtsp_client_t* rtsp, int media) { if (media < 0 || media >= rtsp->media_count) return -1; return sdp_option_media_from(rtsp->media[media].media); }