Skip to content

Commit 9c4df61

Browse files
committed
utils: Add SDP parser
1 parent c4e20cf commit 9c4df61

File tree

4 files changed

+295
-0
lines changed

4 files changed

+295
-0
lines changed

Makefile.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ TEST_OBJS = $(COMMON_OBJS) \
224224
test/test_tv.o \
225225
test/test_net_udp.o \
226226
test/test_rtp.o \
227+
test/test_sdp_parser.o \
227228
test/run_tests.o
228229

229230
DEP_FILES_2 = $(REFLECTOR_OBJS) $(TEST_OBJS) $(ULTRAGRID_OBJS)

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3501,6 +3501,7 @@ if test "$build_default" != no || test "$req_files" = all; then
35013501
src/capture_filter/ratelimit.o
35023502
src/capture_filter/split.o
35033503
src/capture_filter/temporal_3d.o
3504+
src/utils/sdp_parser.o
35043505
src/video_capture/aggregate.o
35053506
src/video_capture/import.o
35063507
src/video_capture/switcher.o

src/utils/sdp_parser.cpp

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/**
2+
* @file utils/sdp_parser.cpp
3+
* @author Martin Piatka <[email protected]>
4+
*/
5+
/*
6+
* Copyright (c) 2025 CESNET, zájmové sdružení právnických osob
7+
* All rights reserved.
8+
*
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, is permitted provided that the following conditions
11+
* are met:
12+
*
13+
* 1. Redistributions of source code must retain the above copyright
14+
* notice, this list of conditions and the following disclaimer.
15+
*
16+
* 2. Redistributions in binary form must reproduce the above copyright
17+
* notice, this list of conditions and the following disclaimer in the
18+
* documentation and/or other materials provided with the distribution.
19+
*
20+
* 3. Neither the name of CESNET nor the names of its contributors may be
21+
* used to endorse or promote products derived from this software without
22+
* specific prior written permission.
23+
*
24+
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25+
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26+
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27+
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28+
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29+
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34+
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35+
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36+
*/
37+
38+
#include "sdp_parser.hpp"
39+
#include "utils/string_view_utils.hpp"
40+
41+
Sap_packet_view Sap_packet_view::from_buffer(const void *buf, size_t size){
42+
Sap_packet_view ret;
43+
44+
std::string_view sap(static_cast<const char *>(buf), size);
45+
46+
if(sap.empty()){
47+
return ret;
48+
}
49+
50+
ret.flags = sap[0];
51+
sap.remove_prefix(1);
52+
53+
ret.version = ret.flags >> 6;
54+
55+
uint8_t auth_len = 0;
56+
if(sap.empty())
57+
return ret;
58+
59+
auth_len = sap[0];
60+
sap.remove_prefix(1);
61+
62+
//TODO error check length
63+
ret.hash = sap[0] << 8 | sap[1];
64+
sap.remove_prefix(2);
65+
66+
//TODO error check length
67+
ret.source = sap.substr(0, 4);
68+
sap.remove_prefix(4);
69+
70+
//TODO error check length
71+
sap.remove_prefix(auth_len);
72+
73+
if(sv_is_prefix(sap, "v=0")){
74+
//RFC says that the payload type is optional if it's sdp and
75+
//that it should be detected by the presence of v=0
76+
ret.payload_type = "application/sdp";
77+
ret.payload = sap;
78+
} else {
79+
auto null_idx = sap.find('\0');
80+
if(null_idx == sap.npos){
81+
return ret;
82+
}
83+
ret.payload_type = sap.substr(0, null_idx);
84+
ret.payload = sap.substr(null_idx + 1);
85+
}
86+
87+
ret.valid = true;
88+
return ret;
89+
}
90+
91+
Sdp_view Sdp_view::from_buffer(const void *buf, size_t size){
92+
Sdp_view ret;
93+
94+
std::string_view sdp(static_cast<const char *>(buf), size);
95+
96+
if(sdp.empty()){
97+
return ret;
98+
}
99+
100+
while(!sdp.empty()){
101+
auto line = tokenize(sdp, '\n');
102+
if(line.empty())
103+
continue;
104+
105+
if(line.back() == '\r')
106+
line.remove_suffix(1);
107+
108+
auto eq_idx = line.find('=');
109+
if(eq_idx == line.npos){
110+
continue;
111+
}
112+
auto key = line.substr(0, eq_idx);
113+
auto val = line.substr(eq_idx + 1);
114+
115+
if(key == "c"){
116+
if(ret.media.empty()){
117+
ret.connection = val;
118+
} else {
119+
ret.media.back().connection = val;
120+
}
121+
} else if(key == "a"){
122+
auto attrib = tokenize(val, ':');
123+
auto attrib_val = tokenize(val, ':');
124+
125+
if(ret.media.empty()){
126+
ret.session_attributes.push_back({attrib, attrib_val});
127+
} else {
128+
ret.media.back().attributes.push_back({attrib, attrib_val});
129+
}
130+
131+
} else if(key =="s"){
132+
ret.session_name = val;
133+
} else if(key == "o"){
134+
ret.origin = val;
135+
} else if(key == "m"){
136+
ret.media.emplace_back();
137+
auto& medium = ret.media.back();
138+
139+
medium.media_desc = val;
140+
}
141+
142+
}
143+
144+
ret.valid = true;
145+
146+
return ret;
147+
}
148+
149+
Rtp_pkt_view Rtp_pkt_view::from_buffer(void *buf, size_t size){
150+
Rtp_pkt_view ret{};
151+
152+
if(size < 12)
153+
return ret;
154+
155+
auto charbuf = static_cast<unsigned char*>(buf);
156+
157+
uint8_t version = charbuf[0] >> 6;
158+
bool padding = charbuf[0] & (1 << 5);
159+
bool extension = charbuf[0] & (1 << 4);
160+
ret.csrc_count = charbuf[0] & 0x0F;
161+
ret.marker = charbuf[1] & 0x80;
162+
ret.payload_type = charbuf[1] & 0x7F;
163+
ret.seq = charbuf[2] << 8 | charbuf[3];
164+
ret.timestamp = charbuf[4] << 24 | charbuf[5] << 16 | charbuf[6] << 8 | charbuf[7];
165+
ret.ssrc = charbuf[8] << 24 | charbuf[9] << 16 | charbuf[10] << 8 | charbuf[11];
166+
167+
168+
size_t data_offset = 12 + ret.csrc_count * 4;
169+
ret.data = &charbuf[data_offset];
170+
ret.data_len = size - data_offset;
171+
172+
ret.valid = true;
173+
return ret;
174+
}

