|
- // RFC 2326 Real Time Streaming Protocol (RTSP)
- // 12.39 Transport (p58)
- //
- // Transport = "Transport" ":" 1#transport-spec
- // transport-spec = transport-protocol/profile[/lower-transport] *parameter
- // transport-protocol = "RTP"
- // profile = "AVP"
- // lower-transport = "TCP" | "UDP"
- // parameter = ( "unicast" | "multicast" )
- // | ";" "destination" [ "=" address ]
- // | ";" "interleaved" "=" channel [ "-" channel ]
- // | ";" "append"
- // | ";" "ttl" "=" ttl
- // | ";" "layers" "=" 1*DIGIT
- // | ";" "port" "=" port [ "-" port ]
- // | ";" "client_port" "=" port [ "-" port ]
- // | ";" "server_port" "=" port [ "-" port ]
- // | ";" "ssrc" "=" ssrc
- // | ";" "mode" = <"> 1\#mode <">
- // ttl = 1*3(DIGIT)
- // port = 1*5(DIGIT)
- // ssrc = 8*8(HEX)
- // channel = 1*3(DIGIT)
- // address = host
- // mode = <"> *Method <"> | Method
- //
- // Transport: RTP/AVP;unicast;client_port=4588-4589;server_port=6256-6257
- // Transport: RTP/AVP;multicast;ttl=127;mode="PLAY",RTP/AVP;unicast;client_port=3456-3457;mode="PLAY"
-
- // RTP Port define
- // RFC 3550: 11. RTP over Network and Transport Protocols (p56)
- // 1. For UDP and similar protocols, RTP should use an even destination port number and
- // the corresponding RTCP stream should use the next higher (odd) destination port number.
- // 2. For applications that take a single port number as a parameter and derive the RTP and RTCP port
- // pair from that number, if an odd number is supplied then the application should replace that
- // number with the next lower (even) number to use as the base of the port pair.
-
- #include "rtsp-header-transport.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
-
- #if defined(_WIN32) || defined(_WIN64) || defined(OS_WINDOWS)
- #define strcasecmp _stricmp
- #define strncasecmp _strnicmp
- #endif
-
- #define TRANSPORT_SPECIAL ",;\r\n"
-
- int rtsp_header_transport(const char* field, struct rtsp_header_transport_t* t)
- {
- const char* p1;
- const char* p = field;
- size_t n;
-
- memset(t, 0, sizeof(*t));
- t->multicast = 0; // default unicast
- t->transport = RTSP_TRANSPORT_RTP_UDP;
-
- while(p && *p)
- {
- p1 = strpbrk(p, TRANSPORT_SPECIAL);
- n = p1 ? (size_t)(p1 - p) : strlen(p); // ptrdiff_t -> size_t
-
- switch(*p)
- {
- case 'r':
- case 'R':
- if(11 == n && 0 == strncasecmp("RTP/AVP/UDP", p, 11))
- {
- t->transport = RTSP_TRANSPORT_RTP_UDP;
- }
- else if(11 == n && 0 == strncasecmp("RTP/AVP/TCP", p, 11))
- {
- t->transport = RTSP_TRANSPORT_RTP_TCP;
- }
- else if(11 == n && 0 == strncasecmp("RAW/RAW/UDP", p, 11))
- {
- t->transport = RTSP_TRANSPORT_RAW;
- }
- else if(7 == n && 0 == strncasecmp("RTP/AVP", p, 7))
- {
- t->transport = RTSP_TRANSPORT_RTP_UDP;
- }
- break;
-
- case 'u':
- case 'U':
- if(7 == n && 0 == strncasecmp("unicast", p, 7))
- {
- t->multicast = 0;
- }
- break;
-
- case 'm':
- case 'M':
- if(9 == n && 0 == strncasecmp("multicast", p, 9))
- {
- t->multicast = 1;
- }
- else if(n > 5 && 0 == strncasecmp("mode=", p, 5))
- {
- if( (11==n && 0 == strcasecmp("\"PLAY\"", p+5)) || (9==n && 0 == strcasecmp("PLAY", p+5)) )
- t->mode = RTSP_TRANSPORT_PLAY;
- else if( (13==n && 0 == strcasecmp("\"RECORD\"", p+5)) || (11==n && 0 == strcasecmp("RECORD", p+5)) )
- t->mode = RTSP_TRANSPORT_RECORD;
- }
- break;
-
- case 'd':
- case 'D':
- if(n >= 12 && 0 == strncasecmp("destination=", p, 12))
- {
- if(n-12 >= sizeof(t->destination)) return -1;
- memcpy(t->destination, p+12, n - 12);
- t->destination[n-12] = '\0';
- }
- break;
-
- case 's':
- case 'S':
- if(n >= 7 && 0 == strncasecmp("source=", p, 7))
- {
- if(n-7 >= sizeof(t->source)) return -1;
- memcpy(t->source, p+7, n - 7);
- t->source[n-7] = '\0';
- }
- else if(13 == n && 0 == strncasecmp("ssrc=", p, 5))
- {
- // unicast only
- assert(0 == t->multicast);
- t->rtp.u.ssrc = (unsigned int)strtoul(p+5, NULL, 16);
- }
- else if(2 == sscanf(p, "server_port=%hu-%hu", &t->rtp.u.server_port1, &t->rtp.u.server_port2))
- {
- assert(0 == t->multicast);
- }
- else if(1 == sscanf(p, "server_port=%hu", &t->rtp.u.server_port1))
- {
- assert(0 == t->multicast);
- t->rtp.u.server_port1 = t->rtp.u.server_port1 / 2 * 2; // RFC 3550 (p56)
- t->rtp.u.server_port2 = t->rtp.u.server_port1 + 1;
- }
- break;
-
- case 'a':
- if(6 == n && 0 == strcasecmp("append", p))
- {
- t->append = 1;
- }
- break;
-
- case 'p':
- if(2 == sscanf(p, "port=%hu-%hu", &t->rtp.m.port1, &t->rtp.m.port2))
- {
- assert(1 == t->multicast);
- }
- else if(1 == sscanf(p, "port=%hu", &t->rtp.m.port1))
- {
- assert(1 == t->multicast);
- t->rtp.m.port1 = t->rtp.m.port1 / 2 * 2; // RFC 3550 (p56)
- t->rtp.m.port2 = t->rtp.m.port1 + 1;
- }
- break;
-
- case 'c':
- if(2 == sscanf(p, "client_port=%hu-%hu", &t->rtp.u.client_port1, &t->rtp.u.client_port2))
- {
- assert(0 == t->multicast);
- }
- else if(1 == sscanf(p, "client_port=%hu", &t->rtp.u.client_port1))
- {
- assert(0 == t->multicast);
- t->rtp.u.client_port1 = t->rtp.u.client_port1 / 2 * 2; // RFC 3550 (p56)
- t->rtp.u.client_port2 = t->rtp.u.client_port1 + 1;
- }
- break;
-
- case 'i':
- if(2 == sscanf(p, "interleaved=%d-%d", &t->interleaved1, &t->interleaved2))
- {
- }
- else if(1 == sscanf(p, "interleaved=%d", &t->interleaved1))
- {
- t->interleaved2 = t->interleaved1 + 1;
- }
- break;
-
- case 't':
- if(1 == sscanf(p, "ttl=%d", &t->rtp.m.ttl))
- {
- assert(1 == t->multicast);
- }
- break;
-
- case 'l':
- if(1 == sscanf(p, "layers=%d", &t->layer))
- {
- }
- break;
- }
-
- if(NULL == p1 || '\r' == *p1 || '\n' == *p1 || '\0' == *p1 || ',' == *p1)
- break;
- p = p1 + 1;
- }
-
- return 0;
- }
-
- #if defined(DEBUG) || defined(_DEBUG)
- void rtsp_header_transport_test(void)
- {
- struct rtsp_header_transport_t t;
-
- memset(&t, 0, sizeof(t));
- assert(0 == rtsp_header_transport("RTP/AVP;unicast;client_port=4588-4589;server_port=6256-6257;ssrc=08abe80f", &t)); // rfc2326 p61
- assert(t.transport==RTSP_TRANSPORT_RTP_UDP);
- assert(t.multicast==0 && t.rtp.u.client_port1==4588 && t.rtp.u.client_port2==4589 && t.rtp.u.server_port1==6256 && t.rtp.u.server_port2==6257);
- assert(t.rtp.u.ssrc == 0x08abe80f);
-
- memset(&t, 0, sizeof(t));
- assert(0 == rtsp_header_transport("RTP/AVP;multicast;ttl=127;mode=\"PLAY\"", &t)); // rfc2326 p61
- assert(t.transport==RTSP_TRANSPORT_RTP_UDP);
- assert(t.multicast==1 && 127==t.rtp.m.ttl && RTSP_TRANSPORT_PLAY==t.mode);
-
- memset(&t, 0, sizeof(t));
- assert(0 == rtsp_header_transport("RTP/AVP/TCP;interleaved=0-1", &t)); // rfc2326 p40
- assert(t.transport == RTSP_TRANSPORT_RTP_TCP);
- assert(t.interleaved1 == 0 && t.interleaved2 == 1);
-
- memset(&t, 0, sizeof(t));
- assert(0 == rtsp_header_transport("RTP/AVP;unicast;source=192.168.111.333.444.555.666.777.888.999.000.123", &t)); // rfc2326 p61
- assert(t.transport==RTSP_TRANSPORT_RTP_UDP);
- assert(t.multicast==0 && 0==strncmp("192.168.111.333.444.555.666.777.888.999.000.123", t.source, sizeof(t.source)-1) && strlen(t.source)<sizeof(t.source));
- }
- #endif
|