190 lines
4.9 KiB
C++
190 lines
4.9 KiB
C++
#include "rtsp-client.h"
|
|
#include "rtsp-client-internal.h"
|
|
#include "rtp-profile.h"
|
|
#include "sdp.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
|
|
#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;
|
|
rtsp->redirect_count = 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);
|
|
}
|