mediasoup 3.21.1 → 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,14 @@
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
+
9
+ ### 3.21.2
10
+
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)).
12
+
5
13
  ### 3.21.1
6
14
 
7
15
  - Worker: Enable SVC for VP8 and H264 ([PR #1851](https://github.com/versatica/mediasoup/pull/1851)).
@@ -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":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EACX,MAAM,EACN,mBAAmB,EACnB,kBAAkB,EAElB,UAAU,EACV,YAAY,EACZ,cAAc,EAEd,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EACX,SAAS,EAGT,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EACX,eAAe,EACf,sBAAsB,EACtB,MAAM,wBAAwB,CAAC;AAKhC,OAAO,KAAK,EACX,cAAc,EACd,qBAAqB,EACrB,MAAM,uBAAuB,CAAC;AAK/B,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAKhF,OAAO,KAAK,EACX,eAAe,EACf,sBAAsB,EACtB,MAAM,wBAAwB,CAAC;AAUhC,OAAO,KAAK,EACX,qBAAqB,EACrB,4BAA4B,EAC5B,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EACX,kBAAkB,EAClB,yBAAyB,EACzB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EACX,eAAe,EACf,wBAAwB,EACxB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAevC,MAAM,MAAM,cAAc,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,UAAU,GAAG;IACjB,eAAe,EAAE,eAAe,CAAC;CACjC,CAAC;AAIF,qBAAa,UAAU,CAAC,aAAa,SAAS,OAAO,GAAG,OAAO,CAC9D,SAAQ,oBAAoB,CAAC,YAAY,CACzC,YAAW,MAAM;;gBAwCL,EACX,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,OAAO,GACP,EAAE;QACF,QAAQ,EAAE,cAAc,CAAC;QACzB,IAAI,EAAE,UAAU,CAAC;QACjB,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,CAAC,EAAE,aAAa,CAAC;KACxB;IAaD,IAAI,EAAE,IAAI,MAAM,CAEf;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,eAAe,IAAI,eAAe,CAErC;IAED,IAAI,OAAO,IAAI,aAAa,CAE3B;IAED,IAAI,OAAO,CAAC,OAAO,EAAE,aAAa,EAEjC;IAED,IAAI,QAAQ,IAAI,cAAc,CAE7B;IAED;;;;OAIG;IACH,IAAI,oBAAoB,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAEjD;IAED,KAAK,IAAI,IAAI;IA6Cb,YAAY,IAAI,IAAI;IAiCd,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;IAmB3B,qBAAqB,CAC1B,sBAAsB,SAAS,OAAO,GAAG,OAAO,EAC/C,EACD,YAAY,EACZ,WAAW,EACX,SAAS,EACT,IAAI,EACJ,SAAS,EACT,SAAS,EACT,SAAiB,EACjB,SAAiB,EACjB,+BAAwC,EACxC,UAAkB,EAClB,kBAA2B,EAC3B,qBAA8B,EAC9B,kBAA4B,EAC5B,2BAAqC,EACrC,+BAAyC,EACzC,iBAAsB,EACtB,OAAO,GACP,EAAE,sBAAsB,CAAC,sBAAsB,CAAC,GAAG,OAAO,CAC1D,eAAe,CAAC,sBAAsB,CAAC,CACvC;IA0MK,oBAAoB,CAAC,qBAAqB,SAAS,OAAO,GAAG,OAAO,EAAE,EAC3E,UAAU,EACV,cAAc,EACd,QAAQ,EACR,IAAI,EACJ,OAAc,EACd,OAAe,EACf,UAAkB,EAClB,kBAA2B,EAC3B,qBAA8B,EAC9B,kBAA4B,EAC5B,2BAAqC,EACrC,+BAAyC,EACzC,UAAkB,EAClB,eAA2C,EAC3C,OAAO,GACP,EAAE,qBAAqB,CAAC,qBAAqB,CAAC,GAAG,OAAO,CACxD,cAAc,CAAC,qBAAqB,CAAC,CACrC;IAqJK,mBAAmB,CAAC,oBAAoB,SAAS,OAAO,GAAG,OAAO,EAAE,EACzE,UAAU,EACV,QAAQ,EACR,IAAI,EACJ,UAAkB,EAClB,kBAA2B,EAC3B,qBAA8B,EAC9B,kBAA4B,EAC5B,2BAAqC,EACrC,+BAAyC,EACzC,SAAiB,EACjB,UAAkB,EAClB,OAAO,GACP,EAAE,oBAAoB,CAAC,oBAAoB,CAAC,GAAG,OAAO,CACtD,aAAa,CAAC,oBAAoB,CAAC,CACnC;IA2HK,qBAAqB,CAC1B,sBAAsB,SAAS,OAAO,GAAG,OAAO,EAC/C,EACD,kBAA2B,EAC3B,qBAA8B,EAC9B,OAAO,GACP,GAAE,sBAAsB,CAAC,sBAAsB,CAAM,GAAG,OAAO,CAC/D,eAAe,CAAC,sBAAsB,CAAC,CACvC;IAsFK,YAAY,CAAC,EAClB,UAAU,EACV,cAAc,EACd,MAAM,EACN,MAAa,EACb,UAAU,EACV,QAAQ,EACR,UAAiB,EACjB,kBAA2B,EAC3B,qBAA8B,EAC9B,kBAA4B,EAC5B,2BAAqC,EACrC,+BAAyC,EACzC,SAAiB,EACjB,UAAkB,GAClB,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAyQ9C,2BAA2B,CAChC,4BAA4B,SAAS,OAAO,GAAG,OAAO,EACrD,EACD,QAAc,EACd,OAAO,GACP,GAAE,4BAA4B,CAAC,4BAA4B,CAAM,GAAG,OAAO,CAC3E,qBAAqB,CAAC,4BAA4B,CAAC,CACnD;IAkDK,wBAAwB,CAC7B,yBAAyB,SAAS,OAAO,GAAG,OAAO,EAClD,EACD,UAAc,EACd,SAAe,EACf,QAAe,EACf,OAAO,GACP,GAAE,yBAAyB,CAAC,yBAAyB,CAAM,GAAG,OAAO,CACrE,kBAAkB,CAAC,yBAAyB,CAAC,CAC7C;IAgED,UAAU,CAAC,EACV,UAAU,EACV,eAAe,GACf,EAAE;QACF,UAAU,EAAE,MAAM,CAAC;QACnB,eAAe,EAAE,eAAe,CAAC;KACjC,GAAG,OAAO;IAwBX,iBAAiB,CAAC,WAAW,EAAE,wBAAwB,EAAE,GAAG,IAAI;IAehE,OAAO,CAAC,oBAAoB;IAkC5B,OAAO,CAAC,mBAAmB;CAQ3B"}
@@ -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.1",
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)",
@@ -129,14 +129,14 @@
129
129
  "globals": "^17.7.0",
