mediasoup 3.21.2 → 3.22.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ### NEXT
4
4
 
5
+ ### 3.22.0
6
+
7
+ - SCTP: Encode subchannels in SCTP messages to enable subchannels mechanism when using pipe transport ([PR #1859](https://github.com/versatica/mediasoup/pull/1859)).
8
+
5
9
  ### 3.21.2
6
10
 
7
11
  - Worker: Fix crash when an SCTP `DataConsumer` is closed and triggers buffered amount low event ([PR #1858](https://github.com/versatica/mediasoup/pull/1858)).
@@ -1,6 +1,6 @@
1
1
  import { EnhancedEventEmitter } from './enhancedEvents';
2
2
  import type { Channel } from './Channel';
3
- import type { Router, PipeToRouterOptions, PipeToRouterResult, PipeTransportPair, RouterDump, RouterEvents, RouterObserver } from './RouterTypes';
3
+ import type { Router, PipeToRouterOptions, PipeToRouterResult, RouterDump, RouterEvents, RouterObserver } from './RouterTypes';
4
4
  import type { Transport } from './TransportTypes';
5
5
  import type { WebRtcTransport, WebRtcTransportOptions } from './WebRtcTransportTypes';
6
6
  import type { PlainTransport, PlainTransportOptions } from './PlainTransportTypes';
@@ -44,7 +44,6 @@ export declare class RouterImpl<RouterAppData extends AppData = AppData> extends
44
44
  createPipeTransport<PipeTransportAppData extends AppData = AppData>({ listenInfo, listenIp, port, enableSctp, maxSendMessageSize, maxReceiveMessageSize, sctpSendBufferSize, sctpPerStreamSendQueueLimit, sctpMaxReceiverWindowBufferSize, enableRtx, enableSrtp, appData, }: PipeTransportOptions<PipeTransportAppData>): Promise<PipeTransport<PipeTransportAppData>>;
45
45
  createDirectTransport<DirectTransportAppData extends AppData = AppData>({ maxSendMessageSize, maxReceiveMessageSize, appData, }?: DirectTransportOptions<DirectTransportAppData>): Promise<DirectTransport<DirectTransportAppData>>;
46
46
  pipeToRouter({ producerId, dataProducerId, router, keepId, listenInfo, listenIp, enableSctp, maxSendMessageSize, maxReceiveMessageSize, sctpSendBufferSize, sctpPerStreamSendQueueLimit, sctpMaxReceiverWindowBufferSize, enableRtx, enableSrtp, }: PipeToRouterOptions): Promise<PipeToRouterResult>;
47
- addPipeTransportPair(pipeTransportPairKey: string, pipeTransportPairPromise: Promise<PipeTransportPair>): void;
48
47
  createActiveSpeakerObserver<ActiveSpeakerObserverAppData extends AppData = AppData>({ interval, appData, }?: ActiveSpeakerObserverOptions<ActiveSpeakerObserverAppData>): Promise<ActiveSpeakerObserver<ActiveSpeakerObserverAppData>>;
49
48
  createAudioLevelObserver<AudioLevelObserverAppData extends AppData = AppData>({ maxEntries, threshold, interval, appData, }?: AudioLevelObserverOptions<AudioLevelObserverAppData>): Promise<AudioLevelObserver<AudioLevelObserverAppData>>;
50
49
  canConsume({ producerId, rtpCapabilities, }: {
@@ -52,6 +51,7 @@ export declare class RouterImpl<RouterAppData extends AppData = AppData> extends
52
51
  rtpCapabilities: RtpCapabilities;
53
52
  }): boolean;
54
53
  updateMediaCodecs(mediaCodecs: RouterRtpCodecCapability[]): void;
54
+ private addPipeTransportPair;
55
55
  private handleListenerError;
56
56
  }
57
57
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"Router.d.ts","sourceRoot":"","sources":["../src/Router.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Router.d.ts","sourceRoot":"","sources":["../src/Router.ts"],"names":[],"mappings":"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"}
@@ -694,24 +694,6 @@ class RouterImpl extends enhancedEvents_1.EnhancedEventEmitter {
694
694
  throw new Error('internal error');
695
695
  }
696
696
  }
697
- addPipeTransportPair(pipeTransportPairKey, pipeTransportPairPromise) {
698
- if (this.#mapRouterPairPipeTransportPairPromise.has(pipeTransportPairKey)) {
699
- throw new Error('given pipeTransportPairKey already exists in this Router');
700
- }
701
- this.#mapRouterPairPipeTransportPairPromise.set(pipeTransportPairKey, pipeTransportPairPromise);
702
- pipeTransportPairPromise
703
- .then(pipeTransportPair => {
704
- const localPipeTransport = pipeTransportPair[this.id];
705
- // NOTE: No need to do any other cleanup here since that is done by the
706
- // Router calling this method on us.
707
- localPipeTransport.observer.on('close', () => {
708
- this.#mapRouterPairPipeTransportPairPromise.delete(pipeTransportPairKey);
709
- });
710
- })
711
- .catch(() => {
712
- this.#mapRouterPairPipeTransportPairPromise.delete(pipeTransportPairKey);
713
- });
714
- }
715
697
  async createActiveSpeakerObserver({ interval = 300, appData, } = {}) {
716
698
  logger.debug('createActiveSpeakerObserver()');
717
699
  if (typeof interval !== 'number') {
@@ -804,6 +786,24 @@ class RouterImpl extends enhancedEvents_1.EnhancedEventEmitter {
804
786
  const rtpCapabilities = ortc.generateRouterRtpCapabilities(clonedMediaCodecs);
805
787
  this.#data.rtpCapabilities = rtpCapabilities;
806
788
  }
789
+ addPipeTransportPair(pipeTransportPairKey, pipeTransportPairPromise) {
790
+ if (this.#mapRouterPairPipeTransportPairPromise.has(pipeTransportPairKey)) {
791
+ throw new Error('given pipeTransportPairKey already exists in this Router');
792
+ }
793
+ this.#mapRouterPairPipeTransportPairPromise.set(pipeTransportPairKey, pipeTransportPairPromise);
794
+ pipeTransportPairPromise
795
+ .then(pipeTransportPair => {
796
+ const localPipeTransport = pipeTransportPair[this.id];
797
+ // NOTE: No need to do any other cleanup here since that is done by the
798
+ // Router calling this method on us.
799
+ localPipeTransport.observer.on('close', () => {
800
+ this.#mapRouterPairPipeTransportPairPromise.delete(pipeTransportPairKey);
801
+ });
802
+ })
803
+ .catch(() => {
804
+ this.#mapRouterPairPipeTransportPairPromise.delete(pipeTransportPairKey);
805
+ });
806
+ }
807
807
  handleListenerError() {
808
808
  this.on('listenererror', (eventName, error) => {
809
809
  logger.error(`event listener threw an error [eventName:${eventName}]:`, error);
@@ -234,10 +234,6 @@ export interface Router<RouterAppData extends AppData = AppData> extends Enhance
234
234
  * Pipes the given Producer or DataProducer into another Router in same host.
235
235
  */
236
236
  pipeToRouter(options: PipeToRouterOptions): Promise<PipeToRouterResult>;
237
- /**
238
- * @private
239
- */
240
- addPipeTransportPair(pipeTransportPairKey: string, pipeTransportPairPromise: Promise<PipeTransportPair>): void;
241
237
  /**
242
238
  * Create an ActiveSpeakerObserver
243
239
  */
@@ -1 +1 @@
1
- {"version":3,"file":"RouterTypes.d.ts","sourceRoot":"","sources":["../src/RouterTypes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RouterTypes.d.ts","sourceRoot":"","sources":["../src/RouterTypes.ts"],"names":[],"mappings":"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"}
@@ -901,7 +901,7 @@ test('router.pipeToRouter() succeeds with data', async () => {
901
901
  expect(pipeDataProducer.label).toBe('foo');
902
902
  expect(pipeDataProducer.protocol).toBe('bar');
903
903
  }, 2000);
904
- test('transport.dataConsume() for a pipe DataProducer succeeds', async () => {
904
+ test('transport.consumeData() for a pipe DataProducer succeeds', async () => {
905
905
  const { pipeDataProducer } = await ctx.router1.pipeToRouter({
906
906
  dataProducerId: ctx.dataProducer.id,
907
907
  router: ctx.router2,
@@ -920,6 +920,38 @@ test('transport.dataConsume() for a pipe DataProducer succeeds', async () => {
920
920
  expect(dataConsumer.label).toBe('foo');
921
921
  expect(dataConsumer.protocol).toBe('bar');
922
922
  }, 2000);
923
+ test('transport.consumeData() for a pipe DataProducer succeeds with subchannels', async () => {
924
+ const directTransport1 = await ctx.router1.createDirectTransport();
925
+ const directDataProducer = await directTransport1.produceData({
926
+ label: 'foo',
927
+ protocol: 'bar',
928
+ });
929
+ await ctx.router1.pipeToRouter({
930
+ dataProducerId: directDataProducer.id,
931
+ router: ctx.router2,
932
+ });
933
+ const directTransport2 = await ctx.router2.createDirectTransport();
934
+ const directDataConsumer = await directTransport2.consumeData({
935
+ dataProducerId: directDataProducer.id,
936
+ subchannels: [123, 666],
937
+ });
938
+ await new Promise((resolve, reject) => {
939
+ directDataConsumer.on('message', (message, ppid) => {
940
+ try {
941
+ expect(message.toString('utf8')).toBe('hello');
942
+ expect(ppid).toBe(51);
943
+ resolve();
944
+ }
945
+ catch (error) {
946
+ reject(error);
947
+ }
948
+ });
949
+ directDataProducer.send('hello',
950
+ /* ppid */ undefined,
951
+ /* subchannels */ [123, 124],
952
+ /* requiredSubchannel */ 666);
953
+ });
954
+ }, 2000);
923
955
  test('dataProducer.close() is transmitted to pipe DataConsumer', async () => {
924
956
  const { pipeDataProducer } = await ctx.router1.pipeToRouter({
925
957
  dataProducerId: ctx.dataProducer.id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mediasoup",
3
- "version": "3.21.2",
3
+ "version": "3.22.0",
4
4
  "description": "Cutting Edge WebRTC Video Conferencing",
5
5
  "contributors": [
6
6
  "Iñaki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)",
@@ -49,7 +49,8 @@ namespace RTC
49
49
  const std::string& dataProducerId,
50
50
  RTC::DataConsumer::Listener* listener,
51
51
  const FBS::Transport::ConsumeDataRequest* data,
52
- size_t maxMessageSize);
52
+ size_t maxMessageSize,
53
+ bool pipe);
53
54
  ~DataConsumer() override;
54
55
 
55
56
  public:
@@ -67,20 +68,17 @@ namespace RTC
67
68
  }
68
69
  bool IsActive() const
69
70
  {
70
- // It's active it DataConsumer and DataProducer are not paused and the transport
71
- // is connected.
71
+ // It's active it DataConsumer and DataProducer are not paused and the SCTP
72
+ // association (if any) is not closed.
72
73
  // clang-format off
73
74
  return (
74
- this->transportConnected &&
75
- (this->type == DataConsumer::Type::DIRECT || this->sctpAssociationConnected) &&
75
+ (this->type == DataConsumer::Type::DIRECT || !this->sctpAssociationClosed) &&
76
76
  !this->paused &&
77
77
  !this->dataProducerPaused &&
78
78
  !this->dataProducerClosed
79
79
  );
80
80
  // clang-format on
81
81
  }
82
- void TransportConnected();
83
- void TransportDisconnected();
84
82
  bool IsPaused() const
85
83
  {
86
84
  return this->paused;
@@ -91,7 +89,6 @@ namespace RTC
91
89
  }
92
90
  void DataProducerPaused();
93
91
  void DataProducerResumed();
94
- void SctpAssociationConnected();
95
92
  void SctpAssociationClosed();
96
93
  void SctpBufferedAmountLow(uint32_t bufferedAmount) const;
97
94
  void SctpSendBufferFull() const;
@@ -116,14 +113,14 @@ namespace RTC
116
113
  SharedInterface* shared{ nullptr };
117
114
  RTC::DataConsumer::Listener* listener{ nullptr };
118
115
  size_t maxMessageSize{ 0u };
116
+ bool pipe{ false };
119
117
  // Others.
120
118
  Type type;
121
119
  RTC::SctpStreamParameters sctpStreamParameters;
122
120
  std::string label;
123
121
  std::string protocol;
124
122
  ankerl::unordered_dense::set<uint16_t> subchannels;
125
- bool transportConnected{ false };
126
- bool sctpAssociationConnected{ false };
123
+ bool sctpAssociationClosed{ false };
127
124
  bool paused{ false };
128
125
  bool dataProducerPaused{ false };
129
126
  bool dataProducerClosed{ false };
@@ -41,6 +41,10 @@ namespace RTC
41
41
 
42
42
  private:
43
43
  bool IsConnected() const override;
44
+ bool IsPipe() const override
45
+ {
46
+ return true;
47
+ }
44
48
  bool HasSrtp() const;
45
49
  void SendRtpPacket(
46
50
  RTC::Consumer* consumer,
@@ -68,6 +68,22 @@ namespace RTC
68
68
  return this->payload.size();
69
69
  }
70
70
 
71
+ /**
72
+ * Replace the whole payload of the message.
73
+ */
74
+ void SetPayload(std::vector<uint8_t> payload)
75
+ {
76
+ this->payload = std::move(payload);
77
+ }
78
+
79
+ /**
80
+ * Remove the first `len` bytes from the beginning of the payload.
81
+ */
82
+ void RemovePayloadFront(size_t len)
83
+ {
84
+ this->payload.erase(this->payload.begin(), this->payload.begin() + len);
85
+ }
86
+
71
87
  /**
72
88
  * Useful to extract the payload and its ownership when destructing the
73
89
  * message.
@@ -0,0 +1,76 @@
1
+ #ifndef MS_RTC_SUBCHANNELS_CODEC_HPP
2
+ #define MS_RTC_SUBCHANNELS_CODEC_HPP
3
+
4
+ #include "common.hpp"
5
+ #include "RTC/SCTP/public/Message.hpp"
6
+ #include <vector>
7
+
8
+ namespace RTC
9
+ {
10
+ /**
11
+ * Helper to (optionally) encode/decode subchannels and required subchannel at
12
+ * the beginning of an SCTP message payload so that this information travels
13
+ * within the SCTP message itself.
14
+ */
15
+ class SubchannelsCodec
16
+ {
17
+ /**
18
+ * Wire layout of the encoded header prepended to the message payload (all
19
+ * fields in network byte order). `R` is the `requiredSubchannelFlag`, i.e.
20
+ * the least significant bit of the Magic Token. The `requiredSubchannel`
21
+ * field is only present when `R` is 1.
22
+ *
23
+ * 0 1 2 3
24
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
25
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26
+ * | Magic Token (1/2) |
27
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28
+ * | Magic Token (2/2) |R|
29
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30
+ * | subchannelsCount | Subchannel 0 |
31
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32
+ * | ... |
33
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34
+ * | Subchannel N-1 | requiredSubchannel (if R=1) |
35
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36
+ */
37
+
38
+ public:
39
+ /**
40
+ * 8-byte Magic Token that prefixes an encoded payload. It is intentionally
41
+ * made of non-printable high bytes and starts with a byte that is not a valid
42
+ * UTF-8 leading byte (0x80-0xBF), so a real string message (valid UTF-8) can
43
+ * never begin with it and the chance of colliding with a binary message is
44
+ * negligible. Its least significant bit is reserved as the
45
+ * `requiredSubchannelFlag`, so it is always 0 in the token constant itself.
46
+ */
47
+ static constexpr uint64_t MagicToken{ 0xA5F09CB3D6E1F28C };
48
+ static constexpr uint64_t RequiredSubchannelFlagMask{ 0x1 };
49
+
50
+ public:
51
+ /**
52
+ * If `subchannels` is not empty or `requiredSubchannel` has value, encodes
53
+ * them at the beginning of the given message payload.
54
+ *
55
+ * @returns true if the message was encoded, false otherwise.
56
+ */
57
+ static bool EncodeSubchannels(
58
+ RTC::SCTP::Message& message,
59
+ const std::vector<uint16_t>& subchannels,
60
+ std::optional<uint16_t> requiredSubchannel);
61
+
62
+ /**
63
+ * If the given message payload starts with the Magic Token, extracts the
64
+ * encoded subchannels and (optionally) the required subchannel, fills the
65
+ * given arguments and removes the encoded header from the message payload.
66
+ *
67
+ * @returns true if the message was successfully decoded, false otherwise.
68
+ */
69
+ static bool DecodeSubchannels(
70
+ RTC::SCTP::Message& message,
71
+ std::vector<uint16_t>& subchannels,
72
+ std::optional<uint16_t>& requiredSubchannel);
73
+ };
74
+ } // namespace RTC
75
+
76
+ #endif
@@ -219,6 +219,10 @@ namespace RTC
219
219
  const std::string& dataConsumerId, const std::string& method) const final;
220
220
  virtual void CheckNoSctpDataConsumer(uint16_t streamId, const std::string& method) const final;
221
221
  virtual bool IsConnected() const = 0;
222
+ virtual bool IsPipe() const
223
+ {
224
+ return false;
225
+ }
222
226
  virtual void SendRtpPacket(
223
227
  RTC::Consumer* consumer, RTC::RTP::Packet* packet, const onSendCallback* cb = nullptr) = 0;
224
228
  virtual void HandleRtcpPacket(RTC::RTCP::Packet* packet) final;
@@ -136,6 +136,7 @@ common_sources = [
136
136
  'src/RTC/SimpleProducerStreamManager.cpp',
137
137
  'src/RTC/SimulcastProducerStreamManager.cpp',
138
138
  'src/RTC/SrtpSession.cpp',
139
+ 'src/RTC/SubchannelsCodec.cpp',
139
140
  'src/RTC/SvcProducerStreamManager.cpp',
140
141
  'src/RTC/TcpConnection.cpp',
141
142
  'src/RTC/TcpServer.cpp',
@@ -430,6 +431,7 @@ test_sources = [
430
431
  'test/src/RTC/TestRateCalculator.cpp',
431
432
  'test/src/RTC/TestRtpEncodingParameters.cpp',
432
433
  'test/src/RTC/TestSeqManager.cpp',
434
+ 'test/src/RTC/TestSubchannelsCodec.cpp',
433
435
  'test/src/RTC/TestTransportCongestionControlServer.cpp',
434
436
  'test/src/RTC/TestTransportTuple.cpp',
435
437
  'test/src/RTC/TestTrendCalculator.cpp',
@@ -21,9 +21,10 @@
21
21
  }
22
22
  },
23
23
  "node_modules/brace-expansion": {
24
- "version": "5.0.6",
25
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
26
- "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
24
+ "version": "5.0.7",
25
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
26
+ "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
27
+ "license": "MIT",
27
28
  "dependencies": {
28
29
  "balanced-match": "^4.0.2"
29
30
  },
@@ -104,9 +105,9 @@
104
105
  "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="
105
106
  },
106
107
  "brace-expansion": {
107
- "version": "5.0.6",
108
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
109
- "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
108
+ "version": "5.0.7",
109
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
110
+ "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
110
111
  "requires": {
111
112
  "balanced-match": "^4.0.2"
112
113
  }
@@ -4,6 +4,7 @@
4
4
  #include "RTC/DataConsumer.hpp"
5
5
  #include "Logger.hpp"
6
6
  #include "MediaSoupErrors.hpp"
7
+ #include "RTC/SubchannelsCodec.hpp"
7
8
 
8
9
  namespace RTC
9
10
  {
@@ -15,12 +16,14 @@ namespace RTC
15
16
  const std::string& dataProducerId,
16
17
  RTC::DataConsumer::Listener* listener,
17
18
  const FBS::Transport::ConsumeDataRequest* data,
18
- size_t maxMessageSize)
19
+ size_t maxMessageSize,
20
+ bool pipe)
19
21
  : id(id),
20
22
  dataProducerId(dataProducerId),
21
23
  shared(shared),
22
24
  listener(listener),
23
- maxMessageSize(maxMessageSize)
25
+ maxMessageSize(maxMessageSize),
26
+ pipe(pipe)
24
27
  {
25
28
  MS_TRACE();
26
29
 
@@ -398,24 +401,6 @@ namespace RTC
398
401
  }
399
402
  }
400
403
 
401
- void DataConsumer::TransportConnected()
402
- {
403
- MS_TRACE();
404
-
405
- this->transportConnected = true;
406
-
407
- MS_DEBUG_DEV("Transport connected [dataConsumerId:%s]", this->id.c_str());
408
- }
409
-
410
- void DataConsumer::TransportDisconnected()
411
- {
412
- MS_TRACE();
413
-
414
- this->transportConnected = false;
415
-
416
- MS_DEBUG_DEV("Transport disconnected [dataConsumerId:%s]", this->id.c_str());
417
- }
418
-
419
404
  void DataConsumer::DataProducerPaused()
420
405
  {
421
406
  MS_TRACE();
@@ -450,22 +435,11 @@ namespace RTC
450
435
  this->id, FBS::Notification::Event::DATACONSUMER_DATAPRODUCER_RESUME);
451
436
  }
452
437
 
453
- void DataConsumer::SctpAssociationConnected()
454
- {
455
- MS_TRACE();
456
-
457
- this->sctpAssociationConnected = true;
458
-
459
- MS_DEBUG_DEV("SctpAssociation connected [dataConsumerId:%s]", this->id.c_str());
460
- }
461
-
462
438
  void DataConsumer::SctpAssociationClosed()
463
439
  {
464
440
  MS_TRACE();
465
441
 
466
- this->sctpAssociationConnected = false;
467
-
468
- MS_DEBUG_DEV("SctpAssociation closed [dataConsumerId:%s]", this->id.c_str());
442
+ this->sctpAssociationClosed = true;
469
443
  }
470
444
 
471
445
  void DataConsumer::SctpBufferedAmountLow(uint32_t bufferedAmount) const
@@ -526,48 +500,57 @@ namespace RTC
526
500
  return false;
527
501
  }
528
502
 
529
- // If a required subchannel is given, verify that this data consumer is
530
- // subscribed to it.
531
- if (
532
- requiredSubchannel.has_value() &&
533
- this->subchannels.find(requiredSubchannel.value()) == this->subchannels.end())
503
+ if (!this->pipe)
534
504
  {
535
- if (cb)
505
+ // If a required subchannel is given, verify that this data consumer is
506
+ // subscribed to it.
507
+ if (requiredSubchannel.has_value() && !this->subchannels.contains(requiredSubchannel.value()))
536
508
  {
537
- (*cb)(false, false);
538
- delete cb;
539
- }
540
-
541
- return false;
542
- }
509
+ if (cb)
510
+ {
511
+ (*cb)(false, false);
512
+ delete cb;
513
+ }
543
514
 
544
- // If subchannels are given, verify that this data consumer is subscribed
545
- // to at least one of them.
546
- if (!subchannels.empty())
547
- {
548
- bool subchannelMatched{ false };
515
+ return false;
516
+ }
549
517
 
550
- for (const auto subchannel : subchannels)
518
+ // If subchannels are given, verify that this data consumer is subscribed
519
+ // to at least one of them.
520
+ if (!subchannels.empty())
551
521
  {
552
- if (this->subchannels.find(subchannel) != this->subchannels.end())
522
+ bool subchannelMatched{ false };
523
+
524
+ for (const auto subchannel : subchannels)
553
525
  {
554
- subchannelMatched = true;
526
+ if (this->subchannels.contains(subchannel))
527
+ {
528
+ subchannelMatched = true;
555
529
 
556
- break;
530
+ break;
531
+ }
557
532
  }
558
- }
559
533
 
560
- if (!subchannelMatched)
561
- {
562
- if (cb)
534
+ if (!subchannelMatched)
563
535
  {
564
- (*cb)(false, false);
565
- delete cb;
566
- }
536
+ if (cb)
537
+ {
538
+ (*cb)(false, false);
539
+ delete cb;
540
+ }
567
541
 
568
- return false;
542
+ return false;
543
+ }
569
544
  }
570
545
  }
546
+ // This is a piped DataConsumer, so instead of verifying subchannels locally,
547
+ // encode the subchannels and required subchannel at the beginning of the
548
+ // message payload so the receiving PipeTransport can decode them and apply
549
+ // them to its own DataConsumers.
550
+ else
551
+ {
552
+ RTC::SubchannelsCodec::EncodeSubchannels(message, subchannels, requiredSubchannel);
553
+ }
571
554
 
572
555
  const size_t messageLen = message.GetPayloadLength();
573
556
 
@@ -575,7 +558,7 @@ namespace RTC
575
558
  {
576
559
  MS_WARN_TAG(
577
560
  message,
578
- "given message exceeds maxMessageSize value [maxMessageSize:%zu, len:%zu]",
561
+ "message exceeds maxMessageSize value [maxMessageSize:%zu, len:%zu]",
579
562
  messageLen,
580
563
  this->maxMessageSize);
581
564
 
@@ -0,0 +1,153 @@
1
+ #define MS_CLASS "RTC::SubchannelsCodec"
2
+ // #define MS_LOG_DEV_LEVEL 3
3
+
4
+ #include "RTC/SubchannelsCodec.hpp"
5
+ #include "Logger.hpp"
6
+ #include "Utils.hpp"
7
+
8
+ namespace RTC
9
+ {
10
+ /* Class methods. */
11
+
12
+ bool SubchannelsCodec::EncodeSubchannels(
13
+ RTC::SCTP::Message& message,
14
+ const std::vector<uint16_t>& subchannels,
15
+ std::optional<uint16_t> requiredSubchannel)
16
+ {
17
+ MS_TRACE();
18
+
19
+ // Nothing to encode.
20
+ if (subchannels.empty() && !requiredSubchannel.has_value())
21
+ {
22
+ return false;
23
+ }
24
+
25
+ if (subchannels.size() > 0xFFFF)
26
+ {
27
+ MS_ERROR("too many subchannels to encode [count:%zu]", subchannels.size());
28
+
29
+ return false;
30
+ }
31
+
32
+ const auto subchannelsCount = static_cast<uint16_t>(subchannels.size());
33
+ const bool requiredSubchannelFlag = requiredSubchannel.has_value();
34
+
35
+ // Length of the header to prepend.
36
+ size_t headerLen =
37
+ 8 /* Magic Token */ + 2 /* subchannelsCount */ + (static_cast<size_t>(subchannelsCount) * 2);
38
+
39
+ if (requiredSubchannelFlag)
40
+ {
41
+ headerLen += 2;
42
+ }
43
+
44
+ const auto payload = message.GetPayload();
45
+
46
+ // Build the whole new payload at once (header followed by the original
47
+ // payload) so it can be moved into the message with a single allocation.
48
+ std::vector<uint8_t> newPayload(headerLen + payload.size());
49
+
50
+ uint64_t magicToken = SubchannelsCodec::MagicToken;
51
+
52
+ if (requiredSubchannelFlag)
53
+ {
54
+ magicToken |= SubchannelsCodec::RequiredSubchannelFlagMask;
55
+ }
56
+
57
+ size_t offset = 0;
58
+
59
+ Utils::Byte::Set8Bytes(newPayload.data(), offset, magicToken);
60
+ offset += 8;
61
+
62
+ Utils::Byte::Set2Bytes(newPayload.data(), offset, subchannelsCount);
63
+ offset += 2;
64
+
65
+ for (const auto subchannel : subchannels)
66
+ {
67
+ Utils::Byte::Set2Bytes(newPayload.data(), offset, subchannel);
68
+ offset += 2;
69
+ }
70
+
71
+ if (requiredSubchannelFlag)
72
+ {
73
+ Utils::Byte::Set2Bytes(newPayload.data(), offset, requiredSubchannel.value());
74
+ offset += 2;
75
+ }
76
+
77
+ // Append the original payload right after the encoded header.
78
+ std::ranges::copy(payload, newPayload.begin() + offset);
79
+
80
+ message.SetPayload(std::move(newPayload));
81
+
82
+ return true;
83
+ }
84
+
85
+ bool SubchannelsCodec::DecodeSubchannels(
86
+ RTC::SCTP::Message& message,
87
+ std::vector<uint16_t>& subchannels,
88
+ std::optional<uint16_t>& requiredSubchannel)
89
+ {
90
+ MS_TRACE();
91
+
92
+ const auto payload = message.GetPayload();
93
+ const size_t len = payload.size();
94
+
95
+ // Not even enough bytes to hold the Magic Token and `subchannelsCount` field,
96
+ // so nothing to decode.
97
+ if (len < 10)
98
+ {
99
+ return false;
100
+ }
101
+
102
+ const uint64_t magicToken = Utils::Byte::Get8Bytes(payload.data(), 0);
103
+
104
+ // The message does not start with the Magic Token, so nothing to decode.
105
+ if ((magicToken & ~SubchannelsCodec::RequiredSubchannelFlagMask) != SubchannelsCodec::MagicToken)
106
+ {
107
+ return false;
108
+ }
109
+
110
+ const bool requiredSubchannelFlag =
111
+ (magicToken & SubchannelsCodec::RequiredSubchannelFlagMask) != 0;
112
+
113
+ const uint16_t subchannelsCount = Utils::Byte::Get2Bytes(payload.data(), 8);
114
+
115
+ // Offset right after the Magic Token and subchannelsCount fields.
116
+ size_t offset = 10;
117
+
118
+ // Bytes needed to hold all announced subchannels and, if present, the
119
+ // requiredSubchannel.
120
+ size_t neededLen = offset + (static_cast<size_t>(subchannelsCount) * 2);
121
+
122
+ if (requiredSubchannelFlag)
123
+ {
124
+ neededLen += 2;
125
+ }
126
+
127
+ if (len < neededLen)
128
+ {
129
+ MS_WARN_DEV("message too short to hold announced subchannels, ignoring");
130
+
131
+ return false;
132
+ }
133
+
134
+ subchannels.reserve(subchannelsCount);
135
+
136
+ for (uint16_t i = 0; i < subchannelsCount; ++i)
137
+ {
138
+ subchannels.push_back(Utils::Byte::Get2Bytes(payload.data(), offset));
139
+ offset += 2;
140
+ }
141
+
142
+ if (requiredSubchannelFlag)
143
+ {
144
+ requiredSubchannel = Utils::Byte::Get2Bytes(payload.data(), offset);
145
+ offset += 2;
146
+ }
147
+
148
+ // Remove the decoded header from the beginning of the message payload.
149
+ message.RemovePayloadFront(offset);
150
+
151
+ return true;
152
+ }
153
+ } // namespace RTC
@@ -18,6 +18,7 @@
18
18
  #include "RTC/RtpDictionaries.hpp"
19
19
  #include "RTC/SCTP/association/Association.hpp"
20
20
  #include "RTC/SCTP/public/SctpOptions.hpp"
21
+ #include "RTC/SubchannelsCodec.hpp"
21
22
  #include "Utils.hpp"
22
23
  #ifdef MS_RTC_LOGGER_RTP
23
24
  #include "RTC/RtcLogger.hpp"
@@ -1111,7 +1112,13 @@ namespace RTC
1111
1112
 
1112
1113
  // This may throw.
1113
1114
  auto* dataConsumer = new RTC::DataConsumer(
1114
- this->shared, dataConsumerId, dataProducerId, this, body, this->maxSendMessageSize);
1115
+ this->shared,
1116
+ dataConsumerId,
1117
+ dataProducerId,
1118
+ this,
1119
+ body,
1120
+ this->maxSendMessageSize,
1121
+ this->IsPipe());
1115
1122
 
1116
1123
  // Verify the type of the DataConsumer.
1117
1124
  switch (dataConsumer->GetType())
@@ -1189,19 +1196,8 @@ namespace RTC
1189
1196
 
1190
1197
  request->Accept(FBS::Response::Body::DataConsumer_DumpResponse, dumpOffset);
1191
1198
 
1192
- if (IsConnected())
1193
- {
1194
- dataConsumer->TransportConnected();
1195
- }
1196
-
1197
1199
  if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP)
1198
1200
  {
1199
- if (this->sctpAssociation->GetAssociationState() == RTC::SCTP::Types::AssociationState::CONNECTED)
1200
- {
1201
- // Tell to the DataConsumer.
1202
- dataConsumer->SctpAssociationConnected();
1203
- }
1204
-
1205
1201
  // Tell to the SCTP association.
1206
1202
  this->sctpAssociation->MayConnect();
1207
1203
  }
@@ -1480,14 +1476,6 @@ namespace RTC
1480
1476
  consumer->TransportConnected();
1481
1477
  }
1482
1478
 
1483
- // Tell all DataConsumers.
1484
- for (auto& kv : this->mapDataConsumers)
1485
- {
1486
- auto* dataConsumer = kv.second;
1487
-
1488
- dataConsumer->TransportConnected();
1489
- }
1490
-
1491
1479
  // Tell the SctpAssociation.
1492
1480
  if (this->sctpAssociation)
1493
1481
  {
@@ -1530,14 +1518,6 @@ namespace RTC
1530
1518
  consumer->TransportDisconnected();
1531
1519
  }
1532
1520
 
1533
- // Tell all DataConsumers.
1534
- for (auto& kv : this->mapDataConsumers)
1535
- {
1536
- auto* dataConsumer = kv.second;
1537
-
1538
- dataConsumer->TransportDisconnected();
1539
- }
1540
-
1541
1521
  // Stop the RTCP timer.
1542
1522
  this->rtcpTimer->Stop();
1543
1523
 
@@ -2999,17 +2979,6 @@ namespace RTC
2999
2979
  {
3000
2980
  MS_TRACE();
3001
2981
 
3002
- // Tell all DataConsumers.
3003
- for (auto& kv : this->mapDataConsumers)
3004
- {
3005
- auto* dataConsumer = kv.second;
3006
-
3007
- if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP)
3008
- {
3009
- dataConsumer->SctpAssociationConnected();
3010
- }
3011
- }
3012
-
3013
2982
  // Notify the upper layer.
3014
2983
 
3015
2984
  // First tell it about the SCTP negotiated capabilities.
@@ -3041,7 +3010,7 @@ namespace RTC
3041
3010
 
3042
3011
  // For debugging purposes.
3043
3012
  #if MS_LOG_DEV_LEVEL == 3
3044
- MS_DUMP("--- SCTP association connected:");
3013
+ MS_DUMP("SCTP association connected:");
3045
3014
  this->sctpAssociation->Dump();
3046
3015
  #endif
3047
3016
  }
@@ -3187,10 +3156,17 @@ namespace RTC
3187
3156
  // Pass the SCTP message to the corresponding DataProducer.
3188
3157
  try
3189
3158
  {
3190
- static thread_local std::vector<uint16_t> emptySubchannels;
3159
+ std::vector<uint16_t> subchannels;
3160
+ std::optional<uint16_t> requiredSubchannel;
3161
+
3162
+ // When this is a pipe transport, the subchannels and required subchannel
3163
+ // may be encoded at the beginning of the message payload.
3164
+ if (this->IsPipe())
3165
+ {
3166
+ RTC::SubchannelsCodec::DecodeSubchannels(message, subchannels, requiredSubchannel);
3167
+ }
3191
3168
 
3192
- dataProducer->ReceiveMessage(
3193
- std::move(message), emptySubchannels, /*requiredSubchannel*/ std::nullopt);
3169
+ dataProducer->ReceiveMessage(std::move(message), subchannels, requiredSubchannel);
3194
3170
  }
3195
3171
  catch (std::exception& error)
3196
3172
  {
@@ -0,0 +1,224 @@
1
+ #include "common.hpp"
2
+ #include "RTC/SCTP/public/Message.hpp"
3
+ #include "RTC/SubchannelsCodec.hpp"
4
+ #include "Utils.hpp"
5
+ #include <catch2/catch_test_macros.hpp>
6
+ #include <vector>
7
+
8
+ SCENARIO("SubchannelsCodec", "[subchannels]")
9
+ {
10
+ // Build a message with the given payload.
11
+ auto makeMessage = [](const std::vector<uint8_t>& payload)
12
+ {
13
+ return RTC::SCTP::Message(/*streamId*/ 1, /*ppid*/ 51, payload);
14
+ };
15
+
16
+ // Copy the current payload of a message into a std::vector.
17
+ auto payloadToVector = [](const RTC::SCTP::Message& message)
18
+ {
19
+ const auto payload = message.GetPayload();
20
+
21
+ return std::vector<uint8_t>(payload.begin(), payload.end());
22
+ };
23
+
24
+ SECTION(
25
+ "EncodeSubchannels() encodes subchannels and requiredSubchannel and DecodeSubchannels() decodes them back")
26
+ {
27
+ const std::vector<uint8_t> originalPayload = { 0x01, 0x02, 0x03, 0x04 };
28
+
29
+ auto message = makeMessage(originalPayload);
30
+
31
+ const std::vector<uint16_t> subchannels = { 10, 20, 300 };
32
+ const std::optional<uint16_t> requiredSubchannel = 5;
33
+
34
+ REQUIRE(
35
+ RTC::SubchannelsCodec::EncodeSubchannels(message, subchannels, requiredSubchannel) == true);
36
+
37
+ // 8 (Magic Token) + 2 (subchannelsCount) + 3 * 2 (subchannels) + 2 (requiredSubchannel).
38
+ REQUIRE(message.GetPayloadLength() == originalPayload.size() + 8 + 2 + (3 * 2) + 2);
39
+
40
+ std::vector<uint16_t> decodedSubchannels;
41
+ std::optional<uint16_t> decodedRequiredSubchannel;
42
+
43
+ REQUIRE(
44
+ RTC::SubchannelsCodec::DecodeSubchannels(
45
+ message, decodedSubchannels, decodedRequiredSubchannel) == true);
46
+
47
+ REQUIRE(decodedSubchannels == subchannels);
48
+ REQUIRE(decodedRequiredSubchannel == requiredSubchannel);
49
+ // The header must have been removed, leaving the original payload.
50
+ REQUIRE(payloadToVector(message) == originalPayload);
51
+ }
52
+
53
+ SECTION("EncodeSubchannels() encodes subchannels without requiredSubchannel")
54
+ {
55
+ const std::vector<uint8_t> originalPayload = { 0xAA, 0xBB };
56
+
57
+ auto message = makeMessage(originalPayload);
58
+
59
+ const std::vector<uint16_t> subchannels = { 1, 2 };
60
+
61
+ REQUIRE(RTC::SubchannelsCodec::EncodeSubchannels(message, subchannels, std::nullopt) == true);
62
+
63
+ // 8 (Magic Token) + 2 (subchannelsCount) + 2 * 2 (subchannels).
64
+ REQUIRE(message.GetPayloadLength() == originalPayload.size() + 8 + 2 + (2 * 2));
65
+
66
+ std::vector<uint16_t> decodedSubchannels;
67
+ std::optional<uint16_t> decodedRequiredSubchannel;
68
+
69
+ REQUIRE(
70
+ RTC::SubchannelsCodec::DecodeSubchannels(
71
+ message, decodedSubchannels, decodedRequiredSubchannel) == true);
72
+
73
+ REQUIRE(decodedSubchannels == subchannels);
74
+ REQUIRE(decodedRequiredSubchannel.has_value() == false);
75
+ REQUIRE(payloadToVector(message) == originalPayload);
76
+ }
77
+
78
+ SECTION("EncodeSubchannels() encodes requiredSubchannel without subchannels")
79
+ {
80
+ const std::vector<uint8_t> originalPayload = { 0xAA, 0xBB, 0xCC };
81
+
82
+ auto message = makeMessage(originalPayload);
83
+
84
+ const std::optional<uint16_t> requiredSubchannel = 4321;
85
+
86
+ REQUIRE(RTC::SubchannelsCodec::EncodeSubchannels(message, {}, requiredSubchannel) == true);
87
+
88
+ // 8 (Magic Token) + 2 (subchannelsCount) + 2 (requiredSubchannel).
89
+ REQUIRE(message.GetPayloadLength() == originalPayload.size() + 8 + 2 + 2);
90
+
91
+ std::vector<uint16_t> decodedSubchannels;
92
+ std::optional<uint16_t> decodedRequiredSubchannel;
93
+
94
+ REQUIRE(
95
+ RTC::SubchannelsCodec::DecodeSubchannels(
96
+ message, decodedSubchannels, decodedRequiredSubchannel) == true);
97
+
98
+ REQUIRE(decodedSubchannels.empty() == true);
99
+ REQUIRE(decodedRequiredSubchannel == requiredSubchannel);
100
+ REQUIRE(payloadToVector(message) == originalPayload);
101
+ }
102
+
103
+ SECTION("EncodeSubchannels() does nothing if there is nothing to encode")
104
+ {
105
+ const std::vector<uint8_t> originalPayload = { 0x01, 0x02 };
106
+
107
+ auto message = makeMessage(originalPayload);
108
+
109
+ REQUIRE(RTC::SubchannelsCodec::EncodeSubchannels(message, {}, std::nullopt) == false);
110
+
111
+ // The message must remain untouched.
112
+ REQUIRE(payloadToVector(message) == originalPayload);
113
+ }
114
+
115
+ SECTION("DecodeSubchannels() does nothing if the message does not start with the Magic Token")
116
+ {
117
+ const std::vector<uint8_t> originalPayload(12);
118
+
119
+ auto message = makeMessage(originalPayload);
120
+
121
+ std::vector<uint16_t> decodedSubchannels;
122
+ std::optional<uint16_t> decodedRequiredSubchannel;
123
+
124
+ REQUIRE(
125
+ RTC::SubchannelsCodec::DecodeSubchannels(
126
+ message, decodedSubchannels, decodedRequiredSubchannel) == false);
127
+
128
+ REQUIRE(decodedSubchannels.empty() == true);
129
+ REQUIRE(decodedRequiredSubchannel.has_value() == false);
130
+ REQUIRE(payloadToVector(message) == originalPayload);
131
+ }
132
+
133
+ SECTION("DecodeSubchannels() does nothing if the message is shorter than the Magic Token")
134
+ {
135
+ const std::vector<uint8_t> originalPayload = { 0x01, 0x02 };
136
+
137
+ auto message = makeMessage(originalPayload);
138
+
139
+ std::vector<uint16_t> decodedSubchannels;
140
+ std::optional<uint16_t> decodedRequiredSubchannel;
141
+
142
+ REQUIRE(
143
+ RTC::SubchannelsCodec::DecodeSubchannels(
144
+ message, decodedSubchannels, decodedRequiredSubchannel) == false);
145
+
146
+ REQUIRE(decodedSubchannels.empty() == true);
147
+ REQUIRE(decodedRequiredSubchannel.has_value() == false);
148
+ REQUIRE(payloadToVector(message) == originalPayload);
149
+ }
150
+
151
+ SECTION(
152
+ "DecodeSubchannels() ignores a truncated message that announces more subchannels than present")
153
+ {
154
+ // Craft a payload with the Magic Token (no requiredSubchannelFlag) that
155
+ // announces 3 subchannels but does not carry their bytes.
156
+ std::vector<uint8_t> originalPayload(10);
157
+
158
+ Utils::Byte::Set8Bytes(originalPayload.data(), 0, RTC::SubchannelsCodec::MagicToken);
159
+ Utils::Byte::Set2Bytes(originalPayload.data(), 8, /*subchannelsCount*/ 3);
160
+
161
+ auto message = makeMessage(originalPayload);
162
+
163
+ std::vector<uint16_t> decodedSubchannels;
164
+ std::optional<uint16_t> decodedRequiredSubchannel;
165
+
166
+ REQUIRE(
167
+ RTC::SubchannelsCodec::DecodeSubchannels(
168
+ message, decodedSubchannels, decodedRequiredSubchannel) == false);
169
+
170
+ REQUIRE(decodedSubchannels.empty() == true);
171
+ REQUIRE(decodedRequiredSubchannel.has_value() == false);
172
+ REQUIRE(payloadToVector(message) == originalPayload);
173
+ }
174
+
175
+ SECTION(
176
+ "DecodeSubchannels() ignores a message whose requiredSubchannelFlag is set but has no room for the requiredSubchannel field")
177
+ {
178
+ // Craft a payload with the Magic Token and requiredSubchannelFlag set,
179
+ // announcing 1 subchannel (present) but without the requiredSubchannel bytes.
180
+ std::vector<uint8_t> originalPayload(12);
181
+
182
+ Utils::Byte::Set8Bytes(
183
+ originalPayload.data(),
184
+ 0,
185
+ RTC::SubchannelsCodec::MagicToken | RTC::SubchannelsCodec::RequiredSubchannelFlagMask);
186
+ Utils::Byte::Set2Bytes(originalPayload.data(), 8, /*subchannelsCount*/ 1);
187
+ Utils::Byte::Set2Bytes(originalPayload.data(), 10, /*subchannel*/ 42);
188
+
189
+ auto message = makeMessage(originalPayload);
190
+
191
+ std::vector<uint16_t> decodedSubchannels;
192
+ std::optional<uint16_t> decodedRequiredSubchannel;
193
+
194
+ REQUIRE(
195
+ RTC::SubchannelsCodec::DecodeSubchannels(
196
+ message, decodedSubchannels, decodedRequiredSubchannel) == false);
197
+
198
+ REQUIRE(decodedSubchannels.empty() == true);
199
+ REQUIRE(decodedRequiredSubchannel.has_value() == false);
200
+ REQUIRE(payloadToVector(message) == originalPayload);
201
+ }
202
+
203
+ SECTION("EncodeSubchannels() and DecodeSubchannels() work with an empty original payload")
204
+ {
205
+ auto message = makeMessage({});
206
+
207
+ const std::vector<uint16_t> subchannels = { 7 };
208
+ const std::optional<uint16_t> requiredSubchannel = 7;
209
+
210
+ REQUIRE(
211
+ RTC::SubchannelsCodec::EncodeSubchannels(message, subchannels, requiredSubchannel) == true);
212
+
213
+ std::vector<uint16_t> decodedSubchannels;
214
+ std::optional<uint16_t> decodedRequiredSubchannel;
215
+
216
+ REQUIRE(
217
+ RTC::SubchannelsCodec::DecodeSubchannels(
218
+ message, decodedSubchannels, decodedRequiredSubchannel) == true);
219
+
220
+ REQUIRE(decodedSubchannels == subchannels);
221
+ REQUIRE(decodedRequiredSubchannel == requiredSubchannel);
222
+ REQUIRE(message.GetPayloadLength() == 0);
223
+ }
224
+ }