// RFC2326 10.6 PAUSE (p36) // 1. A PAUSE request discards all queued PLAY requests. However, the pause // point in the media stream MUST be maintained. A subsequent PLAY // request without Range header resumes from the pause point. int rtsp_server_pause(struct rtsp_server_t* rtsp, const char* uri) { int64_t npt = -1L; const char *prange, *psession; struct rtsp_header_range_t range; prange = rtsp_get_header_by_name(rtsp->parser, "range"); psession = rtsp_get_header_by_name(rtsp->parser, "Session"); rtsp->session.session[0] = 0; // clear session value if (!psession || 0 != rtsp_header_session(psession, &rtsp->session)) { // 454 Session Not Found return rtsp_server_reply(rtsp, 454); } if (prange && 0 == rtsp_header_range(prange, &range)) { npt = range.from; // 10.6 The normal play time for the stream is set to the pause point. (p36) assert(range.type == RTSP_RANGE_NPT); // 3.6 Normal Play Time (p17) assert(range.to_value == RTSP_RANGE_TIME_NOVALUE); // 457 Invalid Range //rtsp_server_reply(req, 457, NULL); //return; } return rtsp->handler.onpause(rtsp->param, rtsp, uri, rtsp->session.session, -1L == npt ? NULL : &npt); }
void rtsp_server_reply_describe(void* rtsp, int code, const char* sdp) { rfc822_datetime_t datetime; struct rtsp_server_request_t *req; req = (struct rtsp_server_request_t *)rtsp; if(200 != code) { rtsp_server_reply(req, code); return; } datetime_format(time(NULL), datetime); snprintf(req->reply, sizeof(req->reply), "RTSP/1.0 200 OK\r\n" "CSeq: %u\r\n" "Date: %s\r\n" "Content-Type: application/sdp\r\n" "Content-Length: %lu\r\n" "\r\n" "%s", req->cseq, datetime, strlen(sdp), sdp); req->transport->send(req->session, req->reply, strlen(req->reply)); }
void rtsp_server_reply_setup(void* rtsp, int code, const char* session, const char* transport) { rfc822_datetime_t datetime; struct rtsp_server_request_t *req; req = (struct rtsp_server_request_t *)rtsp; if(200 != code) { rtsp_server_reply(req, code); return; } datetime_format(time(NULL), datetime); // RTP/AVP;unicast;client_port=4588-4589;server_port=6256-6257 snprintf(req->reply, sizeof(req->reply), "RTSP/1.0 200 OK\r\n" "CSeq: %u\r\n" "Date: %s\r\n" "Session: %s\r\n" "Transport: %s\r\n" "\r\n", req->cseq, datetime, session, transport); req->transport->send(req->session, req->reply, strlen(req->reply)); }
// RFC2326 10.6 PAUSE (p36) // 1. A PAUSE request discards all queued PLAY requests. However, the pause // point in the media stream MUST be maintained. A subsequent PLAY // request without Range header resumes from the pause point. static void rtsp_server_pause(struct rtsp_server_request_t *req, void* parser, const char* uri) { int64_t npt = -1L; const char *prange, *psession; struct rtsp_header_range_t range; struct rtsp_header_session_t session; struct rtsp_server_context_t* ctx = req->server; prange = rtsp_get_header_by_name(parser, "range"); psession = rtsp_get_header_by_name(parser, "Session"); if(!psession || 0 != rtsp_header_session(psession, &session)) { // 454 Session Not Found rtsp_server_reply(req, 454); return; } if(prange && 0 == rtsp_header_range(prange, &range)) { npt = range.from; // 10.6 The normal play time for the stream is set to the pause point. (p36) assert(range.type == RTSP_RANGE_NPT); // 3.6 Normal Play Time (p17) assert(range.to_value == RTSP_RANGE_TIME_NOVALUE); // 457 Invalid Range //rtsp_server_reply(req, 457); //return; } ctx->handler.pause(ctx->ptr, req, uri, session.session, -1L==npt?NULL:&npt); }
static void rtsp_server_play(struct rtsp_server_request_t *req, void* parser, const char* uri) { int64_t npt = -1L; double scale = 0.0f; const char *pscale, *prange, *psession; struct rtsp_header_range_t range; struct rtsp_header_session_t session; struct rtsp_server_context_t* ctx = req->server; pscale = rtsp_get_header_by_name(parser, "scale"); prange = rtsp_get_header_by_name(parser, "range"); psession = rtsp_get_header_by_name(parser, "Session"); if(!psession || 0 != rtsp_header_session(psession, &session)) { // 454 (Session Not Found) rtsp_server_reply(req, 454); return; } if(pscale) { scale = atof(pscale); } if(prange && 0 == rtsp_header_range(prange, &range)) { npt = range.from; } ctx->handler.play(ctx->ptr, req, uri, session.session, -1L==npt?NULL:&npt, pscale?&scale:NULL); }
static void rtsp_server_setup(struct rtsp_server_request_t *req, void *parser, const char* uri) { size_t n; const char *psession, *ptransport; struct rtsp_header_session_t session; struct rtsp_header_transport_t transport[16]; struct rtsp_server_context_t* ctx = req->server; psession = rtsp_get_header_by_name(parser, "Session"); ptransport = rtsp_get_header_by_name(parser, "Transport"); memset(transport, 0, sizeof(transport)); n = sizeof(transport)/sizeof(transport[0]); if(!ptransport || 0 != rtsp_header_transport_ex(ptransport, transport, &n) || 0 == n) { // 461 Unsupported Transport rtsp_server_reply(req, 461); return; } assert(n > 0); if(psession && 0 == rtsp_header_session(psession, &session)) { ctx->handler.setup(ctx->ptr, req, uri, session.session, transport, n); } else { ctx->handler.setup(ctx->ptr, req, uri, NULL, transport, n); } }
static void rtsp_server_teardown(struct rtsp_server_request_t *req, void *parser, const char* uri) { const char *psession; struct rtsp_header_session_t session; struct rtsp_server_context_t* ctx = req->server; psession = rtsp_get_header_by_name(parser, "Session"); if(!psession || 0 != rtsp_header_session(psession, &session)) { // 454 (Session Not Found) rtsp_server_reply(req, 454); return; } ctx->handler.teardown(ctx->ptr, req, uri, session.session); }
void rtsp_server_reply_play(void* rtsp, int code, const int64_t *nptstart, const int64_t *nptend, const char* rtp) { char range[64] = {0}; char rtpinfo[256] = {0}; rfc822_datetime_t datetime; struct rtsp_server_request_t *req; req = (struct rtsp_server_request_t *)rtsp; if(200 != code) { rtsp_server_reply(req, code); return; } if(rtp) { snprintf(rtpinfo, sizeof(rtpinfo), "RTP-Info: %s\r\n", rtp); } if(nptstart) { if(nptend) snprintf(range, sizeof(range), "Range: %.3f-%.3f\r\n", (float)(*nptstart/1000.0f), (float)(*nptend/1000.0f)); else snprintf(range, sizeof(range), "Range: %.3f-\r\n", (float)(*nptstart/1000.0f)); } datetime_format(time(NULL), datetime); // smpte=0:10:22-;time=19970123T153600Z snprintf(req->reply, sizeof(req->reply), "RTSP/1.0 200 OK\r\n" "CSeq: %u\r\n" "Date: %s\r\n" "%s" // Range "%s" // RTP-Info "\r\n", req->cseq, datetime, range, rtpinfo); req->transport->send(req->session, req->reply, strlen(req->reply)); }
void rtsp_server_reply_teardown(void* rtsp, int code) { struct rtsp_server_request_t *req; req = (struct rtsp_server_request_t *)rtsp; rtsp_server_reply(req, code); }
static void rtsp_server_handle(struct rtsp_server_request_t *req, void* parser) { int major, minor; const char* uri; const char* method; req->parser = parser; rtsp_get_version(parser, &major, &minor); if(1 != major && 0 != minor) { //505 RTSP Version Not Supported rtsp_server_reply(req, 505); return; } if(0 != rtsp_get_header_by_name2(parser, "CSeq", (int*)&req->cseq)) { // 400 Bad Request rtsp_server_reply(req, 400); return; } uri = rtsp_get_request_uri(parser); method = rtsp_get_request_method(parser); switch(*method) { case 'o': case 'O': if(0 == stricmp("OPTIONS", method)) { rtsp_server_options(req, parser, uri); return; } break; case 'd': case 'D': if(0 == stricmp("DESCRIBE", method)) { rtsp_server_describe(req, parser, uri); return; } break; case 's': case 'S': if(0 == stricmp("SETUP", method)) { rtsp_server_setup(req, parser, uri); return; } break; case 'p': case 'P': if(0 == stricmp("PLAY", method)) { rtsp_server_play(req, parser, uri); return; } else if(0 == stricmp("PAUSE", method)) { rtsp_server_pause(req, parser, uri); return; } break; case 't': case 'T': if(0 == stricmp("TEARDOWN", method)) { rtsp_server_teardown(req, parser, uri); return; } break; } // 501 Not implemented rtsp_server_reply(req, 501); }