mediasoup 3.23.2 → 3.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/node/lib/DataProducer.d.ts +1 -1
  3. package/node/lib/DataProducer.d.ts.map +1 -1
  4. package/node/lib/DataProducer.js +2 -2
  5. package/node/lib/DataProducerTypes.d.ts +1 -1
  6. package/node/lib/DataProducerTypes.d.ts.map +1 -1
  7. package/node/lib/fbs/data-producer/send-notification.d.ts +5 -2
  8. package/node/lib/fbs/data-producer/send-notification.d.ts.map +1 -1
  9. package/node/lib/fbs/data-producer/send-notification.js +17 -5
  10. package/node/lib/test/test-PipeTransport.js +18 -4
  11. package/package.json +3 -3
  12. package/worker/fbs/dataProducer.fbs +1 -0
  13. package/worker/include/RTC/DataConsumer.hpp +1 -0
  14. package/worker/include/RTC/DataProducer.hpp +4 -2
  15. package/worker/include/RTC/RateCalculator.hpp +5 -5
  16. package/worker/include/RTC/Router.hpp +2 -1
  17. package/worker/include/RTC/SubchannelsCodec.hpp +27 -17
  18. package/worker/include/RTC/Transport.hpp +4 -2
  19. package/worker/src/Channel/ChannelMessageRegistrator.cpp +2 -0
  20. package/worker/src/Channel/ChannelRequest.cpp +2 -0
  21. package/worker/src/Channel/ChannelSocket.cpp +4 -0
  22. package/worker/src/DepLibUV.cpp +6 -3
  23. package/worker/src/RTC/ActiveSpeakerObserver.cpp +8 -0
  24. package/worker/src/RTC/AudioLevelObserver.cpp +4 -0
  25. package/worker/src/RTC/DataConsumer.cpp +19 -2
  26. package/worker/src/RTC/DataProducer.cpp +11 -4
  27. package/worker/src/RTC/DirectTransport.cpp +4 -0
  28. package/worker/src/RTC/DtlsTransport.cpp +16 -0
  29. package/worker/src/RTC/ICE/IceCandidate.cpp +8 -0
  30. package/worker/src/RTC/ICE/StunPacket.cpp +2 -0
  31. package/worker/src/RTC/NackGenerator.cpp +2 -0
  32. package/worker/src/RTC/PipeTransport.cpp +4 -0
  33. package/worker/src/RTC/PlainTransport.cpp +10 -0
  34. package/worker/src/RTC/PortManager.cpp +8 -0
  35. package/worker/src/RTC/Producer.cpp +4 -0
  36. package/worker/src/RTC/RTCP/CompoundPacket.cpp +8 -0
  37. package/worker/src/RTC/RTCP/Feedback.cpp +8 -0
  38. package/worker/src/RTC/RTCP/FeedbackPsRemb.cpp +2 -0
  39. package/worker/src/RTC/RTCP/FeedbackPsSli.cpp +2 -0
  40. package/worker/src/RTC/RTCP/FeedbackPsVbcm.cpp +2 -0
  41. package/worker/src/RTC/RTCP/FeedbackRtpNack.cpp +2 -0
  42. package/worker/src/RTC/RTCP/FeedbackRtpTllei.cpp +2 -0
  43. package/worker/src/RTC/RTCP/FeedbackRtpTmmb.cpp +5 -0
  44. package/worker/src/RTC/RTCP/FeedbackRtpTransport.cpp +8 -0
  45. package/worker/src/RTC/RTCP/Sdes.cpp +2 -0
  46. package/worker/src/RTC/RTP/Codecs/AV1.cpp +2 -0
  47. package/worker/src/RTC/RTP/Codecs/DependencyDescriptor.cpp +6 -0
  48. package/worker/src/RTC/RTP/Codecs/VP8.cpp +2 -0
  49. package/worker/src/RTC/RateCalculator.cpp +42 -37
  50. package/worker/src/RTC/Router.cpp +12 -3
  51. package/worker/src/RTC/RtpDictionaries/RtpHeaderExtensionUri.cpp +5 -0
  52. package/worker/src/RTC/RtpDictionaries/RtpParameters.cpp +2 -0
  53. package/worker/src/RTC/SCTP/association/Association.cpp +2 -0
  54. package/worker/src/RTC/SCTP/rx/DataTracker.cpp +2 -0
  55. package/worker/src/RTC/SeqManager.cpp +12 -0
  56. package/worker/src/RTC/SrtpSession.cpp +6 -0
  57. package/worker/src/RTC/SubchannelsCodec.cpp +38 -6
  58. package/worker/src/RTC/Transport.cpp +12 -6
  59. package/worker/src/RTC/TransportCongestionControlClient.cpp +12 -0
  60. package/worker/src/RTC/TransportCongestionControlServer.cpp +2 -0
  61. package/worker/src/Utils/BitStream.cpp +2 -0
  62. package/worker/src/Worker.cpp +2 -0
  63. package/worker/src/handles/SignalHandle.cpp +4 -0
  64. package/worker/src/handles/TcpConnectionHandle.cpp +12 -0
  65. package/worker/src/handles/TcpServerHandle.cpp +6 -0
  66. package/worker/src/handles/TimerHandle.cpp +4 -0
  67. package/worker/src/handles/UdpSocketHandle.cpp +10 -0
  68. package/worker/src/handles/UnixStreamSocketHandle.cpp +10 -0
  69. package/worker/test/src/RTC/TestRateCalculator.cpp +45 -45
  70. package/worker/test/src/RTC/TestSubchannelsCodec.cpp +161 -19
