36
static const struct RTSPStatusMessage {
37
enum RTSPStatusCode code;
39
} status_messages[] = {
40
{ RTSP_STATUS_OK, "OK" },
41
{ RTSP_STATUS_METHOD, "Method Not Allowed" },
42
{ RTSP_STATUS_BANDWIDTH, "Not Enough Bandwidth" },
43
{ RTSP_STATUS_SESSION, "Session Not Found" },
44
{ RTSP_STATUS_STATE, "Method Not Valid in This State" },
45
{ RTSP_STATUS_AGGREGATE, "Aggregate operation not allowed" },
46
{ RTSP_STATUS_ONLY_AGGREGATE, "Only aggregate operation allowed" },
47
{ RTSP_STATUS_TRANSPORT, "Unsupported transport" },
48
{ RTSP_STATUS_INTERNAL, "Internal Server Error" },
49
{ RTSP_STATUS_SERVICE, "Service Unavailable" },
50
{ RTSP_STATUS_VERSION, "RTSP Version not supported" },
54
static int rtsp_read_close(AVFormatContext *s)
56
RTSPState *rt = s->priv_data;
58
if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN))
59
ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
61
ff_rtsp_close_streams(s);
62
ff_rtsp_close_connections(s);
64
rt->real_setup = NULL;
65
av_freep(&rt->real_setup_cache);
69
static inline int read_line(AVFormatContext *s, char *rbuf, const int rbufsize,
72
RTSPState *rt = s->priv_data;
78
ret = ffurl_read_complete(rt->rtsp_hd, rbuf + idx, 1);
80
return ret ? ret : AVERROR_EOF;
81
if (rbuf[idx] == '\r') {
83
} else if (rbuf[idx] == '\n') {
89
} while (idx < rbufsize);
90
av_log(s, AV_LOG_ERROR, "Message too long\n");
94
static int rtsp_send_reply(AVFormatContext *s, enum RTSPStatusCode code,
95
const char *extracontent, uint16_t seq)
97
RTSPState *rt = s->priv_data;
100
while (status_messages[index].code) {
101
if (status_messages[index].code == code) {
102
snprintf(message, sizeof(message), "RTSP/1.0 %d %s\r\n",
103
code, status_messages[index].message);
108
if (!status_messages[index].code)
109
return AVERROR(EINVAL);
110
av_strlcatf(message, sizeof(message), "CSeq: %d\r\n", seq);
111
av_strlcatf(message, sizeof(message), "Server: %s\r\n", LIBAVFORMAT_IDENT);
113
av_strlcat(message, extracontent, sizeof(message));
114
av_strlcat(message, "\r\n", sizeof(message));
115
av_dlog(s, "Sending response:\n%s", message);
116
ffurl_write(rt->rtsp_hd, message, strlen(message));
121
static inline int check_sessionid(AVFormatContext *s,
122
RTSPMessageHeader *request)
124
RTSPState *rt = s->priv_data;
125
unsigned char *session_id = rt->session_id;
126
if (!session_id[0]) {
127
av_log(s, AV_LOG_WARNING, "There is no session-id at the moment\n");
130
if (strcmp(session_id, request->session_id)) {
131
av_log(s, AV_LOG_ERROR, "Unexpected session-id %s\n",
132
request->session_id);
133
rtsp_send_reply(s, RTSP_STATUS_SESSION, NULL, request->seq);
134
return AVERROR_STREAM_NOT_FOUND;
139
static inline int rtsp_read_request(AVFormatContext *s,
140
RTSPMessageHeader *request,
143
RTSPState *rt = s->priv_data;
147
ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
151
av_dlog(s, "Parsing[%d]: %s\n", rbuflen, rbuf);
152
ff_rtsp_parse_line(request, rbuf, rt, method);
154
} while (rbuflen > 0);
155
if (request->seq != rt->seq + 1) {
156
av_log(s, AV_LOG_ERROR, "Unexpected Sequence number %d\n",
158
return AVERROR(EINVAL);
160
if (rt->session_id[0] && strcmp(method, "OPTIONS")) {
161
ret = check_sessionid(s, request);
169
static int rtsp_read_announce(AVFormatContext *s)
171
RTSPState *rt = s->priv_data;
172
RTSPMessageHeader request = { 0 };
176
ret = rtsp_read_request(s, &request, "ANNOUNCE");
180
if (strcmp(request.content_type, "application/sdp")) {
181
av_log(s, AV_LOG_ERROR, "Unexpected content type %s\n",
182
request.content_type);
183
rtsp_send_reply(s, RTSP_STATUS_SERVICE, NULL, request.seq);
184
return AVERROR_OPTION_NOT_FOUND;
186
if (request.content_length && request.content_length < sizeof(sdp) - 1) {
188
if (ffurl_read_complete(rt->rtsp_hd, sdp, request.content_length)
189
< request.content_length) {
190
av_log(s, AV_LOG_ERROR,
191
"Unable to get complete SDP Description in ANNOUNCE\n");
192
rtsp_send_reply(s, RTSP_STATUS_INTERNAL, NULL, request.seq);
195
sdp[request.content_length] = '\0';
196
av_log(s, AV_LOG_VERBOSE, "SDP: %s\n", sdp);
197
ret = ff_sdp_parse(s, sdp);
200
rtsp_send_reply(s, RTSP_STATUS_OK, NULL, request.seq);
203
av_log(s, AV_LOG_ERROR,
204
"Content-Length header value exceeds sdp allocated buffer (4KB)\n");
205
rtsp_send_reply(s, RTSP_STATUS_INTERNAL,
206
"Content-Length exceeds buffer size", request.seq);
210
static int rtsp_read_options(AVFormatContext *s)
212
RTSPState *rt = s->priv_data;
213
RTSPMessageHeader request = { 0 };
216
/* Parsing headers */
217
ret = rtsp_read_request(s, &request, "OPTIONS");
222
rtsp_send_reply(s, RTSP_STATUS_OK,
223
"Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, RECORD\r\n",
228
static int rtsp_read_setup(AVFormatContext *s, char* host, char *controlurl)
230
RTSPState *rt = s->priv_data;
231
RTSPMessageHeader request = { 0 };
235
char responseheaders[1024];
237
int transportidx = 0;
240
ret = rtsp_read_request(s, &request, "SETUP");
244
if (!request.nb_transports) {
245
av_log(s, AV_LOG_ERROR, "No transport defined in SETUP\n");
246
return AVERROR_INVALIDDATA;
248
for (transportidx = 0; transportidx < request.nb_transports;
250
if (!request.transports[transportidx].mode_record ||
251
(request.transports[transportidx].lower_transport !=
252
RTSP_LOWER_TRANSPORT_UDP &&
253
request.transports[transportidx].lower_transport !=
254
RTSP_LOWER_TRANSPORT_TCP)) {
255
av_log(s, AV_LOG_ERROR, "mode=record/receive not set or transport"
256
" protocol not supported (yet)\n");
257
return AVERROR_INVALIDDATA;
260
if (request.nb_transports > 1)
261
av_log(s, AV_LOG_WARNING, "More than one transport not supported, "
262
"using first of all\n");
263
for (streamid = 0; streamid < rt->nb_rtsp_streams; streamid++) {
264
if (!strcmp(rt->rtsp_streams[streamid]->control_url,
268
if (streamid == rt->nb_rtsp_streams) {
269
av_log(s, AV_LOG_ERROR, "Unable to find requested track\n");
270
return AVERROR_STREAM_NOT_FOUND;
272
rtsp_st = rt->rtsp_streams[streamid];
273
localport = rt->rtp_port_min;
275
if (request.transports[0].lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
276
rt->lower_transport = RTSP_LOWER_TRANSPORT_TCP;
277
if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) {
278
rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
281
rtsp_st->interleaved_min = request.transports[0].interleaved_min;
282
rtsp_st->interleaved_max = request.transports[0].interleaved_max;
283
snprintf(responseheaders, sizeof(responseheaders), "Transport: "
284
"RTP/AVP/TCP;unicast;mode=receive;interleaved=%d-%d"
285
"\r\n", request.transports[0].interleaved_min,
286
request.transports[0].interleaved_max);
289
ff_url_join(url, sizeof(url), "rtp", NULL, host, localport, NULL);
290
av_dlog(s, "Opening: %s", url);
291
ret = ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
292
&s->interrupt_callback, NULL);
295
} while (ret || localport > rt->rtp_port_max);
296
if (localport > rt->rtp_port_max) {
297
rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
301
av_dlog(s, "Listening on: %d",
302
ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle));
303
if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) {
304
rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
308
localport = ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle);
309
snprintf(responseheaders, sizeof(responseheaders), "Transport: "
310
"RTP/AVP/UDP;unicast;mode=receive;source=%s;"
311
"client_port=%d-%d;server_port=%d-%d\r\n",
312
host, request.transports[0].client_port_min,
313
request.transports[0].client_port_max, localport,
317
/* Establish sessionid if not previously set */
318
/* Put this in a function? */
319
/* RFC 2326: session id must be at least 8 digits */
320
while (strlen(rt->session_id) < 8)
321
av_strlcatf(rt->session_id, 512, "%u", av_get_random_seed());
323
av_strlcatf(responseheaders, sizeof(responseheaders), "Session: %s\r\n",
326
rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq);
328
rt->state = RTSP_STATE_PAUSED;
332
static int rtsp_read_record(AVFormatContext *s)
334
RTSPState *rt = s->priv_data;
335
RTSPMessageHeader request = { 0 };
337
char responseheaders[1024];
339
ret = rtsp_read_request(s, &request, "RECORD");
342
ret = check_sessionid(s, &request);
346
snprintf(responseheaders, sizeof(responseheaders), "Session: %s\r\n",
348
rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq);
350
rt->state = RTSP_STATE_STREAMING;
354
static inline int parse_command_line(AVFormatContext *s, const char *line,
355
int linelen, char *uri, int urisize,
356
char *method, int methodsize,
357
enum RTSPMethod *methodcode)
359
RTSPState *rt = s->priv_data;
360
const char *linept, *searchlinept;
361
linept = strchr(line, ' ');
362
if (linept - line > methodsize - 1) {
363
av_log(s, AV_LOG_ERROR, "Method string too long\n");
366
memcpy(method, line, linept - line);
367
method[linept - line] = '\0';
369
if (!strcmp(method, "ANNOUNCE"))
370
*methodcode = ANNOUNCE;
371
else if (!strcmp(method, "OPTIONS"))
372
*methodcode = OPTIONS;
373
else if (!strcmp(method, "RECORD"))
374
*methodcode = RECORD;
375
else if (!strcmp(method, "SETUP"))
377
else if (!strcmp(method, "PAUSE"))
379
else if (!strcmp(method, "TEARDOWN"))
380
*methodcode = TEARDOWN;
382
*methodcode = UNKNOWN;
383
/* Check method with the state */
384
if (rt->state == RTSP_STATE_IDLE) {
385
if ((*methodcode != ANNOUNCE) && (*methodcode != OPTIONS)) {
386
av_log(s, AV_LOG_ERROR, "Unexpected command in Idle State %s\n",
388
return AVERROR_PROTOCOL_NOT_FOUND;
390
} else if (rt->state == RTSP_STATE_PAUSED) {
391
if ((*methodcode != OPTIONS) && (*methodcode != RECORD)
392
&& (*methodcode != SETUP)) {
393
av_log(s, AV_LOG_ERROR, "Unexpected command in Paused State %s\n",
395
return AVERROR_PROTOCOL_NOT_FOUND;
397
} else if (rt->state == RTSP_STATE_STREAMING) {
398
if ((*methodcode != PAUSE) && (*methodcode != OPTIONS)
399
&& (*methodcode != TEARDOWN)) {
400
av_log(s, AV_LOG_ERROR, "Unexpected command in Streaming State"
402
return AVERROR_PROTOCOL_NOT_FOUND;
405
av_log(s, AV_LOG_ERROR, "Unexpected State [%d]\n", rt->state);
409
searchlinept = strchr(linept, ' ');
410
if (searchlinept == NULL) {
411
av_log(s, AV_LOG_ERROR, "Error parsing message URI\n");
412
return AVERROR_INVALIDDATA;
414
if (searchlinept - linept > urisize - 1) {
415
av_log(s, AV_LOG_ERROR, "uri string length exceeded buffer size\n");
418
memcpy(uri, linept, searchlinept - linept);
419
uri[searchlinept - linept] = '\0';
420
if (strcmp(rt->control_uri, uri)) {
421
char host[128], path[512], auth[128];
423
char ctl_host[128], ctl_path[512], ctl_auth[128];
425
av_url_split(NULL, 0, auth, sizeof(auth), host, sizeof(host), &port,
426
path, sizeof(path), uri);
427
av_url_split(NULL, 0, ctl_auth, sizeof(ctl_auth), ctl_host,
428
sizeof(ctl_host), &ctl_port, ctl_path, sizeof(ctl_path),
430
if (strcmp(host, ctl_host))
431
av_log(s, AV_LOG_INFO, "Host %s differs from expected %s\n",
433
if (strcmp(path, ctl_path) && *methodcode != SETUP)
434
av_log(s, AV_LOG_WARNING, "WARNING: Path %s differs from expected"
435
" %s\n", path, ctl_path);
436
if (*methodcode == ANNOUNCE) {
437
av_log(s, AV_LOG_INFO,
438
"Updating control URI to %s\n", uri);
439
av_strlcpy(rt->control_uri, uri, sizeof(rt->control_uri));
443
linept = searchlinept + 1;
444
if (!av_strstart(linept, "RTSP/1.0", NULL)) {
445
av_log(s, AV_LOG_ERROR, "Error parsing protocol or version\n");
446
return AVERROR_PROTOCOL_NOT_FOUND;
451
int ff_rtsp_parse_streaming_commands(AVFormatContext *s)
453
RTSPState *rt = s->priv_data;
454
unsigned char rbuf[4096];
455
unsigned char method[10];
459
RTSPMessageHeader request = { 0 };
460
enum RTSPMethod methodcode;
462
ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
465
ret = parse_command_line(s, rbuf, rbuflen, uri, sizeof(uri), method,
466
sizeof(method), &methodcode);
468
av_log(s, AV_LOG_ERROR, "RTSP: Unexpected Command\n");
472
ret = rtsp_read_request(s, &request, method);
476
if (methodcode == PAUSE) {
477
rt->state = RTSP_STATE_PAUSED;
478
ret = rtsp_send_reply(s, RTSP_STATUS_OK, NULL , request.seq);
479
// TODO: Missing date header in response
480
} else if (methodcode == OPTIONS) {
481
ret = rtsp_send_reply(s, RTSP_STATUS_OK,
482
"Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, "
483
"RECORD\r\n", request.seq);
484
} else if (methodcode == TEARDOWN) {
485
rt->state = RTSP_STATE_IDLE;
486
ret = rtsp_send_reply(s, RTSP_STATUS_OK, NULL , request.seq);
34
492
static int rtsp_read_play(AVFormatContext *s)
36
494
RTSPState *rt = s->priv_data;