130
130
  "ini": "^7.0.0",
131
131
  "jest": "^30.4.2",
132
- "knip": "^6.26.0",
132
+ "knip": "^6.27.0",
133
133
  "marked": "^18.0.6",
134
134
  "open-cli": "^9.0.0",
135
135
  "pick-port": "^2.2.1",
136
136
  "prettier": "^3.9.5",
137
137
  "ts-jest": "^29.4.11",
138
138
  "typescript": "^6.0.3",
139
- "typescript-eslint": "^8.63.0",
139
+ "typescript-eslint": "^8.64.0",
140
140
  "werift-sctp": "^0.0.11"
141
141
  }
142
142
  }
@@ -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
@@ -210,7 +210,7 @@ namespace RTC
210
210
  const std::string& dataProducerId, const std::string& method) const final;
211
211
  virtual RTC::DataConsumer* AssertAndGetDataConsumerById(
212
212
  const std::string& dataConsumerId, const std::string& method) const final;
213
- virtual RTC::DataConsumer* AssertAndGetSctpDataConsumerByStreamId(uint16_t streamId) const final;
213
+ virtual RTC::DataConsumer* GetSctpDataConsumerByStreamId(uint16_t streamId) const final;
214
214
  virtual void CheckNoProducer(const std::string& producerId, const std::string& method) const final;
