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 +4 -0
- package/node/lib/Router.d.ts +2 -2
- package/node/lib/Router.d.ts.map +1 -1
- package/node/lib/Router.js +18 -18
- package/node/lib/RouterTypes.d.ts +0 -4
- package/node/lib/RouterTypes.d.ts.map +1 -1
- package/node/lib/test/test-PipeTransport.js +33 -1
- package/package.json +1 -1
- package/worker/include/RTC/DataConsumer.hpp +7 -10
- package/worker/include/RTC/PipeTransport.hpp +4 -0
- package/worker/include/RTC/SCTP/public/Message.hpp +16 -0
- package/worker/include/RTC/SubchannelsCodec.hpp +76 -0
- package/worker/include/RTC/Transport.hpp +4 -0
- package/worker/meson.build +2 -0
- package/worker/scripts/package-lock.json +7 -6
- package/worker/src/RTC/DataConsumer.cpp +45 -62
- package/worker/src/RTC/SubchannelsCodec.cpp +153 -0
- package/worker/src/RTC/Transport.cpp +19 -43
- package/worker/test/src/RTC/TestSubchannelsCodec.cpp +224 -0
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)).
|
package/node/lib/Router.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EnhancedEventEmitter } from './enhancedEvents';
|
|
2
2
|
import type { Channel } from './Channel';
|
|
3
|
-
import type { Router, PipeToRouterOptions, PipeToRouterResult,
|
|
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 {};
|
package/node/lib/Router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,
|
|
1
|
+
{"version":3,"file":"Router.d.ts","sourceRoot":"","sources":["../src/Router.ts"],"names":[],"mappings":"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"}
|
package/node/lib/Router.js
CHANGED
|
@@ -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":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EACX,SAAS,EACT,mBAAmB,EACnB,iBAAiB,EACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EACX,eAAe,EACf,sBAAsB,EACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EACX,cAAc,EACd,qBAAqB,EACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,KAAK,EACX,eAAe,EACf,sBAAsB,EACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EACX,qBAAqB,EACrB,4BAA4B,EAC5B,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EACX,kBAAkB,EAClB,yBAAyB,EACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EACX,eAAe,EACf,wBAAwB,EACxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAE/C,MAAM,MAAM,aAAa,CAAC,aAAa,SAAS,OAAO,GAAG,OAAO,IAAI;IACpE;;OAEG;IACH,WAAW,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAEzC;;OAEG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IACjC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,MAAM,CAAC;IAErC;;;;OAIG;IACH,+BAA+B,CAAC,EAAE,MAAM,CAAC;IAEzC;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB,GAAG,kBAAkB,CAAC;AAEvB,KAAK,kBAAkB,GAAG,MAAM,CAAC,sBAAsB,EAAE,oBAAoB,CAAC,CAAC;AAE/E,KAAK,sBAAsB,GAAG;IAC7B,UAAU,EAAE,mBAAmB,CAAC;CAChC,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC3B;;OAEG;IACH,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAChC;;OAEG;IACH,YAAY,CAAC,EAAE,QAAQ,CAAC;IAExB;;OAEG;IACH,YAAY,CAAC,EAAE,QAAQ,CAAC;IAExB;;OAEG;IACH,gBAAgB,CAAC,EAAE,YAAY,CAAC;IAEhC;;OAEG;IACH,gBAAgB,CAAC,EAAE,YAAY,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACxB;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB;;OAEG;IACH,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB;;OAEG;IACH,wBAAwB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IAC9D;;OAEG;IACH,uBAAuB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1D;;OAEG;IACH,wBAAwB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IAC9D;;OAEG;IACH,gCAAgC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IACtE;;OAEG;IACH,+BAA+B,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAClE,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAC1B,WAAW,EAAE,EAAE,CAAC;IAEhB,QAAQ,EAAE,EAAE,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,oBAAoB,CAAC,oBAAoB,CAAC,CAAC;AAExE,MAAM,MAAM,oBAAoB,GAAG;IAClC,KAAK,EAAE,EAAE,CAAC;IACV,YAAY,EAAE,CAAC,SAAS,CAAC,CAAC;IAC1B,cAAc,EAAE,CAAC,WAAW,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,WAAW,MAAM,CACtB,aAAa,SAAS,OAAO,GAAG,OAAO,CACtC,SAAQ,oBAAoB,CAAC,YAAY,CAAC;IAC3C;;OAEG;IACH,IAAI,EAAE,IAAI,MAAM,CAAC;IAEjB;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAAC;IAEtB;;OAEG;IACH,IAAI,eAAe,IAAI,eAAe,CAAC;IAEvC;;OAEG;IACH,IAAI,OAAO,IAAI,aAAa,CAAC;IAE7B;;OAEG;IACH,IAAI,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE;IAEpC;;OAEG;IACH,IAAI,QAAQ,IAAI,cAAc,CAAC;IAE/B;;OAEG;IACH,KAAK,IAAI,IAAI,CAAC;IAEd;;;;OAIG;IACH,YAAY,IAAI,IAAI,CAAC;IAErB;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IAE5B;;OAEG;IACH,qBAAqB,CAAC,sBAAsB,SAAS,OAAO,GAAG,OAAO,EACrE,OAAO,EAAE,sBAAsB,CAAC,sBAAsB,CAAC,GACrD,OAAO,CAAC,eAAe,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAEpD;;OAEG;IACH,oBAAoB,CAAC,qBAAqB,SAAS,OAAO,GAAG,OAAO,EACnE,OAAO,EAAE,qBAAqB,CAAC,qBAAqB,CAAC,GACnD,OAAO,CAAC,cAAc,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAElD;;OAEG;IACH,mBAAmB,CAAC,oBAAoB,SAAS,OAAO,GAAG,OAAO,EACjE,OAAO,EAAE,oBAAoB,CAAC,oBAAoB,CAAC,GACjD,OAAO,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAEhD;;OAEG;IACH,qBAAqB,CAAC,sBAAsB,SAAS,OAAO,GAAG,OAAO,EACrE,OAAO,CAAC,EAAE,sBAAsB,CAAC,sBAAsB,CAAC,GACtD,OAAO,CAAC,eAAe,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAEpD;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAExE;;OAEG;IACH,2BAA2B,CAC1B,4BAA4B,SAAS,OAAO,GAAG,OAAO,EAEtD,OAAO,CAAC,EAAE,4BAA4B,CAAC,4BAA4B,CAAC,GAClE,OAAO,CAAC,qBAAqB,CAAC,4BAA4B,CAAC,CAAC,CAAC;IAEhE;;OAEG;IACH,wBAAwB,CAAC,yBAAyB,SAAS,OAAO,GAAG,OAAO,EAC3E,OAAO,CAAC,EAAE,yBAAyB,CAAC,yBAAyB,CAAC,GAC5D,OAAO,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,CAAC,CAAC;IAE1D;;OAEG;IACH,UAAU,CAAC,EACV,UAAU,EACV,eAAe,GACf,EAAE;QACF,UAAU,EAAE,MAAM,CAAC;QACnB,eAAe,EAAE,eAAe,CAAC;KACjC,GAAG,OAAO,CAAC;IAEZ;;;OAGG;IACH,iBAAiB,CAAC,WAAW,EAAE,wBAAwB,EAAE,GAAG,IAAI,CAAC;CACjE"}
|
|
@@ -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.
|
|
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
|
@@ -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
|
|
71
|
-
// is
|
|
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->
|
|
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
|
|
126
|
-
bool sctpAssociationConnected{ false };
|
|
123
|
+
bool sctpAssociationClosed{ false };
|
|
127
124
|
bool paused{ false };
|
|
128
125
|
bool dataProducerPaused{ false };
|
|
129
126
|
bool dataProducerClosed{ false };
|
|
@@ -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;
|
package/worker/meson.build
CHANGED
|
@@ -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.
|
|
25
|
-
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.
|
|
26
|
-
"integrity": "sha512-
|
|
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.
|
|
108
|
-
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.
|
|
109
|
-
"integrity": "sha512-
|
|
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->
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
(
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
}
|
|
509
|
+
if (cb)
|
|
510
|
+
{
|
|
511
|
+
(*cb)(false, false);
|
|
512
|
+
delete cb;
|
|
513
|
+
}
|
|
543
514
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
if (!subchannels.empty())
|
|
547
|
-
{
|
|
548
|
-
bool subchannelMatched{ false };
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
549
517
|
|
|
550
|
-
|
|
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
|
-
|
|
522
|
+
bool subchannelMatched{ false };
|
|
523
|
+
|
|
524
|
+
for (const auto subchannel : subchannels)
|
|
553
525
|
{
|
|
554
|
-
|
|
526
|
+
if (this->subchannels.contains(subchannel))
|
|
527
|
+
{
|
|
528
|
+
subchannelMatched = true;
|
|
555
529
|
|
|
556
|
-
|
|
530
|
+
break;
|
|
531
|
+
}
|
|
557
532
|
}
|
|
558
|
-
}
|
|
559
533
|
|
|
560
|
-
|
|
561
|
-
{
|
|
562
|
-
if (cb)
|
|
534
|
+
if (!subchannelMatched)
|
|
563
535
|
{
|
|
564
|
-
(
|
|
565
|
-
|
|
566
|
-
|
|
536
|
+
if (cb)
|
|
537
|
+
{
|
|
538
|
+
(*cb)(false, false);
|
|
539
|
+
delete cb;
|
|
540
|
+
}
|
|
567
541
|
|
|
568
|
-
|
|
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
|
-
"
|
|
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,
|
|
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("
|
|
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
|
-
|
|
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
|
+
}
|