@@ -12,6 +12,8 @@
12
12
 
13
13
  inline static void onAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf)
14
14
  {
15
+ MS_TRACE();
16
+
15
17
  auto* connection = static_cast<TcpConnectionHandle*>(handle->data);
16
18
 
17
19
  if (connection)
@@ -22,6 +24,8 @@ inline static void onAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t*
22
24
 
23
25
  inline static void onRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf)
24
26
  {
27
+ MS_TRACE();
28
+
25
29
  auto* connection = static_cast<TcpConnectionHandle*>(handle->data);
26
30
 
27
31
  if (connection)
@@ -32,6 +36,8 @@ inline static void onRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* bu
32
36
 
33
37
  inline static void onWrite(uv_write_t* req, int status)
34
38
  {
39
+ MS_TRACE();
40
+
35
41
  auto* writeData = static_cast<TcpConnectionHandle::UvWriteData*>(req->data);
36
42
  auto* handle = req->handle;
37
43
  auto* connection = static_cast<TcpConnectionHandle*>(handle->data);
@@ -50,11 +56,15 @@ inline static void onWrite(uv_write_t* req, int status)
50
56
  // ensuring that we call `delete xxx` with same type as `new xxx` before.
51
57
  inline static void onCloseTcp(uv_handle_t* handle)
52
58
  {
59
+ MS_TRACE();
60
+
53
61
  delete reinterpret_cast<uv_tcp_t*>(handle);
54
62
  }
55
63
 
56
64
  inline static void onShutdown(uv_shutdown_t* req, int /*status*/)
57
65
  {
66
+ MS_TRACE();
67
+
58
68
  auto* handle = req->handle;
59
69
 
60
70
  delete req;
@@ -104,6 +114,8 @@ void TcpConnectionHandle::TriggerClose()
104
114
 
105
115
  void TcpConnectionHandle::Dump(int indentation) const
106
116
  {
117
+ MS_TRACE();
118
+
107
119
  MS_DUMP_CLEAN(indentation, "<TcpConnectionHandle>");
108
120
  MS_DUMP_CLEAN(indentation, " local IP: %s", this->localIp.c_str());
109
121
  MS_DUMP_CLEAN(indentation, " local port: %" PRIu16, static_cast<uint16_t>(this->localPort));
@@ -14,6 +14,8 @@ static constexpr int ListenBacklog{ 512 };
14
14
 
15
15
  inline static void onConnection(uv_stream_t* handle, int status)
16
16
  {
17
+ MS_TRACE();
18
+
17
19
  auto* server = static_cast<TcpServerHandle*>(handle->data);
18
20
 
19
21
  if (server)
@@ -24,6 +26,8 @@ inline static void onConnection(uv_stream_t* handle, int status)
24
26
 
25
27
  inline static void onCloseTcp(uv_handle_t* handle)
26
28
  {
29
+ MS_TRACE();
30
+
27
31
  delete reinterpret_cast<uv_tcp_t*>(handle);
28
32
  }
29
33
 
@@ -71,6 +75,8 @@ TcpServerHandle::~TcpServerHandle()
71
75
 
72
76
  void TcpServerHandle::Dump(int indentation) const
73
77
  {
78
+ MS_TRACE();
79
+
74
80
  MS_DUMP_CLEAN(indentation, "<TcpServerHandle>");
75
81
  MS_DUMP_CLEAN(indentation, " local IP: %s", this->localIp.c_str());
76
82
  MS_DUMP_CLEAN(indentation, " local port: %" PRIu16, static_cast<uint16_t>(this->localPort));
@@ -10,11 +10,15 @@
10
10
 
11
11
  static void onTimer(uv_timer_t* handle)
12
12
  {
13
+ MS_TRACE();
14
+
13
15
  static_cast<TimerHandle*>(handle->data)->OnUvTimer();
14
16
  }
15
17
 
16
18
  static void onCloseTimer(uv_handle_t* handle)
17
19
  {
20
+ MS_TRACE();
21
+
18
22
  delete reinterpret_cast<uv_timer_t*>(handle);
19
23
  }
20
24
 
@@ -20,6 +20,8 @@ alignas(4) static thread_local uint8_t ReadBuffer[ReadBufferSize];
20
20
 
21
21
  inline static void onAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf)
22
22
  {
23
+ MS_TRACE();
24
+
23
25
  auto* socket = static_cast<UdpSocketHandle*>(handle->data);
24
26
 
25
27
  if (socket)
@@ -31,6 +33,8 @@ inline static void onAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t*
31
33
  inline static void onRecv(
32
34
  uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned int flags)
33
35
  {
36
+ MS_TRACE();
37
+
34
38
  auto* socket = static_cast<UdpSocketHandle*>(handle->data);
35
39
 
36
40
  if (socket)
@@ -41,6 +45,8 @@ inline static void onRecv(
41
45
 
42
46
  inline static void onSend(uv_udp_send_t* req, int status)
43
47
  {
48
+ MS_TRACE();
49
+
44
50
  auto* sendData = static_cast<UdpSocketHandle::UvSendData*>(req->data);
45
51
  auto* handle = req->handle;
46
52
  auto* socket = static_cast<UdpSocketHandle*>(handle->data);
@@ -57,6 +63,8 @@ inline static void onSend(uv_udp_send_t* req, int status)
57
63
 
58
64
  inline static void onCloseUdp(uv_handle_t* handle)
59
65
  {
66
+ MS_TRACE();
67
+
60
68
  delete reinterpret_cast<uv_udp_t*>(handle);
61
69
  }
62
70
 
@@ -108,6 +116,8 @@ UdpSocketHandle::~UdpSocketHandle()
108
116
 
109
117
  void UdpSocketHandle::Dump(int indentation) const
110
118
  {
119
+ MS_TRACE();
120
+
111
121
  MS_DUMP_CLEAN(indentation, "<UdpSocketHandle>");
112
122
  MS_DUMP_CLEAN(indentation, " local IP: %s", this->localIp.c_str());
113
123
  MS_DUMP_CLEAN(indentation, " local port: %" PRIu16, static_cast<uint16_t>(this->localPort));
@@ -16,6 +16,8 @@
16
16
 
17
17
  inline static void onAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf)
18
18
  {
19
+ MS_TRACE_STD();
20
+
19
21
  auto* socket = static_cast<UnixStreamSocketHandle*>(handle->data);
20
22
 
21
23
  if (socket)
@@ -26,6 +28,8 @@ inline static void onAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t*
26
28
 
27
29
  inline static void onRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf)
28
30
  {
31
+ MS_TRACE_STD();
32
+
29
33
  auto* socket = static_cast<UnixStreamSocketHandle*>(handle->data);
30
34
 
31
35
  if (socket)
@@ -36,6 +40,8 @@ inline static void onRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* bu
36
40
 
37
41
  inline static void onWrite(uv_write_t* req, int status)
38
42
  {
43
+ MS_TRACE_STD();
44
+
39
45
  auto* writeData = static_cast<UnixStreamSocketHandle::UvWriteData*>(req->data);
40
46
  auto* handle = req->handle;
41
47
  auto* socket = static_cast<UnixStreamSocketHandle*>(handle->data);
@@ -54,11 +60,15 @@ inline static void onWrite(uv_write_t* req, int status)
54
60
  // ensuring that we call `delete xxx` with same type as `new xxx` before.
55
61
  inline static void onClosePipe(uv_handle_t* handle)
56
62
  {
63
+ MS_TRACE_STD();
64
+
57
65
  delete reinterpret_cast<uv_pipe_t*>(handle);
58
66
  }
59
67
 
60
68
  inline static void onShutdown(uv_shutdown_t* req, int /*status*/)
61
69
  {
70
+ MS_TRACE_STD();
71
+
62
72
  auto* handle = req->handle;
63
73
 
64
74
  delete req;
@@ -14,9 +14,9 @@ SCENARIO("RateCalculator", "[rate-calculator]")
14
14
  };
15
15
 
16
16
  auto validate =
17
- [](RTC::RateCalculator& rate, uint64_t timeBaseMs, std::vector<TestRateCalculatorData>& input)
17
+ [](RTC::RateCalculator& rate, uint64_t timeBaseMs, const std::vector<TestRateCalculatorData>& input)
18
18
  {
19
- for (auto& item : input)
19
+ for (const auto& item : input)
20
20
  {
21
21
  rate.Update(item.size, timeBaseMs + item.offset);
22
22
 
@@ -26,7 +26,7 @@ SCENARIO("RateCalculator", "[rate-calculator]")
26
26
  // Repeat forcing nowMs to be 0.
27
27
  rate.Reset();
28
28
 
29
- for (auto& item : input)
29
+ for (const auto& item : input)
30
30
  {
31
31
  rate.Update(item.size, timeBaseMs + item.offset);
32
32
 
@@ -36,7 +36,7 @@ SCENARIO("RateCalculator", "[rate-calculator]")
36
36
  // Repeat forcing nowMs to be std::numeric_limits<uint64_t>::max() - 100.
37
37
  rate.Reset();
38
38
 
39
- for (auto& item : input)
39
+ for (const auto& item : input)
40
40
  {
41
41
  rate.Update(item.size, timeBaseMs + item.offset);
42
42
 
@@ -51,9 +51,9 @@ SCENARIO("RateCalculator", "[rate-calculator]")
51
51
  RTC::RateCalculator rate;
52
52
 
53
53
  // clang-format off
54
- std::vector<TestRateCalculatorData> input =
54
+ const std::vector<TestRateCalculatorData> input =
55
55
  {
56
- { 0, 5, 40 }
56
+ { .offset=0, .size=5, .rate=40 }
57
57
  };
58
58
  // clang-format on
59
59
 
@@ -65,12 +65,12 @@ SCENARIO("RateCalculator", "[rate-calculator]")
65
65
  RTC::RateCalculator rate;
66
66
 
67
67
  // clang-format off
68
- std::vector<TestRateCalculatorData> input =
68
+ const std::vector<TestRateCalculatorData> input =
69
69
  {
70
- { 0, 5, 40 },
71
- { 100, 2, 56 },
72
- { 300, 2, 72 },
73
- { 999, 4, 104 }
70
+ { .offset=0, .size=5, .rate=40 },
71
+ { .offset=100, .size=2, .rate=56 },
72
+ { .offset=300, .size=2, .rate=72 },
73
+ { .offset=999, .size=4, .rate=104 }
74
74
  };
75
75
  // clang-format on
76
76
 
@@ -82,11 +82,11 @@ SCENARIO("RateCalculator", "[rate-calculator]")
82
82
  RTC::RateCalculator rate(1000, 8000, 100);
83
83
 
84
84
  // clang-format off
85
- std::vector<TestRateCalculatorData> input =
85
+ const std::vector<TestRateCalculatorData> input =
86
86
  {
87
- { 0, 5, 40 },
88
- { 1000, 5, 40 },
89
- { 2000, 5, 40 }
87
+ { .offset=0, .size=5, .rate=40 },
88
+ { .offset=1000, .size=5, .rate=40 },
89
+ { .offset=2000, .size=5, .rate=40 }
90
90
  };
91
91
  // clang-format on
92
92
 
@@ -98,13 +98,13 @@ SCENARIO("RateCalculator", "[rate-calculator]")
98
98
  RTC::RateCalculator rate(1000, 8000, 1000);
99
99
 
100
100
  // clang-format off
101
- std::vector<TestRateCalculatorData> input =
101
+ const std::vector<TestRateCalculatorData> input =
102
102
  {
103
- { 0, 5, 40 },
104
- { 999, 2, 56 },
105
- { 1001, 1, 24 },
106
- { 1001, 1, 32 },
107
- { 2000, 1, 24 }
103
+ { .offset=0, .size=5, .rate=40 },
104
+ { .offset=999, .size=2, .rate=56 },
105
+ { .offset=1001, .size=1, .rate=24 },
106
+ { .offset=1001, .size=1, .rate=32 },
107
+ { .offset=2000, .size=1, .rate=24 }
108
108
  };
109
109
  // clang-format on
110
110
 
@@ -118,15 +118,15 @@ SCENARIO("RateCalculator", "[rate-calculator]")
118
118
  RTC::RateCalculator rate(1000, 8000, 100);
119
119
 
120
120
  // clang-format off
121
- std::vector<TestRateCalculatorData> input =
121
+ const std::vector<TestRateCalculatorData> input =
122
122
  {
123
- { 0, 5, 40 },
124
- { 999, 2, 56 },
125
- { 1001, 1, 24 }, // merged inside 999
126
- { 1001, 1, 32 }, // merged inside 999
127
- { 2000, 1, 8 } // it will erase the item with timestamp=999,
128
- // removing also the next two samples.
129
- // The end estimation will include only the last sample.
123
+ { .offset=0, .size=5, .rate=40 },
124
+ { .offset=999, .size=2, .rate=56 },
125
+ { .offset=1001, .size=1, .rate=24 }, // merged inside 999
126
+ { .offset=1001, .size=1, .rate=32 }, // merged inside 999
127
+ { .offset=2000, .size=1, .rate=8 } // it will erase the item with
128
+ // timestamp=999, removing also the next two samples. The
129
+ // end estimation will include only the last sample.
130
130
  };
131
131
  // clang-format on
132
132
 
@@ -141,18 +141,18 @@ SCENARIO("RateCalculator", "[rate-calculator]")
141
141
  RTC::RateCalculator rate(1000, 8000, 5);
142
142
 
143
143
  // clang-format off
144
- std::vector<TestRateCalculatorData> input =
144
+ const std::vector<TestRateCalculatorData> input =
145
145
  {
146
- { 1000, 1, 1*8 },
147
- { 1200, 1, 1*8 + 1*8 },
148
- { 1400, 1, 1*8 + 2*8 },
149
- { 1600, 1, 1*8 + 3*8 },
150
- { 1800, 1, 1*8 + 4*8 },
151
- { 2000, 1, 1*8 + (5-1)*8 }, // starts wrap here
152
- { 2200, 1, 1*8 + (6-2)*8 },
153
- { 2400, 1, 1*8 + (7-3)*8 },
154
- { 2600, 1, 1*8 + (8-4)*8 },
155
- { 2800, 1, 1*8 + (9-5)*8 },
146
+ { .offset=1000, .size=1, .rate=1*8 },
147
+ { .offset=1200, .size=1, .rate=(1*8) + (1*8) },
148
+ { .offset=1400, .size=1, .rate=(1*8) + (2*8) },
149
+ { .offset=1600, .size=1, .rate=(1*8) + (3*8) },
150
+ { .offset=1800, .size=1, .rate=(1*8) + (4*8) },
151
+ { .offset=2000, .size=1, .rate=(1*8) + ((5-1)*8) }, // starts wrap here
152
+ { .offset=2200, .size=1, .rate=(1*8) + ((6-2)*8) },
153
+ { .offset=2400, .size=1, .rate=(1*8) + ((7-3)*8) },
154
+ { .offset=2600, .size=1, .rate=(1*8) + ((8-4)*8) },
155
+ { .offset=2800, .size=1, .rate=(1*8) + ((9-5)*8) },
156
156
  };
157
157
  // clang-format on
158
158
 
@@ -167,12 +167,12 @@ SCENARIO("RateCalculator", "[rate-calculator]")
167
167
  RTC::RateCalculator rate(1000, 8000, 3);
168
168
 
169
169
  // clang-format off
170
- std::vector<TestRateCalculatorData> input =
170
+ const std::vector<TestRateCalculatorData> input =
171
171
  {
172
- { 0, 1, 8 },
173
- { 333, 1, 16 },
174
- { 666, 1, 24 },
175
- { 999, 1, 32 },
172
+ { .offset=0, .size=1, .rate=8 },
173
+ { .offset=333, .size=1, .rate=16 },
174
+ { .offset=666, .size=1, .rate=24 },
175
+ { .offset=999, .size=1, .rate=32 },
176
176
  };
177
177
  // clang-format on
178
178
 
@@ -22,7 +22,7 @@ SCENARIO("SubchannelsCodec", "[subchannels]")
22
22
  };
23
23
 
24
24
  SECTION(
25
- "EncodeSubchannels() encodes subchannels and requiredSubchannel and DecodeSubchannels() decodes them back")
25
+ "EncodeSubchannels() encodes subchannels, requiredSubchannel and ignoredSubchannel and DecodeSubchannels() decodes them back")
26
26
  {
27
27
  const std::vector<uint8_t> originalPayload = { 0x01, 0x02, 0x03, 0x04 };
28
28
 
@@ -30,27 +30,32 @@ SCENARIO("SubchannelsCodec", "[subchannels]")
30
30
 
31
31
  const std::vector<uint16_t> subchannels = { 10, 20, 300 };
32
32
  const std::optional<uint16_t> requiredSubchannel = 5;
33
+ const std::optional<uint16_t> ignoredSubchannel = 6;
33
34
 
34
35
  REQUIRE(
35
- RTC::SubchannelsCodec::EncodeSubchannels(message, subchannels, requiredSubchannel) == true);
36
+ RTC::SubchannelsCodec::EncodeSubchannels(
37
+ message, subchannels, requiredSubchannel, ignoredSubchannel) == true);
36
38
 
37
- // 8 (Magic Token) + 2 (subchannelsCount) + 3 * 2 (subchannels) + 2 (requiredSubchannel).
38
- REQUIRE(message.GetPayloadLength() == originalPayload.size() + 8 + 2 + (3 * 2) + 2);
39
+ // 8 (Magic Token) + 2 (subchannelsCount) + 3 * 2 (subchannels) +
40
+ // 2 (requiredSubchannel) + 2 (ignoredSubchannel).
41
+ REQUIRE(message.GetPayloadLength() == originalPayload.size() + 8 + 2 + (3 * 2) + 2 + 2);
39
42
 
40
43
  std::vector<uint16_t> decodedSubchannels;
41
44
  std::optional<uint16_t> decodedRequiredSubchannel;
45
+ std::optional<uint16_t> decodedIgnoredSubchannel;
42
46
 
43
47
  REQUIRE(
44
48
  RTC::SubchannelsCodec::DecodeSubchannels(
45
- message, decodedSubchannels, decodedRequiredSubchannel) == true);
49
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == true);
46
50
 
47
51
  REQUIRE(decodedSubchannels == subchannels);
48
52
  REQUIRE(decodedRequiredSubchannel == requiredSubchannel);
53
+ REQUIRE(decodedIgnoredSubchannel == ignoredSubchannel);
49
54
  // The header must have been removed, leaving the original payload.
50
55
  REQUIRE(payloadToVector(message) == originalPayload);
51
56
  }
52
57
 
53
- SECTION("EncodeSubchannels() encodes subchannels without requiredSubchannel")
58
+ SECTION("EncodeSubchannels() encodes subchannels without requiredSubchannel nor ignoredSubchannel")
54
59
  {
55
60
  const std::vector<uint8_t> originalPayload = { 0xAA, 0xBB };
56
61
 
@@ -58,20 +63,24 @@ SCENARIO("SubchannelsCodec", "[subchannels]")
58
63
 
59
64
  const std::vector<uint16_t> subchannels = { 1, 2 };
60
65
 
61
- REQUIRE(RTC::SubchannelsCodec::EncodeSubchannels(message, subchannels, std::nullopt) == true);
66
+ REQUIRE(
67
+ RTC::SubchannelsCodec::EncodeSubchannels(message, subchannels, std::nullopt, std::nullopt) ==
68
+ true);
62
69
 
63
70
  // 8 (Magic Token) + 2 (subchannelsCount) + 2 * 2 (subchannels).
64
71
  REQUIRE(message.GetPayloadLength() == originalPayload.size() + 8 + 2 + (2 * 2));
65
72
 
66
73
  std::vector<uint16_t> decodedSubchannels;
67
74
  std::optional<uint16_t> decodedRequiredSubchannel;
75
+ std::optional<uint16_t> decodedIgnoredSubchannel;
68
76
 
69
77
  REQUIRE(
70
78
  RTC::SubchannelsCodec::DecodeSubchannels(
71
- message, decodedSubchannels, decodedRequiredSubchannel) == true);
79
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == true);
72
80
 
73
81
  REQUIRE(decodedSubchannels == subchannels);
74
82
  REQUIRE(decodedRequiredSubchannel.has_value() == false);
83
+ REQUIRE(decodedIgnoredSubchannel.has_value() == false);
75
84
  REQUIRE(payloadToVector(message) == originalPayload);
76
85
  }
77
86
 
@@ -83,20 +92,82 @@ SCENARIO("SubchannelsCodec", "[subchannels]")
83
92
 
84
93
  const std::optional<uint16_t> requiredSubchannel = 4321;
85
94
 
86
- REQUIRE(RTC::SubchannelsCodec::EncodeSubchannels(message, {}, requiredSubchannel) == true);
95
+ REQUIRE(
96
+ RTC::SubchannelsCodec::EncodeSubchannels(message, {}, requiredSubchannel, std::nullopt) == true);
87
97
 
88
98
  // 8 (Magic Token) + 2 (subchannelsCount) + 2 (requiredSubchannel).
89
99
  REQUIRE(message.GetPayloadLength() == originalPayload.size() + 8 + 2 + 2);
90
100
 
91
101
  std::vector<uint16_t> decodedSubchannels;
92
102
  std::optional<uint16_t> decodedRequiredSubchannel;
103
+ std::optional<uint16_t> decodedIgnoredSubchannel;
93
104
 
94
105
  REQUIRE(
95
106
  RTC::SubchannelsCodec::DecodeSubchannels(
96
- message, decodedSubchannels, decodedRequiredSubchannel) == true);
107
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == true);
97
108
 
98
109
  REQUIRE(decodedSubchannels.empty() == true);
99
110
  REQUIRE(decodedRequiredSubchannel == requiredSubchannel);
111
+ REQUIRE(decodedIgnoredSubchannel.has_value() == false);
112
+ REQUIRE(payloadToVector(message) == originalPayload);
113
+ }
114
+
115
+ SECTION("EncodeSubchannels() encodes ignoredSubchannel without subchannels")
116
+ {
117
+ const std::vector<uint8_t> originalPayload = { 0xAA, 0xBB, 0xCC };
118
+
119
+ auto message = makeMessage(originalPayload);
120
+
121
+ const std::optional<uint16_t> ignoredSubchannel = 1234;
122
+
123
+ REQUIRE(
124
+ RTC::SubchannelsCodec::EncodeSubchannels(message, {}, std::nullopt, ignoredSubchannel) == true);
125
+
126
+ // 8 (Magic Token) + 2 (subchannelsCount) + 2 (ignoredSubchannel).
127
+ REQUIRE(message.GetPayloadLength() == originalPayload.size() + 8 + 2 + 2);
128
+
129
+ std::vector<uint16_t> decodedSubchannels;
130
+ std::optional<uint16_t> decodedRequiredSubchannel;
131
+ std::optional<uint16_t> decodedIgnoredSubchannel;
132
+
133
+ REQUIRE(
134
+ RTC::SubchannelsCodec::DecodeSubchannels(
135
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == true);
136
+
137
+ REQUIRE(decodedSubchannels.empty() == true);
138
+ REQUIRE(decodedRequiredSubchannel.has_value() == false);
139
+ REQUIRE(decodedIgnoredSubchannel == ignoredSubchannel);
140
+ REQUIRE(payloadToVector(message) == originalPayload);
141
+ }
142
+
143
+ SECTION("EncodeSubchannels() encodes subchannels and ignoredSubchannel without requiredSubchannel")
144
+ {
145
+ const std::vector<uint8_t> originalPayload = { 0x11 };
146
+
147
+ auto message = makeMessage(originalPayload);
148
+
149
+ const std::vector<uint16_t> subchannels = { 100, 200 };
150
+ const std::optional<uint16_t> ignoredSubchannel = 200;
151
+
152
+ REQUIRE(
153
+ RTC::SubchannelsCodec::EncodeSubchannels(
154
+ message, subchannels, std::nullopt, ignoredSubchannel) == true);
155
+
156
+ // 8 (Magic Token) + 2 (subchannelsCount) + 2 * 2 (subchannels) +
157
+ // 2 (ignoredSubchannel).
158
+ REQUIRE(message.GetPayloadLength() == originalPayload.size() + 8 + 2 + (2 * 2) + 2);
159
+
160
+ std::vector<uint16_t> decodedSubchannels;
161
+ std::optional<uint16_t> decodedRequiredSubchannel;
162
+ std::optional<uint16_t> decodedIgnoredSubchannel;
163
+
164
+ REQUIRE(
165
+ RTC::SubchannelsCodec::DecodeSubchannels(
166
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == true);
167
+
168
+ REQUIRE(decodedSubchannels == subchannels);
169
+ REQUIRE(decodedRequiredSubchannel.has_value() == false);
170
+ REQUIRE(decodedIgnoredSubchannel == ignoredSubchannel);
100
171
  REQUIRE(payloadToVector(message) == originalPayload);
101
172
  }
102
173
 
@@ -106,7 +177,8 @@ SCENARIO("SubchannelsCodec", "[subchannels]")
106
177
 
107
178
  auto message = makeMessage(originalPayload);
108
179
 
109
- REQUIRE(RTC::SubchannelsCodec::EncodeSubchannels(message, {}, std::nullopt) == false);
180
+ REQUIRE(
181
+ RTC::SubchannelsCodec::EncodeSubchannels(message, {}, std::nullopt, std::nullopt) == false);
110
182
 
111
183
  // The message must remain untouched.
112
184
  REQUIRE(payloadToVector(message) == originalPayload);
@@ -120,13 +192,15 @@ SCENARIO("SubchannelsCodec", "[subchannels]")
120
192
 
121
193
  std::vector<uint16_t> decodedSubchannels;
122
194
  std::optional<uint16_t> decodedRequiredSubchannel;
195
+ std::optional<uint16_t> decodedIgnoredSubchannel;
123
196
 
124
197
  REQUIRE(
125
198
  RTC::SubchannelsCodec::DecodeSubchannels(
126
- message, decodedSubchannels, decodedRequiredSubchannel) == false);
199
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == false);
127
200
 
128
201
  REQUIRE(decodedSubchannels.empty() == true);
129
202
  REQUIRE(decodedRequiredSubchannel.has_value() == false);
203
+ REQUIRE(decodedIgnoredSubchannel.has_value() == false);
130
204
  REQUIRE(payloadToVector(message) == originalPayload);
131
205
  }
132
206
 
@@ -138,21 +212,23 @@ SCENARIO("SubchannelsCodec", "[subchannels]")
138
212
 
139
213
  std::vector<uint16_t> decodedSubchannels;
140
214
  std::optional<uint16_t> decodedRequiredSubchannel;
215
+ std::optional<uint16_t> decodedIgnoredSubchannel;
141
216
 
142
217
  REQUIRE(
143
218
  RTC::SubchannelsCodec::DecodeSubchannels(
144
- message, decodedSubchannels, decodedRequiredSubchannel) == false);
219
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == false);
145
220
 
146
221
  REQUIRE(decodedSubchannels.empty() == true);
147
222
  REQUIRE(decodedRequiredSubchannel.has_value() == false);
223
+ REQUIRE(decodedIgnoredSubchannel.has_value() == false);
148
224
  REQUIRE(payloadToVector(message) == originalPayload);
149
225
  }
150
226
 
151
227
  SECTION(
152
228
  "DecodeSubchannels() ignores a truncated message that announces more subchannels than present")
153
229
  {
154
- // Craft a payload with the Magic Token (no requiredSubchannelFlag) that
155
- // announces 3 subchannels but does not carry their bytes.
230
+ // Craft a payload with the Magic Token (no flags set) that announces 3
231
+ // subchannels but does not carry their bytes.
156
232
  std::vector<uint8_t> originalPayload(10);
157
233
 
158
234
  Utils::Byte::Set8Bytes(originalPayload.data(), 0, RTC::SubchannelsCodec::MagicToken);
@@ -162,13 +238,15 @@ SCENARIO("SubchannelsCodec", "[subchannels]")
162
238
 
163
239
  std::vector<uint16_t> decodedSubchannels;
164
240
  std::optional<uint16_t> decodedRequiredSubchannel;
241
+ std::optional<uint16_t> decodedIgnoredSubchannel;
165
242
 
166
243
  REQUIRE(
167
244
  RTC::SubchannelsCodec::DecodeSubchannels(
168
- message, decodedSubchannels, decodedRequiredSubchannel) == false);
245
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == false);
169
246
 
170
247
  REQUIRE(decodedSubchannels.empty() == true);
171
248
  REQUIRE(decodedRequiredSubchannel.has_value() == false);
249
+ REQUIRE(decodedIgnoredSubchannel.has_value() == false);
172
250
  REQUIRE(payloadToVector(message) == originalPayload);
173
251
  }
174
252
 
@@ -190,13 +268,73 @@ SCENARIO("SubchannelsCodec", "[subchannels]")
190
268
 
191
269
  std::vector<uint16_t> decodedSubchannels;
192
270
  std::optional<uint16_t> decodedRequiredSubchannel;
271
+ std::optional<uint16_t> decodedIgnoredSubchannel;
272
+
273
+ REQUIRE(
274
+ RTC::SubchannelsCodec::DecodeSubchannels(
275
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == false);
276
+
277
+ REQUIRE(decodedSubchannels.empty() == true);
278
+ REQUIRE(decodedRequiredSubchannel.has_value() == false);
279
+ REQUIRE(decodedIgnoredSubchannel.has_value() == false);
280
+ REQUIRE(payloadToVector(message) == originalPayload);
281
+ }
282
+
283
+ SECTION(
284
+ "DecodeSubchannels() ignores a message whose ignoredSubchannelFlag is set but has no room for the ignoredSubchannel field")
285
+ {
286
+ // Craft a payload with the Magic Token and ignoredSubchannelFlag set,
287
+ // announcing 1 subchannel (present) but without the ignoredSubchannel bytes.
288
+ std::vector<uint8_t> originalPayload(12);
289
+
290
+ Utils::Byte::Set8Bytes(
291
+ originalPayload.data(),
292
+ 0,
293
+ RTC::SubchannelsCodec::MagicToken | RTC::SubchannelsCodec::IgnoredSubchannelFlagMask);
294
+ Utils::Byte::Set2Bytes(originalPayload.data(), 8, /*subchannelsCount*/ 1);
295
+ Utils::Byte::Set2Bytes(originalPayload.data(), 10, /*subchannel*/ 42);
296
+
297
+ auto message = makeMessage(originalPayload);
298
+
299
+ std::vector<uint16_t> decodedSubchannels;
300
+ std::optional<uint16_t> decodedRequiredSubchannel;
301
+ std::optional<uint16_t> decodedIgnoredSubchannel;
302
+
303
+ REQUIRE(
304
+ RTC::SubchannelsCodec::DecodeSubchannels(
305
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == false);
306
+
307
+ REQUIRE(decodedSubchannels.empty() == true);
308
+ REQUIRE(decodedRequiredSubchannel.has_value() == false);
309
+ REQUIRE(decodedIgnoredSubchannel.has_value() == false);
310
+ REQUIRE(payloadToVector(message) == originalPayload);
311
+ }
312
+
313
+ SECTION(
314
+ "DecodeSubchannels() ignores a message with both flags set but room for just one of the fields")
315
+ {
316
+ // Craft a payload with the Magic Token and both flags set, announcing no
317
+ // subchannels but carrying just 2 bytes after the header.
318
+ std::vector<uint8_t> originalPayload(12);
319
+
320
+ Utils::Byte::Set8Bytes(
321
+ originalPayload.data(), 0, RTC::SubchannelsCodec::MagicToken | RTC::SubchannelsCodec::FlagsMask);
322
+ Utils::Byte::Set2Bytes(originalPayload.data(), 8, /*subchannelsCount*/ 0);
323
+ Utils::Byte::Set2Bytes(originalPayload.data(), 10, /*requiredSubchannel*/ 42);
324
+
325
+ auto message = makeMessage(originalPayload);
326
+
327
+ std::vector<uint16_t> decodedSubchannels;
328
+ std::optional<uint16_t> decodedRequiredSubchannel;
329
+ std::optional<uint16_t> decodedIgnoredSubchannel;
193
330
 
194
331
  REQUIRE(
195
332
  RTC::SubchannelsCodec::DecodeSubchannels(
196
- message, decodedSubchannels, decodedRequiredSubchannel) == false);
333
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == false);
197
334
 
198
335
  REQUIRE(decodedSubchannels.empty() == true);
199
336
  REQUIRE(decodedRequiredSubchannel.has_value() == false);
337
+ REQUIRE(decodedIgnoredSubchannel.has_value() == false);
200
338
  REQUIRE(payloadToVector(message) == originalPayload);
201
339
  }
202
340
 
@@ -206,19 +344,23 @@ SCENARIO("SubchannelsCodec", "[subchannels]")
206
344
 
207
345
  const std::vector<uint16_t> subchannels = { 7 };
208
346
  const std::optional<uint16_t> requiredSubchannel = 7;
347
+ const std::optional<uint16_t> ignoredSubchannel = 8;
209
348
 
210
349
  REQUIRE(
211
- RTC::SubchannelsCodec::EncodeSubchannels(message, subchannels, requiredSubchannel) == true);
350
+ RTC::SubchannelsCodec::EncodeSubchannels(
351
+ message, subchannels, requiredSubchannel, ignoredSubchannel) == true);
212
352
 
213
353
  std::vector<uint16_t> decodedSubchannels;
214
354
  std::optional<uint16_t> decodedRequiredSubchannel;
355
+ std::optional<uint16_t> decodedIgnoredSubchannel;
215
356
 
216
357
  REQUIRE(
217
358
  RTC::SubchannelsCodec::DecodeSubchannels(
218
- message, decodedSubchannels, decodedRequiredSubchannel) == true);
359
+ message, decodedSubchannels, decodedRequiredSubchannel, decodedIgnoredSubchannel) == true);
219
360
 
220
361
  REQUIRE(decodedSubchannels == subchannels);
221
362
  REQUIRE(decodedRequiredSubchannel == requiredSubchannel);
363
+ REQUIRE(decodedIgnoredSubchannel == ignoredSubchannel);
222
364
  REQUIRE(message.GetPayloadLength() == 0);
223
365
  }
224
366
  }