215
215
  virtual void CheckNoConsumer(const std::string& consumerId, const std::string& method) const final;
216
216
  virtual void CheckNoDataProducer(
@@ -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
 
@@ -446,7 +446,7 @@ namespace RTC
446
446
  {
447
447
  MS_TRACE();
448
448
 
449
- auto it = this->mapTransports.find(transportId);
449
+ const auto it = this->mapTransports.find(transportId);
450
450
 
451
451
  if (this->mapTransports.find(transportId) == this->mapTransports.end())
452
452
  {
@@ -461,7 +461,7 @@ namespace RTC
461
461
  {
462
462
  MS_TRACE();
463
463
 
464
- auto it = this->mapRtpObservers.find(rtpObserverId);
464
+ const auto it = this->mapRtpObservers.find(rtpObserverId);
465
465
 
466
466
  if (this->mapRtpObservers.find(rtpObserverId) == this->mapRtpObservers.end())
467
467
  {
@@ -566,7 +566,7 @@ namespace RTC
566
566
  consumer->ProducerPaused();
567
567
  }
568
568
 
569
- auto it = this->mapProducerRtpObservers.find(producer);
569
+ const auto it = this->mapProducerRtpObservers.find(producer);
570
570
 
571
571
  if (it != this->mapProducerRtpObservers.end())
572
572
  {
@@ -590,7 +590,7 @@ namespace RTC
590
590
  consumer->ProducerResumed();
591
591
  }
592
592
 
593
- auto it = this->mapProducerRtpObservers.find(producer);
593
+ const auto it = this->mapProducerRtpObservers.find(producer);
594
594
 
595
595
  if (it != this->mapProducerRtpObservers.end())
596
596
  {
@@ -688,7 +688,7 @@ namespace RTC
688
688
  }
689
689
  }
690
690
 
691
- auto it = this->mapProducerRtpObservers.find(producer);
691
+ const auto it = this->mapProducerRtpObservers.find(producer);
692
692
 
693
693
  if (it != this->mapProducerRtpObservers.end())
694
694
  {
@@ -1076,7 +1076,7 @@ namespace RTC
1076
1076
  RTC::Producer* Router::RtpObserverGetProducer(
1077
1077
  RTC::RtpObserver* /* rtpObserver */, const std::string& id)
1078
1078
  {
1079
- auto it = this->mapProducers.find(id);
1079
+ const auto it = this->mapProducers.find(id);
1080
1080
 
1081
1081
  if (it == this->mapProducers.end())
1082
1082
  {
@@ -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
  }
@@ -1401,6 +1397,10 @@ namespace RTC
1401
1397
 
1402
1398
  if (this->sctpAssociation)
1403
1399
  {
1400
+ // NOTE: This must be called after removing data consumers from the maps,
1401
+ // otherwise if `OnAssociationStreamBufferedAmountLow()` was triggered it
1402
+ // would end up emitting an event associated to an already closed data
1403
+ // consumer.
1404
1404
  this->sctpAssociation->ResetStreams(
1405
1405
  std::array<uint16_t, 1>{ dataConsumer->GetSctpStreamParameters().streamId });
1406
1406
  }
@@ -1476,14 +1476,6 @@ namespace RTC
1476
1476
  consumer->TransportConnected();
1477
1477
  }
1478
1478
 
1479
- // Tell all DataConsumers.
1480
- for (auto& kv : this->mapDataConsumers)
1481
- {
1482
- auto* dataConsumer = kv.second;
1483
-
1484
- dataConsumer->TransportConnected();
1485
- }
1486
-
1487
1479
  // Tell the SctpAssociation.
1488
1480
  if (this->sctpAssociation)
1489
1481
  {
@@ -1526,14 +1518,6 @@ namespace RTC
1526
1518
  consumer->TransportDisconnected();
1527
1519
  }
1528
1520
 
1529
- // Tell all DataConsumers.
1530
- for (auto& kv : this->mapDataConsumers)
1531
- {
1532
- auto* dataConsumer = kv.second;
1533
-
1534
- dataConsumer->TransportDisconnected();
1535
- }
1536
-
1537
1521
  // Stop the RTCP timer.
1538
1522
  this->rtcpTimer->Stop();
1539
1523
 
@@ -1764,7 +1748,7 @@ namespace RTC
1764
1748
  {
1765
1749
  MS_TRACE();
1766
1750
 
1767
- auto it = this->mapProducers.find(producerId);
1751
+ const auto it = this->mapProducers.find(producerId);
1768
1752
 
1769
1753
  if (it == this->mapProducers.end())
1770
1754
  {
@@ -1779,7 +1763,7 @@ namespace RTC
1779
1763
  {
1780
1764
  MS_TRACE();
1781
1765
 
1782
- auto it = this->mapConsumers.find(consumerId);
1766
+ const auto it = this->mapConsumers.find(consumerId);
1783
1767
 
1784
1768
  if (it == this->mapConsumers.end())
1785
1769
  {
@@ -1793,7 +1777,7 @@ namespace RTC
1793
1777
  {
1794
1778
  MS_TRACE();
1795
1779
 
1796
- auto mapSsrcConsumerIt = this->mapSsrcConsumer.find(ssrc);
1780
+ const auto mapSsrcConsumerIt = this->mapSsrcConsumer.find(ssrc);
1797
1781
 
1798
1782
  if (mapSsrcConsumerIt == this->mapSsrcConsumer.end())
1799
1783
  {
@@ -1809,7 +1793,7 @@ namespace RTC
1809
1793
  {
1810
1794
  MS_TRACE();
1811
1795
 
1812
- auto mapRtxSsrcConsumerIt = this->mapRtxSsrcConsumer.find(ssrc);
1796
+ const auto mapRtxSsrcConsumerIt = this->mapRtxSsrcConsumer.find(ssrc);
1813
1797
 
1814
1798
  if (mapRtxSsrcConsumerIt == this->mapRtxSsrcConsumer.end())
1815
1799
  {
@@ -1826,7 +1810,7 @@ namespace RTC
1826
1810
  {
1827
1811
  MS_TRACE();
1828
1812
 
1829
- auto it = this->mapDataProducers.find(dataProducerId);
1813
+ const auto it = this->mapDataProducers.find(dataProducerId);
1830
1814
 
1831
1815
  if (it == this->mapDataProducers.end())
1832
1816
  {
@@ -1841,7 +1825,7 @@ namespace RTC
1841
1825
  {
1842
1826
  MS_TRACE();
1843
1827
 
1844
- auto it = this->mapDataConsumers.find(dataConsumerId);
1828
+ const auto it = this->mapDataConsumers.find(dataConsumerId);
1845
1829
 
1846
1830
  if (it == this->mapDataConsumers.end())
1847
1831
  {
@@ -1851,15 +1835,15 @@ namespace RTC
1851
1835
  return it->second;
1852
1836
  }
1853
1837
 
1854
- RTC::DataConsumer* Transport::AssertAndGetSctpDataConsumerByStreamId(uint16_t streamId) const
1838
+ RTC::DataConsumer* Transport::GetSctpDataConsumerByStreamId(uint16_t streamId) const
1855
1839
  {
1856
1840
  MS_TRACE();
1857
1841
 
1858
- auto it = this->mapSctpStreamIdDataConsumers.find(streamId);
1842
+ const auto it = this->mapSctpStreamIdDataConsumers.find(streamId);
1859
1843
 
1860
1844
  if (it == this->mapSctpStreamIdDataConsumers.end())
1861
1845
  {
1862
- MS_THROW_NOT_FOUND_ERROR("SCTP DataConsumer with streamId %" PRIu16 " not found", streamId);
1846
+ return nullptr;
1863
1847
  }
1864
1848
 
1865
1849
  return it->second;
@@ -2938,6 +2922,10 @@ namespace RTC
2938
2922
  this->mapSctpStreamIdDataConsumers.erase(dataConsumer->GetSctpStreamParameters().streamId);
2939
2923
  }
2940
2924
 
2925
+ // NOTE: This must be called after removing the data consumer from the maps,
2926
+ // otherwise if `OnAssociationStreamBufferedAmountLow()` was triggered it
2927
+ // would end up emitting an event associated to an already closed data
2928
+ // consumer.
2941
2929
  if (this->sctpAssociation)
2942
2930
  {
2943
2931
  this->sctpAssociation->ResetStreams(
@@ -2991,17 +2979,6 @@ namespace RTC
2991
2979
  {
2992
2980
  MS_TRACE();
2993
2981
 
2994
- // Tell all DataConsumers.
2995
- for (auto& kv : this->mapDataConsumers)
2996
- {
2997
- auto* dataConsumer = kv.second;
2998
-
2999
- if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP)
3000
- {
3001
- dataConsumer->SctpAssociationConnected();
3002
- }
3003
- }
3004
-
3005
2982
  // Notify the upper layer.
3006
2983
 
3007
2984
  // First tell it about the SCTP negotiated capabilities.
@@ -3033,7 +3010,7 @@ namespace RTC
3033
3010
 
3034
3011
  // For debugging purposes.
3035
3012
  #if MS_LOG_DEV_LEVEL == 3
3036
- MS_DUMP("--- SCTP association connected:");
3013
+ MS_DUMP("SCTP association connected:");
3037
3014
  this->sctpAssociation->Dump();
3038
3015
  #endif
3039
3016
  }
@@ -3179,10 +3156,17 @@ namespace RTC
3179
3156
  // Pass the SCTP message to the corresponding DataProducer.
3180
3157
  try
3181
3158
  {
3182
- 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
+ }
3183
3168
 
3184
- dataProducer->ReceiveMessage(
3185
- std::move(message), emptySubchannels, /*requiredSubchannel*/ std::nullopt);
3169
+ dataProducer->ReceiveMessage(std::move(message), subchannels, requiredSubchannel);
3186
3170
  }
3187
3171
  catch (std::exception& error)
3188
3172
  {
@@ -3247,8 +3231,6 @@ namespace RTC
3247
3231
 
3248
3232
  if (!dataConsumersToClose.empty())
3249
3233
  {
3250
- this->sctpAssociation->ResetStreams(streamsToReset);
3251
-
3252
3234
  for (auto* dataConsumer : dataConsumersToClose)
3253
3235
  {
3254
3236
  // Remove it from the maps.
@@ -3271,6 +3253,12 @@ namespace RTC
3271
3253
  // Delete it.
3272
3254
  delete dataConsumer;
3273
3255
  }
3256
+
3257
+ // NOTE: This must be called after removing data consumers from the maps,
3258
+ // otherwise if `OnAssociationStreamBufferedAmountLow()` was triggered it
3259
+ // would end up emitting an event associated to an already closed data
3260
+ // consumer.
3261
+ this->sctpAssociation->ResetStreams(streamsToReset);
3274
3262
  }
3275
3263
  }
3276
3264
  }
@@ -3279,7 +3267,7 @@ namespace RTC
3279
3267
  {
3280
3268
  MS_TRACE();
3281
3269
 
3282
- const auto* dataConsumer = AssertAndGetSctpDataConsumerByStreamId(streamId);
3270
+ const auto* dataConsumer = GetSctpDataConsumerByStreamId(streamId);
3283
3271
 
3284
3272
  if (!dataConsumer)
3285
3273
  {
@@ -188,7 +188,7 @@ RTC::WebRtcServer* Worker::AssertAndGetWebRtcServerById(
188
188
  {
189
189
  MS_TRACE();
190
190
 
191
- auto it = this->mapWebRtcServers.find(webRtcServerId);
191
+ const auto it = this->mapWebRtcServers.find(webRtcServerId);
192
192
 
193
193
  if (it == this->mapWebRtcServers.end())
194
194
  {
@@ -202,7 +202,7 @@ RTC::Router* Worker::AssertAndGetRouterById(const std::string& routerId, const s
202
202
  {
203
203
  MS_TRACE();
204
204
 
205
- auto it = this->mapRouters.find(routerId);
205
+ const auto it = this->mapRouters.find(routerId);
206
206
 
207
207
  if (it == this->mapRouters.end())
208
208
  {
@@ -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
+ }