stream-deploy/ZLM/3rdpart/media-server/librtsp/source/client/rtsp-client-setup.c

225 lines
8.3 KiB
C++

/*
C->S:
SETUP rtsp://example.com/foo/bar/baz.rm RTSP/1.0
CSeq: 302
Transport: RTP/AVP;unicast;client_port=4588-4589
S->C:
RTSP/1.0 200 OK
CSeq: 302
Date: 23 Jan 1997 15:35:06 GMT
Session: 47112344
Transport: RTP/AVP;unicast;client_port=4588-4589;server_port=6256-6257
*/
#include "rtsp-client-internal.h"
static const char* sc_rtsp_setup = "SETUP %s RTSP/1.0\r\n"
"CSeq: %u\r\n"
"%s" // Session: %s\r\n
"%s" // Authorization: Digest xxx
"%s" // Transport: RTP/AVP;unicast;client_port=6000-6001
"User-Agent: %s\r\n"
"\r\n";
int rtsp_addr_is_multicast(const char* ip);
static int rtsp_client_media_setup(struct rtsp_client_t* rtsp, int i)
{
int len;
char transport[128];
char session[sizeof(rtsp->session[0].session) + 12], *p;
assert(i < rtsp->media_count);
assert(RTSP_SETUP == rtsp->state);
if (i >= rtsp->media_count) return -1;
transport[0] = session[0] = '\0';
p = rtsp->session[0].session;
len = (rtsp->aggregate && *p) ? snprintf(session, sizeof(session), "Session: %s\r\n", p) : 0;
assert(len >= 0 && len < sizeof(session));
switch (rtsp->transport[i].transport) {
case RTSP_TRANSPORT_RTP_TCP:
len = snprintf(transport, sizeof(transport), "Transport: RTP/AVP/TCP;interleaved=%d-%d\r\n", rtsp->transport[i].interleaved1, rtsp->transport[i].interleaved2);
break;
case RTSP_TRANSPORT_RTP_UDP:
if(0 == rtsp->transport[i].multicast)
len = snprintf(transport, sizeof(transport), "Transport: RTP/AVP;unicast;client_port=%hu-%hu\r\n", rtsp->transport[i].rtp.u.client_port1, rtsp->transport[i].rtp.u.client_port2);
else if(*rtsp->transport[i].destination)
len = snprintf(transport, sizeof(transport), "Transport: RTP/AVP;multicast;destination=%s;port=%hu-%hu;ttl=%d\r\n", rtsp->transport[i].destination, rtsp->transport[i].rtp.m.port1, rtsp->transport[i].rtp.m.port2, rtsp->transport[i].rtp.m.ttl);
else
len = snprintf(transport, sizeof(transport), "Transport: RTP/AVP;multicast;port=%hu-%hu;ttl=%d\r\n", rtsp->transport[i].rtp.m.port1, rtsp->transport[i].rtp.m.port2, rtsp->transport[i].rtp.m.ttl);
break;
case RTSP_TRANSPORT_RAW:
if(0 == rtsp->transport[i].multicast)
len = snprintf(transport, sizeof(transport), "Transport: RAW/RAW/UDP;unicast;client_port=%hu-%hu\r\n", rtsp->transport[i].rtp.u.client_port1, rtsp->transport[i].rtp.u.client_port2);
else if(*rtsp->transport[i].destination)
len = snprintf(transport, sizeof(transport), "Transport: RAW/RAW/UDP;multicast;destination=%s;port=%hu-%hu;ttl=%d\r\n", rtsp->transport[i].destination, rtsp->transport[i].rtp.m.port1, rtsp->transport[i].rtp.m.port2, rtsp->transport[i].rtp.m.ttl);
else
len = snprintf(transport, sizeof(transport), "Transport: RAW/RAW/UDP;multicast;port=%hu-%hu;ttl=%d\r\n", rtsp->transport[i].rtp.m.port1, rtsp->transport[i].rtp.m.port2, rtsp->transport[i].rtp.m.ttl);
break;
default:
assert(0);
return -1;
}
assert(len >= 0 && len < sizeof(transport));
len = rtsp_client_authenrization(rtsp, "SETUP", rtsp->media[i].uri, NULL, 0, rtsp->authenrization, sizeof(rtsp->authenrization));
len = snprintf(rtsp->req, sizeof(rtsp->req), sc_rtsp_setup, rtsp->media[i].uri, rtsp->cseq++, session, rtsp->authenrization, transport, USER_AGENT);
return (len > 0 && len < sizeof(rtsp->req) && len == rtsp->handler.send(rtsp->param, rtsp->media[i].uri, rtsp->req, len)) ? 0 : -1;
}
int rtsp_client_setup(struct rtsp_client_t* rtsp, const char* sdp, int len)
{
int i, r;
unsigned short port[2];
struct rtsp_media_t *m;
struct rtsp_header_transport_t *t;
if (NULL == sdp || 0 == *sdp || len < 1)
return -1;
r = rtsp_media_sdp(sdp, len, rtsp->media, sizeof(rtsp->media)/sizeof(rtsp->media[0]));
if (r < 0 || r > sizeof(rtsp->media) / sizeof(rtsp->media[0]))
return r < 0 ? r : -E2BIG; // too many media stream
rtsp->media_count = r;
for (i = 0; i < rtsp->media_count; i++)
{
m = rtsp->media + i;
t = rtsp->transport + i;
// rfc 2326 C.1.1 Control URL (p80)
// If found at the session level, the attribute indicates the URL for aggregate control
rtsp_media_set_url(m, rtsp->baseuri, rtsp->location, rtsp->uri);
port[0] = (unsigned short)m->port[0];
port[1] = (unsigned short)m->port[1];
snprintf(t->source, sizeof(t->source), "%s", m->source);
snprintf(t->destination, sizeof(t->destination), "%s", m->address);
r = rtsp->handler.rtpport(rtsp->param, i, t->source, port, t->destination, sizeof(t->destination));
if (r < 0)
return r;
if(RTSP_TRANSPORT_RTP_TCP == r)
{
t->transport = RTSP_TRANSPORT_RTP_TCP;
t->interleaved1 = 0==port[0] ? 2 * (unsigned short)i : port[0];
t->interleaved2 = 0==port[1] ? t->interleaved1 + 1 : port[1];
}
else if((RTSP_TRANSPORT_RTP_UDP == r || RTSP_TRANSPORT_RAW == r) && rtsp_addr_is_multicast(t->destination))
{
assert(0 == t->rtp.u.client_port1 % 2);
t->transport = r;
t->multicast = 1;
t->rtp.m.ttl = 16; // default RTT
t->rtp.m.port1 = port[0];
t->rtp.m.port2 = 0 == port[1] ? t->rtp.m.port1 + 1 : port[1];
}
else if(RTSP_TRANSPORT_RTP_UDP == r || RTSP_TRANSPORT_RAW == r)
{
assert(0 == t->rtp.u.client_port1 % 2);
t->transport = r;
t->multicast = 0;
t->rtp.u.client_port1 = port[0];
t->rtp.u.client_port2 = 0 == port[1] ? t->rtp.u.client_port1 + 1 : port[1];
}
else if (0 == r)
{
// ignore media
if (i + 1 < rtsp->media_count)
memmove(rtsp->media + i, rtsp->media + i + 1, sizeof(rtsp->media[0]) * (rtsp->media_count - i - 1));
rtsp->media_count--;
i--; // redo
continue;
}
else
{
assert(0);
return -1;
}
}
rtsp->aggregate = (rtsp->media_count > 1 && rtsp->media[0].session_uri[0]) ? 1 : 0;
if (rtsp->aggregate)
{
snprintf(rtsp->aggregate_uri, sizeof(rtsp->aggregate_uri), "%s", rtsp->media[0].session_uri);
}
else if(rtsp->media_count > 1)
{
// fix some IPC set Content-Base only
const char* base;
base = rtsp->baseuri[0] ? rtsp->baseuri : rtsp->location;
rtsp->aggregate = base[0] ? 1 : 0;
if(rtsp->aggregate)
snprintf(rtsp->aggregate_uri, sizeof(rtsp->aggregate_uri), "%s", base);
}
rtsp->state = RTSP_SETUP;
rtsp->progress = 0;
return rtsp_client_media_setup(rtsp, rtsp->progress);
}
int rtsp_client_setup_onreply(struct rtsp_client_t* rtsp, void* parser)
{
int code;
const char *session;
const char *transport;
struct rtsp_header_range_t* range;
assert(RTSP_SETUP == rtsp->state);
assert(rtsp->progress < rtsp->media_count);
code = http_get_status_code(parser);
if (200 == code)
{
session = http_get_header_by_name(parser, "Session");
transport = http_get_header_by_name(parser, "Transport");
if (!session || 0 != rtsp_header_session(session, &rtsp->session[rtsp->progress])
|| !transport || 0 != rtsp_header_transport(transport, &rtsp->transport[rtsp->progress]))
{
printf("Get rtsp transport error.\n");
return -EINVAL;
}
//assert(rtsp->media[rtsp->progress].transport.transport != RTSP_TRANSPORT_RTP_TCP || (rtsp->media[rtsp->progress].transport.rtp.u.client_port1== rtsp->media[rtsp->progress].transport.interleaved1 && rtsp->media[rtsp->progress].transport.rtp.u.client_port2 == rtsp->media[rtsp->progress].transport.interleaved2));
assert(strlen(session) < sizeof(rtsp->session[0].session));
assert(!rtsp->aggregate || 0 == strcmp(rtsp->session[0].session, rtsp->session[rtsp->progress].session));
if (rtsp->media_count == ++rtsp->progress)
{
assert(rtsp->media_count > 0);
range = &rtsp->media[0].range;
return rtsp->handler.onsetup(rtsp->param, rtsp->session[rtsp->progress].timeout / 1000, RTSP_RANGE_TIME_NORMAL==range->from_value && RTSP_RANGE_TIME_NORMAL==range->to_value ? range->to - range->from : -1);
}
else
{
// setup next media
return rtsp_client_media_setup(rtsp, rtsp->progress);
}
}
else if (401 == code)
{
// Unauthorized
const char* authenticate;
authenticate = http_get_header_by_name(parser, "WWW-Authenticate");
if (authenticate)
{
rtsp_client_www_authenticate(rtsp, authenticate);
}
return -EACCES; // try again
}
else if (461 == code)
{
// Unsupported Transport
return -1;
}
else
{
return -1;
}
}