100 : m_Client(aClient), m_Streamer(&aStreamer) {
101 m_RtspClient = &m_Client;
102 m_RtspSessionID = random(65536);
103 LOGI(
"RTSP session created");
115 LOGI(
"RTSP session destructor");
118 if (m_streaming && m_Streamer) {
119 LOGI(
"Final cleanup: stopping streamer in destructor");
121 m_Streamer->releaseUdpTransport();
126 if (m_RtspClient && m_RtspClient->connected()) {
127 Platform::closeSocket(m_RtspClient);
130 LOGI(
"RTSP session cleanup completed");
150 LOGD(
"handleRequests");
154 if (!m_sessionOpen) {
159 memset(mRecvBuf.data(), 0x00, RTSP_BUFFER_SIZE);
160 int res =
readSocket(m_RtspClient, mRecvBuf.data(), RTSP_BUFFER_SIZE,
165 if ((mRecvBuf[0] ==
'O') || (mRecvBuf[0] ==
'D') ||
166 (mRecvBuf[0] ==
'S') || (mRecvBuf[0] ==
'P') ||
167 (mRecvBuf[0] ==
'T')) {
170 if (C == RTSP_PLAY) {
172 }
else if (C == RTSP_PAUSE) {
174 }
else if (C == RTSP_TEARDOWN) {
175 m_sessionOpen =
false;
178 if (m_streaming && m_Streamer) {
179 LOGI(
"Stopping streamer due to TEARDOWN");
181 m_Streamer->releaseUdpTransport();
187 }
else if (res == 0) {
188 LOGW(
"client closed socket, exiting");
189 m_sessionOpen =
false;
192 if (m_streaming && m_Streamer) {
193 LOGI(
"Stopping streamer due to client disconnect");
195 m_Streamer->releaseUdpTransport();
207 bool isSessionOpen() {
return m_sessionOpen; }
209 bool isStreaming() {
return m_streaming; }
212 const char* STD_URL_PRE_SUFFIX =
"trackID";
216 typename Platform::TcpClientType m_Client;
217 typename Platform::TcpClientType* m_RtspClient =
220 uint16_t m_ClientRTPPort;
221 uint16_t m_ClientRTCPPort;
222 RTSPAudioStreamerBase<Platform>* m_Streamer =
231 unsigned m_ContentLength;
232 uint16_t m_RtpClientPort =
234 uint16_t m_RtcpClientPort =
237 bool m_TransportIsTcp =
false;
238 int m_InterleavedRtp = -1;
239 int m_InterleavedRtcp = -1;
250 bool m_is_init =
false;
251 bool m_streaming =
false;
252 volatile bool m_sessionOpen =
true;
262 if (m_is_init)
return;
267 m_sessionOpen =
true;
270 if (mRecvBuf.size() == 0) {
271 mRecvBuf.resize(RTSP_BUFFER_SIZE);
273 if (mCurRequest.size() == 0) {
274 mCurRequest.resize(RTSP_BUFFER_SIZE);
276 if (m_URLPreSuffix.size() == 0) {
277 m_URLPreSuffix.resize(RTSP_PARAM_STRING_MAX);
279 if (m_URLSuffix.size() == 0) {
280 m_URLSuffix.resize(RTSP_PARAM_STRING_MAX);
282 if (m_CSeq.size() == 0) {
283 m_CSeq.resize(RTSP_PARAM_STRING_MAX);
285 if (m_URLHostPort.size() == 0) {
286 m_URLHostPort.resize(MAX_HOSTNAME_LEN);
288 if (m_Response.size() == 0) {
289 m_Response.resize(RTSP_RESPONSE_BUFFER_SIZE);
291 if (m_SDPBuf.size() == 0) {
292 m_SDPBuf.resize(RTSP_SDP_BUFFER_SIZE);
294 if (m_URLBuf.size() == 0) {
295 m_URLBuf.resize(RTSP_URL_BUFFER_SIZE);
297 if (m_Buf1.size() == 0) {
298 m_Buf1.resize(RTSP_SMALL_BUFFER_SIZE);
300 if (m_Buf2.size() == 0) {
301 m_Buf2.resize(RTSP_SMALL_BUFFER_SIZE);
303 if (m_CmdName.size() == 0) {
304 m_CmdName.resize(RTSP_PARAM_STRING_MAX);
307 m_RtspCmdType = RTSP_UNKNOWN;
308 memset(m_URLPreSuffix.data(), 0x00, m_URLPreSuffix.size());
309 memset(m_URLSuffix.data(), 0x00, m_URLSuffix.size());
310 memset(m_CSeq.data(), 0x00, m_CSeq.size());
311 memset(m_URLHostPort.data(), 0x00, m_URLHostPort.size());
313 m_TransportIsTcp =
false;
314 m_InterleavedRtp = -1;
315 m_InterleavedRtcp = -1;
327 unsigned aRequestSize) {
329 switch (m_RtspCmdType) {
334 case RTSP_DESCRIBE: {
350 case RTSP_TEARDOWN: {
358 return m_RtspCmdType;
369 LOGI(
"aRequest: ------------------------\n%s\n-------------------------",
372 const unsigned CurRequestSize = aRequestSize;
373 memcpy(mCurRequest.data(), aRequest, aRequestSize);
376 parseClientPorts(mCurRequest.data());
377 parseTransportHeader(mCurRequest.data());
380 unsigned idxAfterCmd = 0;
381 if (!parseCommandName(mCurRequest.data(), CurRequestSize, idxAfterCmd))
383 determineCommandType();
384 parseUrlHostPortAndSuffix(mCurRequest.data(), CurRequestSize, idxAfterCmd);
387 if (!parseCSeq(mCurRequest.data(), CurRequestSize, idxAfterCmd))
389 parseContentLength(mCurRequest.data(), CurRequestSize, idxAfterCmd);
392 detectClientHeaderPreference(mCurRequest.data());
398 void parseClientPorts(
char* req) {
399 char* ClientPortPtr = strstr(req,
"client_port");
400 if (!ClientPortPtr)
return;
401 char* lineEnd = strstr(ClientPortPtr,
"\r\n");
402 if (!lineEnd)
return;
403 char* CP = m_Response.data();
404 memset(CP, 0, m_Response.size());
405 char saved = lineEnd[0];
407 strcpy(CP, ClientPortPtr);
408 char* eq = strstr(CP,
"=");
412 char* dash = strstr(CP,
"-");
415 m_ClientRTPPort = atoi(CP);
416 m_ClientRTCPPort = m_ClientRTPPort + 1;
422 void parseTransportHeader(
char* req) {
423 char* TransportPtr = strstr(req,
"Transport:");
424 if (!TransportPtr)
return;
425 char* lineEnd = strstr(TransportPtr,
"\r\n");
426 if (!lineEnd)
return;
427 char* CP = m_Response.data();
428 memset(CP, 0, m_Response.size());
429 char saved = lineEnd[0];
431 strncpy(CP, TransportPtr, m_Response.size() - 1);
432 CP[m_Response.size() - 1] =
'\0';
433 if (strstr(CP,
"RTP/AVP/TCP") || strstr(CP,
"/TCP")) m_TransportIsTcp =
true;
434 char* inter = strstr(CP,
"interleaved=");
436 inter += strlen(
"interleaved=");
438 if (sscanf(inter,
"%d-%d", &a, &b) == 2) {
439 m_InterleavedRtp = a;
440 m_InterleavedRtcp = b;
441 }
else if (sscanf(inter,
"%d,%d", &a, &b) == 2) {
442 m_InterleavedRtp = a;
443 m_InterleavedRtcp = b;
444 }
else if (sscanf(inter,
"%d", &a) == 1) {
445 m_InterleavedRtp = a;
446 m_InterleavedRtcp = a + 1;
452 bool parseCommandName(
char* req,
unsigned reqSize,
unsigned& outIdx) {
455 for (i = 0; i < m_CmdName.size() - 1 && i < reqSize; ++i) {
457 if (c ==
' ' || c ==
'\t') {
465 LOGE(
"failed to parse RTSP");
468 LOGI(
"RTSP received %s", m_CmdName.data());
473 void determineCommandType() {
474 if (strstr(m_CmdName.data(),
"OPTIONS"))
475 m_RtspCmdType = RTSP_OPTIONS;
476 else if (strstr(m_CmdName.data(),
"DESCRIBE"))
477 m_RtspCmdType = RTSP_DESCRIBE;
478 else if (strstr(m_CmdName.data(),
"SETUP"))
479 m_RtspCmdType = RTSP_SETUP;
480 else if (strstr(m_CmdName.data(),
"PLAY"))
481 m_RtspCmdType = RTSP_PLAY;
482 else if (strstr(m_CmdName.data(),
"PAUSE"))
483 m_RtspCmdType = RTSP_PAUSE;
484 else if (strstr(m_CmdName.data(),
"TEARDOWN"))
485 m_RtspCmdType = RTSP_TEARDOWN;
487 LOGE(
"Error: Unsupported Command received (%s)!", m_CmdName.data());
490 void parseUrlHostPortAndSuffix(
char* req,
unsigned reqSize,
unsigned& i) {
492 while (j < reqSize && (req[j] ==
' ' || req[j] ==
'\t')) ++j;
493 for (; (int)j < (
int)(reqSize - 8); ++j) {
494 if ((req[j] ==
'r' || req[j] ==
'R') && (req[j + 1] ==
't' || req[j + 1] ==
'T') &&
495 (req[j + 2] ==
's' || req[j + 2] ==
'S') && (req[j + 3] ==
'p' || req[j + 3] ==
'P') &&
496 req[j + 4] ==
':' && req[j + 5] ==
'/') {
501 while (j < reqSize && req[j] !=
'/' && req[j] !=
' ' && uidx < m_URLHostPort.size() - 1) {
502 m_URLHostPort[uidx++] = req[j++];
511 LOGD(
"m_URLHostPort: %s", m_URLHostPort.data());
514 for (
unsigned k = i + 1; (int)k < (
int)(reqSize - 5); ++k) {
515 if (req[k] ==
'R' && req[k + 1] ==
'T' && req[k + 2] ==
'S' && req[k + 3] ==
'P' && req[k + 4] ==
'/') {
516 while (--k >= i && req[k] ==
' ') {}
518 while (k1 > i && req[k1] !=
'=') --k1;
519 if (k - k1 + 1 <= m_URLSuffix.size()) {
520 unsigned n = 0, k2 = k1 + 1;
521 while (k2 <= k) m_URLSuffix[n++] = req[k2++];
522 m_URLSuffix[n] =
'\0';
523 if (k1 - i <= m_URLPreSuffix.size()) ok =
true;
526 while (k2 <= k1 - 1) m_URLPreSuffix[n++] = req[k2++];
527 m_URLPreSuffix[n] =
'\0';
533 LOGD(
"m_URLSuffix: %s", m_URLSuffix.data());
534 LOGD(
"m_URLPreSuffix: %s", m_URLPreSuffix.data());
535 LOGD(
"URL Suffix parse succeeded: %i", ok);
538 bool parseCSeq(
char* req,
unsigned reqSize,
unsigned startIdx) {
540 for (
unsigned j = startIdx; (int)j < (
int)(reqSize - 5); ++j) {
541 if (req[j] ==
'C' && req[j + 1] ==
'S' && req[j + 2] ==
'e' && req[j + 3] ==
'q' && req[j + 4] ==
':') {
543 while (j < reqSize && (req[j] ==
' ' || req[j] ==
'\t')) ++j;
545 for (n = 0; n < m_CSeq.size() - 1 && j < reqSize; ++n, ++j) {
547 if (c ==
'\r' || c ==
'\n') {
557 LOGD(
"Look for CSeq success: %i", ok);
561 void parseContentLength(
char* req,
unsigned reqSize,
unsigned startIdx) {
562 for (
unsigned j = startIdx; (int)j < (
int)(reqSize - 15); ++j) {
563 if (req[j] ==
'C' && req[j + 1] ==
'o' && req[j + 2] ==
'n' && req[j + 3] ==
't' &&
564 req[j + 4] ==
'e' && req[j + 5] ==
'n' && req[j + 6] ==
't' && req[j + 7] ==
'-' &&
565 (req[j + 8] ==
'L' || req[j + 8] ==
'l') && req[j + 9] ==
'e' && req[j + 10] ==
'n' &&
566 req[j + 11] ==
'g' && req[j + 12] ==
't' && req[j + 13] ==
'h' && req[j + 14] ==
':') {
568 while (j < reqSize && (req[j] ==
' ' || req[j] ==
'\t')) ++j;
570 if (sscanf(&req[j],
"%u", &num) == 1) m_ContentLength = num;
575 void detectClientHeaderPreference(
char* req) {
576 char* ua = strstr(req,
"User-Agent:");
577 bool want_rfc2250 =
false;
579 if (strcasestr(ua,
"ffmpeg") || strcasestr(ua,
"ffplay") || strcasestr(ua,
"libavformat") ||
580 strcasestr(ua,
"Lavf")) {
583 if (strcasestr(ua,
"vlc")) want_rfc2250 =
false;
585 char* qm = strchr(req,
'?');
587 if (strstr(qm,
"mpa_hdr=1")) want_rfc2250 =
true;
588 if (strstr(qm,
"mpa_hdr=0")) want_rfc2250 =
false;
590 if (m_Streamer && m_Streamer->getAudioSource()) {
591 RTSPFormat& fmt = m_Streamer->getAudioSource()->getFormat();
592 fmt.setUseRfc2250Header(want_rfc2250);
600 snprintf(m_Response.data(), m_Response.size(),
601 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n"
602 "Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE\r\n\r\n",
605 sendSocket(m_RtspClient, m_Response.data(), strlen(m_Response.data()));
615 if (strcmp(m_URLPreSuffix.data(), STD_URL_PRE_SUFFIX) == 0) {
617 m_StreamID = strtol(m_URLSuffix.data(), &end, 10);
618 if (*end !=
'\0') m_StreamID = -1;
623 strncpy(m_Buf1.data(), m_URLHostPort.data(), 256);
624 ColonPtr = strstr(m_Buf1.data(),
":");
625 if (ColonPtr !=
nullptr) ColonPtr[0] = 0x00;
628 m_SDPBuf.data(), m_SDPBuf.size(),
630 "o=- %d 0 IN IP4 %s\r\n"
633 rand() & 0xFF, m_Buf1.data(),
634 m_Streamer->getAudioSource()->getFormat().format(m_Buf2.data(), 256),
637 snprintf(m_URLBuf.data(), m_URLBuf.size(),
"rtsp://%s",
638 m_URLHostPort.data());
640 snprintf(m_Response.data(), m_Response.size(),
641 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n"
643 "Content-Base: %s/\r\n"
644 "Content-Type: application/sdp\r\n"
645 "Content-Length: %d\r\n\r\n"
648 (
int)strlen(m_SDPBuf.data()), m_SDPBuf.data());
651 Serial.println(
"------------------------------");
652 Serial.println((
const char*)m_Response.data());
653 Serial.println(
"------------------------------");
654 sendSocket(m_RtspClient, m_Response.data(), strlen(m_Response.data()));
662 if (m_TransportIsTcp) {
664 int ch0 = (m_InterleavedRtp >= 0) ? m_InterleavedRtp : 0;
665 int ch1 = (m_InterleavedRtcp >= 0) ? m_InterleavedRtcp : (ch0 + 1);
666 m_Streamer->initTcpInterleavedTransport(m_RtspClient, ch0, ch1);
669 snprintf(m_Buf1.data(), m_Buf1.size(),
670 "RTP/AVP/TCP;unicast;interleaved=%d-%d", ch0, ch1);
675 snprintf(m_Buf1.data(), m_Buf1.size(),
676 "RTP/AVP;unicast;client_port=%i-%i;server_port=%i-%i;ssrc=%08X",
677 m_ClientRTPPort, m_ClientRTCPPort,
678 m_Streamer->getRtpServerPort(), m_Streamer->getRtcpServerPort(),
679 (
unsigned)m_Streamer->currentSsrc());
681 snprintf(m_Response.data(), m_Response.size(),
682 "RTSP/1.0 200 OK\r\n"
688 m_CSeq.data(),
dateHeader(), m_RtspSessionID, m_Buf1.data());
690 Serial.println(
"------------------------------");
691 Serial.println((
char*)m_Response.data());
692 Serial.println(
"------------------------------");
694 sendSocket(m_RtspClient, m_Response.data(), strlen(m_Response.data()));
703 snprintf(m_URLBuf.data(), m_URLBuf.size(),
"rtsp://%s/%s=0",
704 m_URLHostPort.data(), STD_URL_PRE_SUFFIX);
707 uint16_t seq = m_Streamer ? m_Streamer->currentSeq() : 0;
708 uint32_t rtptime = m_Streamer ? m_Streamer->currentRtpTimestamp() : 0;
711 snprintf(m_Response.data(), m_Response.size(),
712 "RTSP/1.0 200 OK\r\n"
714 "Range: npt=0.000-\r\n"
716 "RTP-Info: url=%s;seq=%u;rtptime=%u\r\n\r\n",
717 m_CSeq.data(), m_RtspSessionID, m_URLBuf.data(), (
unsigned)seq,
720 Serial.println(
"------------------------------");
721 Serial.println((
char*)m_Response.data());
722 Serial.println(
"------------------------------");
724 sendSocket(m_RtspClient, m_Response.data(), strlen(m_Response.data()));
734 if (m_streaming && m_Streamer) {
737 snprintf(m_Response.data(), m_Response.size(),
738 "RTSP/1.0 200 OK\r\n"
740 "Session: %i\r\n\r\n",
741 m_CSeq.data(), m_RtspSessionID);
742 sendSocket(m_RtspClient, m_Response.data(), strlen(m_Response.data()));
752 snprintf(m_Response.data(), m_Response.size(),
753 "RTSP/1.0 200 OK\r\n"
757 sendSocket(m_RtspClient, m_Response.data(), strlen(m_Response.data()));
759 m_sessionOpen =
false;
774 m_RtpClientPort = aRtpPort;
775 m_RtcpClientPort = aRtcpPort;
779 Platform::getSocketPeerAddr(m_RtspClient, &clientIP, &clientPort);
781 m_Streamer->initUdpTransport(clientIP, m_RtpClientPort);
784 typename Platform::TcpClientType*& getClient() {
return m_RtspClient; }
786 uint16_t getRtpClientPort() {
return m_RtpClientPort; }
796 inline int readSocket(
typename Platform::TcpClientType* sock,
char* buf,
797 size_t buflen,
int timeoutmsec) {
798 return Platform::readSocket(sock, buf, buflen, timeoutmsec);
808 inline ssize_t
sendSocket(
typename Platform::TcpClientType* sock,
809 const void* buf,
size_t len) {
810 return Platform::sendSocket(sock, buf, len);
818 static char buf[200];
819 time_t tt = time(NULL);
820 strftime(buf,
sizeof(buf),
"Date: %a, %b %d %Y %H:%M:%S GMT", gmtime(&tt));