libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
rtppacket.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_NETWORK
13#include <cassert>
14#include <cstring>
15#include <promeki/bufferview.h>
16#include <promeki/queue.h>
17#include <promeki/timestamp.h>
18
19PROMEKI_NAMESPACE_BEGIN
20
64class RtpPacket : public BufferView {
65 public:
67 using List = promeki::List<RtpPacket>;
68
71 using Queue = promeki::Queue<RtpPacket>;
72
74 using SizeList = promeki::List<size_t>;
75
77 static constexpr size_t HeaderSize = 12;
78
80 RtpPacket() = default;
81
88 RtpPacket(Buffer buf, size_t offset, size_t size) : BufferView(std::move(buf), offset, size) {}
89
95 bool isNull() const { return data() == nullptr; }
96
105 bool isValid() const {
106 if (data() == nullptr) return false;
107 if (size() < HeaderSize) return false;
108 if (((data()[0] >> 6) & 0x03) != 2) return false;
109 return headerSize() != 0;
110 }
111
121 explicit RtpPacket(size_t packetSize) : BufferView(Buffer(packetSize), 0, packetSize) {
122 std::memset(data(), 0, packetSize);
123 setVersion(2);
124 }
125
136 static List createList(size_t count, size_t packetSize) {
137 List ret;
138 if (count == 0 || packetSize == 0) return ret;
139 size_t totalSize = count * packetSize;
140 // F9 hot-path: RTP packets are wire-format byte
141 // streams; no consumer requires page (4 KB)
142 // alignment, and the default Buffer ctor rounds
143 // the request *up* to a page for the underlying
144 // aligned_alloc. A ~200 byte ANC keep-alive
145 // therefore allocates a whole 4 KB page. 16-byte
146 // alignment matches malloc's natural alignment
147 // and lets the small-block fast path serve every
148 // sub-MTU packet without page-table churn.
149 auto buf = Buffer(totalSize, /*align=*/16);
150 std::memset(buf.data(), 0, totalSize);
151 ret.reserve(count);
152 for (size_t i = 0; i < count; ++i) {
153 RtpPacket pkt(buf, i * packetSize, packetSize);
154 pkt.setVersion(2);
155 ret.pushToBack(std::move(pkt));
156 }
157 return ret;
158 }
159
170 static List createList(const SizeList &sizes) {
171 List ret;
172 if (sizes.isEmpty()) return ret;
173 size_t totalSize = 0;
174 for (size_t i = 0; i < sizes.size(); ++i) totalSize += sizes[i];
175 if (totalSize == 0) return ret;
176 // F9 hot-path: see the uniform-size overload —
177 // 16-byte alignment avoids the 4 KB-per-allocation
178 // page-rounding tax on small ANC / audio / data
179 // packets.
180 auto buf = Buffer(totalSize, /*align=*/16);
181 std::memset(buf.data(), 0, totalSize);
182 ret.reserve(sizes.size());
183 size_t offset = 0;
184 for (size_t i = 0; i < sizes.size(); ++i) {
185 RtpPacket pkt(buf, offset, sizes[i]);
186 if (sizes[i] >= HeaderSize) pkt.setVersion(2);
187 ret.pushToBack(std::move(pkt));
188 offset += sizes[i];
189 }
190 return ret;
191 }
192
194 uint8_t version() const { return (hdr()[0] >> 6) & 0x03; }
195
197 void setVersion(uint8_t v) { hdr()[0] = (hdr()[0] & 0x3F) | ((v & 0x03) << 6); }
198
200 bool padding() const { return (hdr()[0] >> 5) & 0x01; }
201
203 void setPadding(bool p) { hdr()[0] = (hdr()[0] & 0xDF) | (p ? 0x20 : 0x00); }
204
206 bool extension() const { return (hdr()[0] >> 4) & 0x01; }
207
209 void setExtension(bool x) { hdr()[0] = (hdr()[0] & 0xEF) | (x ? 0x10 : 0x00); }
210
212 uint8_t csrcCount() const { return hdr()[0] & 0x0F; }
213
215 bool marker() const { return (hdr()[1] >> 7) & 0x01; }
216
218 void setMarker(bool m) { hdr()[1] = (hdr()[1] & 0x7F) | (m ? 0x80 : 0x00); }
219
221 uint8_t payloadType() const { return hdr()[1] & 0x7F; }
222
224 void setPayloadType(uint8_t pt) { hdr()[1] = (hdr()[1] & 0x80) | (pt & 0x7F); }
225
227 uint16_t sequenceNumber() const { return (static_cast<uint16_t>(hdr()[2]) << 8) | hdr()[3]; }
228
230 void setSequenceNumber(uint16_t seq) {
231 hdr()[2] = static_cast<uint8_t>(seq >> 8);
232 hdr()[3] = static_cast<uint8_t>(seq & 0xFF);
233 }
234
236 uint32_t timestamp() const {
237 return (static_cast<uint32_t>(hdr()[4]) << 24) | (static_cast<uint32_t>(hdr()[5]) << 16) |
238 (static_cast<uint32_t>(hdr()[6]) << 8) | static_cast<uint32_t>(hdr()[7]);
239 }
240
242 void setTimestamp(uint32_t ts) {
243 hdr()[4] = static_cast<uint8_t>((ts >> 24) & 0xFF);
244 hdr()[5] = static_cast<uint8_t>((ts >> 16) & 0xFF);
245 hdr()[6] = static_cast<uint8_t>((ts >> 8) & 0xFF);
246 hdr()[7] = static_cast<uint8_t>(ts & 0xFF);
247 }
248
250 uint32_t ssrc() const {
251 return (static_cast<uint32_t>(hdr()[8]) << 24) | (static_cast<uint32_t>(hdr()[9]) << 16) |
252 (static_cast<uint32_t>(hdr()[10]) << 8) | static_cast<uint32_t>(hdr()[11]);
253 }
254
256 void setSsrc(uint32_t s) {
257 hdr()[8] = static_cast<uint8_t>((s >> 24) & 0xFF);
258 hdr()[9] = static_cast<uint8_t>((s >> 16) & 0xFF);
259 hdr()[10] = static_cast<uint8_t>((s >> 8) & 0xFF);
260 hdr()[11] = static_cast<uint8_t>(s & 0xFF);
261 }
262
272 size_t headerSize() const {
273 if (size() < HeaderSize) return 0;
274 size_t hs = HeaderSize + csrcCount() * 4;
275 if (hs > size()) return 0;
276 if (extension()) {
277 // Need at least 4 bytes for the extension header
278 if (hs + 4 > size()) return 0;
279 const uint8_t *ext = data() + hs;
280 uint16_t extLen = (static_cast<uint16_t>(ext[2]) << 8) | ext[3];
281 hs += 4 + extLen * 4;
282 if (hs > size()) return 0;
283 }
284 return hs;
285 }
286
291 uint16_t extensionProfile() const {
292 if (!extension()) return 0;
293 size_t extOffset = HeaderSize + csrcCount() * 4;
294 if (extOffset + 4 > size()) return 0;
295 const uint8_t *ext = data() + extOffset;
296 return (static_cast<uint16_t>(ext[0]) << 8) | ext[1];
297 }
298
303 uint16_t extensionLength() const {
304 if (!extension()) return 0;
305 size_t extOffset = HeaderSize + csrcCount() * 4;
306 if (extOffset + 4 > size()) return 0;
307 const uint8_t *ext = data() + extOffset;
308 return (static_cast<uint16_t>(ext[2]) << 8) | ext[3];
309 }
310
317 const uint8_t *payload() const {
318 size_t hs = headerSize();
319 if (hs == 0 || hs >= size()) return nullptr;
320 return data() + hs;
321 }
322
324 uint8_t *payload() {
325 size_t hs = headerSize();
326 if (hs == 0 || hs >= size()) return nullptr;
327 return data() + hs;
328 }
329
336 size_t payloadSize() const {
337 size_t hs = headerSize();
338 if (hs == 0 || hs >= size()) return 0;
339 return size() - hs;
340 }
341
347 void clear() {
348 if (isNull()) return;
349 std::memset(data(), 0, size());
350 setVersion(2);
351 }
352
376 TimeStamp arrivalSteady;
377
378 private:
379 const uint8_t *hdr() const {
380 assert(data() != nullptr && size() >= HeaderSize);
381 return data();
382 }
383 uint8_t *hdr() {
384 assert(data() != nullptr && size() >= HeaderSize);
385 return data();
386 }
387};
388
389PROMEKI_NAMESPACE_END
390
391#endif // PROMEKI_ENABLE_NETWORK