src/utils/sdp_parser.hpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/**
2+
* @file utils/sdp_parser.hpp
3+
* @author Martin Piatka <[email protected]>
4+
*/
5+
/*
6+
* Copyright (c) 2025 CESNET, zájmové sdružení právnických osob
7+
* All rights reserved.
8+
*
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, is permitted provided that the following conditions
11+
* are met:
12+
*
13+
* 1. Redistributions of source code must retain the above copyright
14+
* notice, this list of conditions and the following disclaimer.
15+
*
16+
* 2. Redistributions in binary form must reproduce the above copyright
17+
* notice, this list of conditions and the following disclaimer in the
18+
* documentation and/or other materials provided with the distribution.
19+
*
20+
* 3. Neither the name of CESNET nor the names of its contributors may be
21+
* used to endorse or promote products derived from this software without
22+
* specific prior written permission.
23+
*
24+
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25+
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26+
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27+
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28+
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29+
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34+
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35+
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36+
*/
37+
38+
#ifndef SDP_PARSER_HPP_cccb52235120
39+
#define SDP_PARSER_HPP_cccb52235120
40+
41+
#include <string_view>
42+
#include <vector>
43+
#include <cstdint>
44+
45+
#define SAP_FLAG_COMPRESSED (1 << 0)
46+
#define SAP_FLAG_ENCRYPTED (1 << 1)
47+
#define SAP_FLAG_DELETION (1 << 2)
48+
#define SAP_FLAG_IPV6 (1 << 4)
49+
50+
51+
struct Sap_packet_view{
52+
uint8_t version;
53+
uint8_t flags;
54+
uint16_t hash;
55+
56+
std::string_view source;
57+
std::string_view payload_type;
58+
std::string_view payload;
59+
60+
static Sap_packet_view from_buffer(const void *buf, size_t size);
61+
62+
bool isValid() const { return valid; }
63+
bool isCompressed() const { return flags & SAP_FLAG_COMPRESSED; }
64+
bool isEncrypted() const { return flags & SAP_FLAG_ENCRYPTED; }
65+
bool isDeletion() const { return flags & SAP_FLAG_DELETION; }
66+
bool isIpv6() const { return flags & SAP_FLAG_IPV6; }
67+
68+
bool valid = false;
69+
70+
};
71+
72+
struct Sdp_attribute{
73+
std::string_view key;
74+
std::string_view val;
75+
};
76+
77+
struct Sdp_media_desc{
78+
std::string_view media_desc;
79+
std::string_view title;
80+
std::string_view connection;
81+
std::vector<Sdp_attribute> attributes;
82+
};
83+
84+
struct Sdp_view{
85+
std::string_view origin;
86+
std::string_view session_name;
87+
std::string_view session_info;
88+
std::string_view connection;
89+
90+
std::string_view session_time;
91+
std::vector<Sdp_attribute> session_attributes;
92+
93+
std::vector<Sdp_media_desc> media;
94+
95+
static Sdp_view from_buffer(const void *buf, size_t size);
96+
bool isValid() const { return valid; }
97+
98+
bool valid = false;
99+
};
100+
101+
struct Rtp_pkt_view{
102+
bool marker;
103+
uint8_t payload_type;
104+
uint16_t seq;
105+
uint32_t timestamp;
106+
uint32_t ssrc;
107+
//uint32_t *csrcs;
108+
size_t csrc_count;
109+
void *data;
110+
size_t data_len;
111+
112+
static Rtp_pkt_view from_buffer(void *buf, size_t size);
113+
bool isValid() const { return valid; }
114+
115+
bool valid = false;
116+
};
117+
118+
119+
#endif

0 commit comments

Comments
 (0)