diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ee22cc4dc..80554d4b58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ ### NEXT - Node: Update TypeScript to v6 ([PR #1790](https://github.com/versatica/mediasoup/pull/1790)). +- New built-in SCTP stack ([PR #1806](https://github.com/versatica/mediasoup/pull/1806)): + - **Breaking change:** Remove `useBuiltInSctpStack` option in `WorkerSettngs`. + - **Breaking change:** Remove `SctpCapabilities` type. No longer needed. + - `WebRtcTransport`, `PlainTransport`, `PipeTransport`: Add `sctpNegotiatedCapabilities()` getter. + - **Breaking change:** `WebRtcTransport`, `PlainTransport`, `PipeTransport` options: Remove `numSctpStreams` and `maxSctpMessageSize`, and add `maxSendMessageSize`, `maxReceiveMessageSize`, `sctpPerStreamSendQueueLimit` and `sctpMaxReceiverWindowBufferSize`. + - **Breaking change:** `DirectTransport` options: Remove `maxMessageSize`, and add `maxSendMessageSize` and `maxReceiveMessageSize`. + - **Breaking change:** Change `SctpParameters` type from `{ port, OS, MIS, maxMessageSize }` to `{ port, maxSendMessageSize, maxReceiveMessageSize, sendBufferSize, perStreamSendQueueLimit, maxReceiverWindowBufferSize, isDataChannel}`. ### 3.19.22 diff --git a/node/src/DataConsumer.ts b/node/src/DataConsumer.ts index d9cf66fef9..1b2478af8b 100644 --- a/node/src/DataConsumer.ts +++ b/node/src/DataConsumer.ts @@ -610,6 +610,7 @@ export function parseDataConsumerDumpResponse( : undefined, label: data.label()!, protocol: data.protocol()!, + bufferedAmount: data.bufferedAmount(), bufferedAmountLowThreshold: data.bufferedAmountLowThreshold(), paused: data.paused(), dataProducerPaused: data.dataProducerPaused(), diff --git a/node/src/DataConsumerTypes.ts b/node/src/DataConsumerTypes.ts index a254780d82..d7f240edff 100644 --- a/node/src/DataConsumerTypes.ts +++ b/node/src/DataConsumerTypes.ts @@ -66,6 +66,7 @@ export type DataConsumerDump = { sctpStreamParameters?: SctpStreamParameters; label: string; protocol: string; + bufferedAmount: number; bufferedAmountLowThreshold: number; }; diff --git a/node/src/DirectTransportTypes.ts b/node/src/DirectTransportTypes.ts index a3a961ec06..cca94dbbef 100644 --- a/node/src/DirectTransportTypes.ts +++ b/node/src/DirectTransportTypes.ts @@ -12,10 +12,16 @@ export type DirectTransportOptions< DirectTransportAppData extends AppData = AppData, > = { /** - * Maximum allowed size for direct messages sent from DataProducers. + * Maximum allowed size for messages sent by DataConsumers (in bytes). * Default 262144. */ - maxMessageSize: number; + maxSendMessageSize?: number; + + /** + * Maximum allowed size for SCTP messages received by DataProducers (in bytes). + * Default 262144. + */ + maxReceiveMessageSize?: number; /** * Custom application data. diff --git a/node/src/PipeTransport.ts b/node/src/PipeTransport.ts index b835dbfc3a..a0cae083cd 100644 --- a/node/src/PipeTransport.ts +++ b/node/src/PipeTransport.ts @@ -29,7 +29,10 @@ import { serializeRtpEncodingParameters, serializeRtpParameters, } from './rtpParametersFbsUtils'; -import type { SctpParameters } from './sctpParametersTypes'; +import type { + SctpParameters, + SctpNegotiatedCapabilities, +} from './sctpParametersTypes'; import type { SrtpParameters } from './srtpParametersTypes'; import { parseSrtpParameters, @@ -53,6 +56,7 @@ export type PipeTransportData = { tuple: TransportTuple; sctpParameters?: SctpParameters; sctpState?: SctpState; + sctpNegotiatedCapabilities?: SctpNegotiatedCapabilities; rtx: boolean; srtpParameters?: SrtpParameters; }; @@ -112,6 +116,10 @@ export class PipeTransportImpl return this.#data.sctpState; } + get sctpNegotiatedCapabilities(): SctpNegotiatedCapabilities | undefined { + return this.#data.sctpNegotiatedCapabilities; + } + get srtpParameters(): SrtpParameters | undefined { return this.#data.srtpParameters; } @@ -311,6 +319,28 @@ export class PipeTransportImpl break; } + case Event.TRANSPORT_SCTP_NEGOTIATED_CAPABILITIES: { + const notification = + new FbsTransport.SctpNegotiatedCapabilitiesNotification(); + + data!.body(notification); + + const sctpNegotiatedCapabilities: SctpNegotiatedCapabilities = { + negotiatedMaxOutboundStreams: notification + .negotiatedCapabilities()! + .negotiatedMaxOutboundStreams(), + negotiatedMaxInboundStreams: notification + .negotiatedCapabilities()! + .negotiatedMaxInboundStreams(), + }; + + this.#data.sctpNegotiatedCapabilities = sctpNegotiatedCapabilities; + + super.handleSctpNegotiatedCapabilities(sctpNegotiatedCapabilities); + + break; + } + case Event.TRANSPORT_TRACE: { const notification = new FbsTransport.TraceNotification(); diff --git a/node/src/PipeTransportTypes.ts b/node/src/PipeTransportTypes.ts index 996cbe4433..6968086c51 100644 --- a/node/src/PipeTransportTypes.ts +++ b/node/src/PipeTransportTypes.ts @@ -12,7 +12,10 @@ import type { } from './TransportTypes'; import type { Consumer } from './ConsumerTypes'; import type { SrtpParameters } from './srtpParametersTypes'; -import type { SctpParameters, NumSctpStreams } from './sctpParametersTypes'; +import type { + SctpParameters, + SctpNegotiatedCapabilities, +} from './sctpParametersTypes'; import type { Either, AppData } from './types'; export type PipeTransportOptions< @@ -24,22 +27,37 @@ export type PipeTransportOptions< enableSctp?: boolean; /** - * SCTP streams number. + * Maximum allowed size for SCTP messages sent by DataConsumers (in bytes). + * Default 262144. */ - numSctpStreams?: NumSctpStreams; + maxSendMessageSize?: number; /** - * Maximum allowed size for SCTP messages sent by DataProducers. - * Default 268435456. + * Maximum allowed size for SCTP messages received by DataProducers (in bytes). + * Default 262144. */ - maxSctpMessageSize?: number; + maxReceiveMessageSize?: number; /** - * Maximum SCTP send buffer used by DataConsumers. - * Default 268435456. + * Maximum SCTP send buffer used by DataConsumers (in bytes). + * Default 2000000. */ sctpSendBufferSize?: number; + /** + * Per stream send queue size limit. Similar to `sctpSendBufferSize`, but + * limiting the size of individual streams. + * Default 2000000. + */ + sctpPerStreamSendQueueLimit?: number; + + /** + * Maximum received window buffer size (in bytes). This should be a bit larger + * than the largest sized message you want to be able to receive. + * Default 5242880. + */ + sctpMaxReceiverWindowBufferSize?: number; + /** * Enable RTX and NACK for RTP retransmission. Useful if both Routers are * located in different hosts and there is packet lost in the link. For this @@ -155,6 +173,14 @@ export interface PipeTransport< */ get sctpState(): SctpState | undefined; + /** + * SCTP negotiated capabilities. + * + * @remarks + * - Only present if SCTP association is connected. + */ + get sctpNegotiatedCapabilities(): SctpNegotiatedCapabilities | undefined; + /** * SRTP parameters. */ diff --git a/node/src/PlainTransport.ts b/node/src/PlainTransport.ts index 122da8ea9f..27bb1f3add 100644 --- a/node/src/PlainTransport.ts +++ b/node/src/PlainTransport.ts @@ -19,7 +19,10 @@ import { parseBaseTransportStats, parseTransportTraceEventData, } from './Transport'; -import type { SctpParameters } from './sctpParametersTypes'; +import type { + SctpParameters, + SctpNegotiatedCapabilities, +} from './sctpParametersTypes'; import type { SrtpParameters } from './srtpParametersTypes'; import { parseSrtpParameters, @@ -43,6 +46,7 @@ export type PlainTransportData = { rtcpTuple?: TransportTuple; sctpParameters?: SctpParameters; sctpState?: SctpState; + sctpNegotiatedCapabilities?: SctpNegotiatedCapabilities; srtpParameters?: SrtpParameters; }; @@ -109,6 +113,10 @@ export class PlainTransportImpl return this.#data.sctpState; } + get sctpNegotiatedCapabilities(): SctpNegotiatedCapabilities | undefined { + return this.#data.sctpNegotiatedCapabilities; + } + get srtpParameters(): SrtpParameters | undefined { return this.#data.srtpParameters; } @@ -277,6 +285,28 @@ export class PlainTransportImpl break; } + case Event.TRANSPORT_SCTP_NEGOTIATED_CAPABILITIES: { + const notification = + new FbsTransport.SctpNegotiatedCapabilitiesNotification(); + + data!.body(notification); + + const sctpNegotiatedCapabilities: SctpNegotiatedCapabilities = { + negotiatedMaxOutboundStreams: notification + .negotiatedCapabilities()! + .negotiatedMaxOutboundStreams(), + negotiatedMaxInboundStreams: notification + .negotiatedCapabilities()! + .negotiatedMaxInboundStreams(), + }; + + this.#data.sctpNegotiatedCapabilities = sctpNegotiatedCapabilities; + + super.handleSctpNegotiatedCapabilities(sctpNegotiatedCapabilities); + + break; + } + case Event.TRANSPORT_TRACE: { const notification = new FbsTransport.TraceNotification(); diff --git a/node/src/PlainTransportTypes.ts b/node/src/PlainTransportTypes.ts index add7cd5dc3..41d40769f2 100644 --- a/node/src/PlainTransportTypes.ts +++ b/node/src/PlainTransportTypes.ts @@ -11,7 +11,10 @@ import type { TransportObserverEvents, } from './TransportTypes'; import type { SrtpParameters, SrtpCryptoSuite } from './srtpParametersTypes'; -import type { SctpParameters, NumSctpStreams } from './sctpParametersTypes'; +import type { + SctpParameters, + SctpNegotiatedCapabilities, +} from './sctpParametersTypes'; import type { Either, AppData } from './types'; export type PlainTransportOptions< @@ -36,22 +39,37 @@ export type PlainTransportOptions< enableSctp?: boolean; /** - * SCTP streams number. + * Maximum allowed size for SCTP messages sent by DataConsumers (in bytes). + * Default 262144. */ - numSctpStreams?: NumSctpStreams; + maxSendMessageSize?: number; /** - * Maximum allowed size for SCTP messages sent by DataProducers. + * Maximum allowed size for SCTP messages received by DataProducers (in bytes). * Default 262144. */ - maxSctpMessageSize?: number; + maxReceiveMessageSize?: number; /** - * Maximum SCTP send buffer used by DataConsumers. - * Default 262144. + * Maximum SCTP send buffer used by DataConsumers (in bytes). + * Default 2000000. */ sctpSendBufferSize?: number; + /** + * Per stream send queue size limit. Similar to `sctpSendBufferSize`, but + * limiting the size of individual streams. + * Default 2000000. + */ + sctpPerStreamSendQueueLimit?: number; + + /** + * Maximum received window buffer size (in bytes). This should be a bit larger + * than the largest sized message you want to be able to receive. + * Default 5242880. + */ + sctpMaxReceiverWindowBufferSize?: number; + /** * Enable SRTP. For this to work, connect() must be called * with remote SRTP parameters. Default false. @@ -172,6 +190,14 @@ export interface PlainTransport< */ get sctpState(): SctpState | undefined; + /** + * SCTP negotiated capabilities. + * + * @remarks + * - Only present if SCTP association is connected. + */ + get sctpNegotiatedCapabilities(): SctpNegotiatedCapabilities | undefined; + /** * SRTP parameters. */ diff --git a/node/src/Router.ts b/node/src/Router.ts index 30b65afd54..89e7a5cf77 100644 --- a/node/src/Router.ts +++ b/node/src/Router.ts @@ -82,7 +82,6 @@ import * as FbsWebRtcTransport from './fbs/web-rtc-transport'; import * as FbsPlainTransport from './fbs/plain-transport'; import * as FbsPipeTransport from './fbs/pipe-transport'; import * as FbsDirectTransport from './fbs/direct-transport'; -import * as FbsSctpParameters from './fbs/sctp-parameters'; export type RouterInternal = { routerId: string; @@ -302,9 +301,11 @@ export class RouterImpl preferTcp = false, initialAvailableOutgoingBitrate = 600000, enableSctp = false, - numSctpStreams = { OS: 1024, MIS: 1024 }, - maxSctpMessageSize = 262144, - sctpSendBufferSize = 262144, + maxSendMessageSize = 262144, + maxReceiveMessageSize = 262144, + sctpSendBufferSize = 2000000, + sctpPerStreamSendQueueLimit = 2000000, + sctpMaxReceiverWindowBufferSize = 5242880, iceConsentTimeout = 30, appData, }: WebRtcTransportOptions): Promise< @@ -324,12 +325,6 @@ export class RouterImpl throw new TypeError( 'only one of webRtcServer, listenInfos and listenIps must be given' ); - } else if ( - numSctpStreams && - (typeof numSctpStreams.OS !== 'number' || - typeof numSctpStreams.MIS !== 'number') - ) { - throw new TypeError('if given, numSctpStreams must contain OS and MIS'); } else if (appData && typeof appData !== 'object') { throw new TypeError('if given, appData must be an object'); } @@ -425,17 +420,15 @@ export class RouterImpl } const baseTransportOptions = new FbsTransport.OptionsT( - undefined /* direct */, - undefined /* maxMessageSize */, + /* direct */ undefined, initialAvailableOutgoingBitrate, enableSctp, - new FbsSctpParameters.NumSctpStreamsT( - numSctpStreams.OS, - numSctpStreams.MIS - ), - maxSctpMessageSize, + maxSendMessageSize, + maxReceiveMessageSize, sctpSendBufferSize, - true /* isDataChannel */ + sctpPerStreamSendQueueLimit, + sctpMaxReceiverWindowBufferSize, + /* isDataChannel */ true ); const webRtcTransportOptions = @@ -529,9 +522,11 @@ export class RouterImpl rtcpMux = true, comedia = false, enableSctp = false, - numSctpStreams = { OS: 1024, MIS: 1024 }, - maxSctpMessageSize = 262144, - sctpSendBufferSize = 262144, + maxSendMessageSize = 262144, + maxReceiveMessageSize = 262144, + sctpSendBufferSize = 2000000, + sctpPerStreamSendQueueLimit = 2000000, + sctpMaxReceiverWindowBufferSize = 5242880, enableSrtp = false, srtpCryptoSuite = 'AES_CM_128_HMAC_SHA1_80', appData, @@ -578,17 +573,15 @@ export class RouterImpl /* Build Request. */ const baseTransportOptions = new FbsTransport.OptionsT( - undefined /* direct */, - undefined /* maxMessageSize */, - undefined /* initialAvailableOutgoingBitrate */, + /* direct */ undefined, + /* initialAvailableOutgoingBitrate */ undefined, enableSctp, - new FbsSctpParameters.NumSctpStreamsT( - numSctpStreams.OS, - numSctpStreams.MIS - ), - maxSctpMessageSize, + maxSendMessageSize, + maxReceiveMessageSize, sctpSendBufferSize, - false /* isDataChannel */ + sctpPerStreamSendQueueLimit, + sctpMaxReceiverWindowBufferSize, + /* isDataChannel */ false ); const plainTransportOptions = new FbsPlainTransport.PlainTransportOptionsT( @@ -693,9 +686,11 @@ export class RouterImpl listenIp, port, enableSctp = false, - numSctpStreams = { OS: 1024, MIS: 1024 }, - maxSctpMessageSize = 268435456, - sctpSendBufferSize = 268435456, + maxSendMessageSize = 262144, + maxReceiveMessageSize = 262144, + sctpSendBufferSize = 2000000, + sctpPerStreamSendQueueLimit = 2000000, + sctpMaxReceiverWindowBufferSize = 5242880, enableRtx = false, enableSrtp = false, appData, @@ -733,17 +728,15 @@ export class RouterImpl /* Build Request. */ const baseTransportOptions = new FbsTransport.OptionsT( - undefined /* direct */, - undefined /* maxMessageSize */, - undefined /* initialAvailableOutgoingBitrate */, + /* direct */ undefined, + /* initialAvailableOutgoingBitrate */ undefined, enableSctp, - new FbsSctpParameters.NumSctpStreamsT( - numSctpStreams.OS, - numSctpStreams.MIS - ), - maxSctpMessageSize, + maxSendMessageSize, + maxReceiveMessageSize, sctpSendBufferSize, - false /* isDataChannel */ + sctpPerStreamSendQueueLimit, + sctpMaxReceiverWindowBufferSize, + /* isDataChannel */ false ); const pipeTransportOptions = new FbsPipeTransport.PipeTransportOptionsT( @@ -826,19 +819,18 @@ export class RouterImpl return transport; } - async createDirectTransport( - { - maxMessageSize = 262144, - appData, - }: DirectTransportOptions = { - maxMessageSize: 262144, - } - ): Promise> { + async createDirectTransport< + DirectTransportAppData extends AppData = AppData, + >({ + maxSendMessageSize = 262144, + maxReceiveMessageSize = 262144, + appData, + }: DirectTransportOptions = {}): Promise< + DirectTransport + > { logger.debug('createDirectTransport()'); - if (typeof maxMessageSize !== 'number' || maxMessageSize < 0) { - throw new TypeError('if given, maxMessageSize must be a positive number'); - } else if (appData && typeof appData !== 'object') { + if (appData && typeof appData !== 'object') { throw new TypeError('if given, appData must be an object'); } @@ -846,14 +838,15 @@ export class RouterImpl /* Build Request. */ const baseTransportOptions = new FbsTransport.OptionsT( - true /* direct */, - maxMessageSize, - undefined /* initialAvailableOutgoingBitrate */, - undefined /* enableSctp */, - undefined /* numSctpStreams */, - undefined /* maxSctpMessageSize */, - undefined /* sctpSendBufferSize */, - undefined /* isDataChannel */ + /* direct */ true, + /* initialAvailableOutgoingBitrate */ undefined, + /* enableSctp */ undefined, + maxSendMessageSize, + maxReceiveMessageSize, + /* sctpSendBufferSize */ undefined, + /* sctpPerStreamSendQueueLimit */ undefined, + /* sctpMaxReceiverWindowBufferSize */ undefined, + /* isDataChannel */ undefined ); const directTransportOptions = @@ -928,7 +921,11 @@ export class RouterImpl listenInfo, listenIp, enableSctp = true, - numSctpStreams = { OS: 1024, MIS: 1024 }, + maxSendMessageSize = 262144, + maxReceiveMessageSize = 262144, + sctpSendBufferSize = 2000000, + sctpPerStreamSendQueueLimit = 2000000, + sctpMaxReceiverWindowBufferSize = 5242880, enableRtx = false, enableSrtp = false, }: PipeToRouterOptions): Promise { @@ -1001,14 +998,22 @@ export class RouterImpl this.createPipeTransport({ listenInfo: listenInfo!, enableSctp, - numSctpStreams, + maxSendMessageSize, + maxReceiveMessageSize, + sctpSendBufferSize, + sctpPerStreamSendQueueLimit, + sctpMaxReceiverWindowBufferSize, enableRtx, enableSrtp, }), router.createPipeTransport({ listenInfo: listenInfo!, enableSctp, - numSctpStreams, + maxSendMessageSize, + maxReceiveMessageSize, + sctpSendBufferSize, + sctpPerStreamSendQueueLimit, + sctpMaxReceiverWindowBufferSize, enableRtx, enableSrtp, }), diff --git a/node/src/RouterTypes.ts b/node/src/RouterTypes.ts index dd560c0745..3e035c280f 100644 --- a/node/src/RouterTypes.ts +++ b/node/src/RouterTypes.ts @@ -34,7 +34,6 @@ import type { RtpCapabilities, RouterRtpCodecCapability, } from './rtpParametersTypes'; -import type { NumSctpStreams } from './sctpParametersTypes'; import type { Either, AppData } from './types'; export type RouterOptions = { @@ -81,9 +80,36 @@ export type PipeToRouterOptions = { enableSctp?: boolean; /** - * SCTP streams number. + * Maximum allowed size for SCTP messages sent by DataConsumers (in bytes). + * Default 262144. */ - numSctpStreams?: NumSctpStreams; + maxSendMessageSize?: number; + + /** + * Maximum allowed size for SCTP messages received by DataProducers (in bytes). + * Default 262144. + */ + maxReceiveMessageSize?: number; + + /** + * Maximum SCTP send buffer used by DataConsumers (in bytes). + * Default 2000000. + */ + sctpSendBufferSize?: number; + + /** + * Per stream send queue size limit. Similar to `sctpSendBufferSize`, but + * limiting the size of individual streams. + * Default 2000000. + */ + sctpPerStreamSendQueueLimit?: number; + + /** + * Maximum received window buffer size (in bytes). This should be a bit larger + * than the largest sized message you want to be able to receive. + * Default 5242880. + */ + sctpMaxReceiverWindowBufferSize?: number; /** * Enable RTX and NACK for RTP retransmission. diff --git a/node/src/Transport.ts b/node/src/Transport.ts index ae6580c4cb..42ed9f9eb8 100644 --- a/node/src/Transport.ts +++ b/node/src/Transport.ts @@ -70,10 +70,11 @@ import { } from './rtpParametersFbsUtils'; import type { SctpParameters, + SctpNegotiatedCapabilities, SctpStreamParameters, } from './sctpParametersTypes'; import { - parseSctpParametersDump, + parseSctpParameters, serializeSctpStreamParameters, } from './sctpParametersFbsUtils'; import type { AppData } from './types'; @@ -124,6 +125,7 @@ export abstract class TransportImpl< protected readonly internal: TransportInternal; // Transport data. This is set by the subclass. + // eslint-disable-next-line no-unused-private-class-members readonly #data: TransportData; // Channel instance. @@ -169,6 +171,9 @@ export abstract class TransportImpl< // Buffer with available SCTP stream ids. #sctpStreamIds?: Buffer; + // Max number of negotiated outbound SCTP streams. + #sctpNegotiatedMaxOutboundStreams?: number; + // Next SCTP stream id. #nextSctpStreamId = 0; @@ -856,7 +861,7 @@ export abstract class TransportImpl< type = 'sctp'; // This may throw. - sctpStreamId = this.getNextSctpStreamId(); + sctpStreamId = this.allocateSctpStreamId(); sctpStreamParameters = dataProducer.sctpStreamParameters ? utils.clone(dataProducer.sctpStreamParameters) @@ -865,7 +870,6 @@ export abstract class TransportImpl< ordered: true, }; - this.#sctpStreamIds![sctpStreamId] = 1; sctpStreamParameters.streamId = sctpStreamId; if (ordered !== undefined) { @@ -995,18 +999,38 @@ export abstract class TransportImpl< ); } - private getNextSctpStreamId(): number { - if ( - !this.#data.sctpParameters || - typeof this.#data.sctpParameters.MIS !== 'number' - ) { - throw new TypeError('missing sctpParameters.MIS'); + protected handleSctpNegotiatedCapabilities( + sctpNegotiatedCapabilities: SctpNegotiatedCapabilities + ): void { + this.#sctpNegotiatedMaxOutboundStreams = + sctpNegotiatedCapabilities.negotiatedMaxOutboundStreams; + } + + private allocateSctpStreamId(): number { + if (!this.#sctpStreamIds) { + // Allocate a buffer with 65535 elements set to 0. + // Notice that 65535 is the maximum number of streams in a SCTP + // association. + this.#sctpStreamIds = Buffer.alloc(65535, 0); } - const numStreams = this.#data.sctpParameters.MIS; + // It may happen that the SCTP association is connected after having + // created many DataConsumers and hence some of them could have + // exceeded the max number of SCTP outgoing streams. + // + // NOTE: This is not an issue in real world because nowadays all the + // WebRTC browsers negotiate 65535 (max value) for their inbound + // number of streams and mediasoup always negotiates 65565 (max value) + // for its outbound number of streams. + if ( + this.#sctpNegotiatedMaxOutboundStreams !== undefined && + this.#nextSctpStreamId + 1 > this.#sctpNegotiatedMaxOutboundStreams + ) { + logger.warn( + `SCTP negotiated max outbound streams is higher than current next SCTP streamId + 1, resetting it to 0` + ); - if (!this.#sctpStreamIds) { - this.#sctpStreamIds = Buffer.alloc(numStreams, 0); + this.#nextSctpStreamId = 0; } let sctpStreamId; @@ -1015,7 +1039,8 @@ export abstract class TransportImpl< sctpStreamId = (this.#nextSctpStreamId + idx) % this.#sctpStreamIds.length; - if (!this.#sctpStreamIds[sctpStreamId]) { + if (this.#sctpStreamIds[sctpStreamId] === 0) { + this.#sctpStreamIds[sctpStreamId] = 1; this.#nextSctpStreamId = sctpStreamId + 1; return sctpStreamId; @@ -1144,7 +1169,7 @@ export function parseBaseTransportDump( let sctpParameters: SctpParameters | undefined; if (fbsSctpParameters) { - sctpParameters = parseSctpParametersDump(fbsSctpParameters); + sctpParameters = parseSctpParameters(fbsSctpParameters); } // Retrieve sctpState. @@ -1175,7 +1200,8 @@ export function parseBaseTransportDump( dataConsumerIds: dataConsumerIds, recvRtpHeaderExtensions: recvRtpHeaderExtensions, rtpListener: rtpListener, - maxMessageSize: binary.maxMessageSize(), + maxSendMessageSize: binary.maxSendMessageSize(), + maxReceiveMessageSize: binary.maxReceiveMessageSize(), sctpParameters: sctpParameters, sctpState: sctpState, sctpListener: sctpListener, diff --git a/node/src/TransportTypes.ts b/node/src/TransportTypes.ts index d65dcec718..f51986e560 100644 --- a/node/src/TransportTypes.ts +++ b/node/src/TransportTypes.ts @@ -163,7 +163,8 @@ export type BaseTransportDump = { mapRtxSsrcConsumerId: { key: number; value: string }[]; recvRtpHeaderExtensions: RecvRtpHeaderExtensions; rtpListener: RtpListenerDump; - maxMessageSize: number; + maxSendMessageSize: number; + maxReceiveMessageSize: number; dataProducerIds: string[]; dataConsumerIds: string[]; sctpParameters?: SctpParameters; diff --git a/node/src/WebRtcTransport.ts b/node/src/WebRtcTransport.ts index 646e261773..385d35d5c2 100644 --- a/node/src/WebRtcTransport.ts +++ b/node/src/WebRtcTransport.ts @@ -31,7 +31,10 @@ import { parseTransportTraceEventData, parseTuple, } from './Transport'; -import type { SctpParameters } from './sctpParametersTypes'; +import type { + SctpParameters, + SctpNegotiatedCapabilities, +} from './sctpParametersTypes'; import type { AppData } from './types'; import * as fbsUtils from './fbsUtils'; import { Event, Notification } from './fbs/notification'; @@ -62,6 +65,7 @@ export type WebRtcTransportData = { dtlsRemoteCert?: string; sctpParameters?: SctpParameters; sctpState?: SctpState; + sctpNegotiatedCapabilities?: SctpNegotiatedCapabilities; }; const logger = new Logger('WebRtcTransport'); @@ -156,6 +160,10 @@ export class WebRtcTransportImpl< return this.#data.sctpState; } + get sctpNegotiatedCapabilities(): SctpNegotiatedCapabilities | undefined { + return this.#data.sctpNegotiatedCapabilities; + } + override close(): void { if (this.closed) { return; @@ -375,6 +383,28 @@ export class WebRtcTransportImpl< break; } + case Event.TRANSPORT_SCTP_NEGOTIATED_CAPABILITIES: { + const notification = + new FbsTransport.SctpNegotiatedCapabilitiesNotification(); + + data!.body(notification); + + const sctpNegotiatedCapabilities: SctpNegotiatedCapabilities = { + negotiatedMaxOutboundStreams: notification + .negotiatedCapabilities()! + .negotiatedMaxOutboundStreams(), + negotiatedMaxInboundStreams: notification + .negotiatedCapabilities()! + .negotiatedMaxInboundStreams(), + }; + + this.#data.sctpNegotiatedCapabilities = sctpNegotiatedCapabilities; + + super.handleSctpNegotiatedCapabilities(sctpNegotiatedCapabilities); + + break; + } + case Event.TRANSPORT_TRACE: { const notification = new FbsTransport.TraceNotification(); diff --git a/node/src/WebRtcTransportTypes.ts b/node/src/WebRtcTransportTypes.ts index 40db9bd735..9265c54ddf 100644 --- a/node/src/WebRtcTransportTypes.ts +++ b/node/src/WebRtcTransportTypes.ts @@ -12,7 +12,10 @@ import type { TransportObserverEvents, } from './TransportTypes'; import type { WebRtcServer } from './WebRtcServerTypes'; -import type { SctpParameters, NumSctpStreams } from './sctpParametersTypes'; +import type { + SctpParameters, + SctpNegotiatedCapabilities, +} from './sctpParametersTypes'; import type { Either, AppData } from './types'; export type WebRtcTransportOptions< @@ -56,22 +59,37 @@ type WebRtcTransportOptionsBase = { enableSctp?: boolean; /** - * SCTP streams number. + * Maximum allowed size for SCTP messages sent by DataConsumers (in bytes). + * Default 262144. */ - numSctpStreams?: NumSctpStreams; + maxSendMessageSize?: number; /** - * Maximum allowed size for SCTP messages sent by DataProducers. + * Maximum allowed size for SCTP messages received by DataProducers (in bytes). * Default 262144. */ - maxSctpMessageSize?: number; + maxReceiveMessageSize?: number; /** - * Maximum SCTP send buffer used by DataConsumers. - * Default 262144. + * Maximum SCTP send buffer used by DataConsumers (in bytes). + * Default 2000000. */ sctpSendBufferSize?: number; + /** + * Per stream send queue size limit. Similar to `sctpSendBufferSize`, but + * limiting the size of individual streams. + * Default 2000000. + */ + sctpPerStreamSendQueueLimit?: number; + + /** + * Maximum received window buffer size (in bytes). This should be a bit larger + * than the largest sized message you want to be able to receive. + * Default 5242880. + */ + sctpMaxReceiverWindowBufferSize?: number; + /** * Custom application data. */ @@ -287,6 +305,14 @@ export interface WebRtcTransport< */ get sctpState(): SctpState | undefined; + /** + * SCTP negotiated capabilities. + * + * @remarks + * - Only present if SCTP association is connected. + */ + get sctpNegotiatedCapabilities(): SctpNegotiatedCapabilities | undefined; + /** * Dump WebRtcTransport. * diff --git a/node/src/Worker.ts b/node/src/Worker.ts index 7d62d24c55..f50e14478c 100644 --- a/node/src/Worker.ts +++ b/node/src/Worker.ts @@ -85,7 +85,6 @@ export class WorkerImpl workerBin, libwebrtcFieldTrials, disableLiburing, - useBuiltInSctpStack, appData, }: WorkerSettings) { super(); @@ -143,12 +142,6 @@ export class WorkerImpl spawnArgs.push('--disableLiburing=true'); } - if (useBuiltInSctpStack) { - spawnArgs.push('--useBuiltInSctpStack=true'); - } else { - spawnArgs.push('--useBuiltInSctpStack=false'); - } - logger.debug(`spawning worker process: ${spawnBin} ${spawnArgs.join(' ')}`); this.#child = spawn( diff --git a/node/src/WorkerTypes.ts b/node/src/WorkerTypes.ts index b5a9656cce..c66c3948d8 100644 --- a/node/src/WorkerTypes.ts +++ b/node/src/WorkerTypes.ts @@ -80,11 +80,6 @@ export type WorkerSettings = { */ disableLiburing?: boolean; - /** - * Use the mediasoup built-in SCTP stack instead usrsctp. - */ - useBuiltInSctpStack?: boolean; - /** * Custom application data. */ diff --git a/node/src/index.ts b/node/src/index.ts index 2800d63db6..9a3c29bd84 100644 --- a/node/src/index.ts +++ b/node/src/index.ts @@ -102,7 +102,6 @@ export async function createWorker({ workerBin, libwebrtcFieldTrials, disableLiburing = false, - useBuiltInSctpStack = false, appData, }: WorkerSettings = {}): Promise> { logger.debug('createWorker()'); @@ -121,7 +120,6 @@ export async function createWorker({ workerBin, libwebrtcFieldTrials, disableLiburing, - useBuiltInSctpStack, appData, }); diff --git a/node/src/sctpParametersFbsUtils.ts b/node/src/sctpParametersFbsUtils.ts index 9d1e513063..49b83c514b 100644 --- a/node/src/sctpParametersFbsUtils.ts +++ b/node/src/sctpParametersFbsUtils.ts @@ -1,21 +1,26 @@ import type * as flatbuffers from 'flatbuffers'; import type { SctpStreamParameters, - SctpParametersDump, + SctpParameters, } from './sctpParametersTypes'; import * as FbsSctpParameters from './fbs/sctp-parameters'; -export function parseSctpParametersDump( +export function parseSctpParameters( binary: FbsSctpParameters.SctpParameters -): SctpParametersDump { +): SctpParameters { return { port: binary.port(), - OS: binary.os(), - MIS: binary.mis(), - maxMessageSize: binary.maxMessageSize(), + maxSendMessageSize: binary.maxSendMessageSize(), + maxReceiveMessageSize: binary.maxReceiveMessageSize(), sendBufferSize: binary.sendBufferSize(), - sctpBufferedAmount: binary.sctpBufferedAmount(), + perStreamSendQueueLimit: binary.perStreamSendQueueLimit(), + maxReceiverWindowBufferSize: binary.maxReceiverWindowBufferSize(), isDataChannel: binary.isDataChannel(), + + // TODO: SCTP: For backwards compatibility. Remove them in the future. + OS: 65535, + MIS: 65535, + maxMessageSize: binary.maxReceiveMessageSize(), }; } diff --git a/node/src/sctpParametersTypes.ts b/node/src/sctpParametersTypes.ts index bd0601cf4d..a2a139acb1 100644 --- a/node/src/sctpParametersTypes.ts +++ b/node/src/sctpParametersTypes.ts @@ -1,53 +1,23 @@ -export type SctpCapabilities = { - numStreams: NumSctpStreams; -}; - -/** - * Both OS and MIS are part of the SCTP INIT+ACK handshake. OS refers to the - * initial number of outgoing SCTP streams that the server side transport creates - * (to be used by DataConsumers), while MIS refers to the maximum number of - * incoming SCTP streams that the server side transport can receive (to be used - * by DataProducers). So, if the server side transport will just be used to - * create data producers (but no data consumers), OS can be low (~1). - * - * mediasoup-client provides specific per browser/version OS and MIS values via - * the device.sctpCapabilities getter. However those values must be reversed - * when provided to the mediasoup server transport. - */ -export type NumSctpStreams = { - /** - * Initially requested number of outgoing SCTP streams. - */ - OS: number; - - /** - * Maximum number of incoming SCTP streams. - */ - MIS: number; -}; - export type SctpParameters = { - /** - * Must always equal 5000. - */ port: number; + maxSendMessageSize: number; + maxReceiveMessageSize: number; + sendBufferSize: number; + perStreamSendQueueLimit: number; + maxReceiverWindowBufferSize: number; + isDataChannel: boolean; - /** - * Initially requested number of outgoing SCTP streams. - */ + // TODO: SCTP: For backwards compatibility. Remove them in the future. OS: number; - - /** - * Maximum number of incoming SCTP streams. - */ MIS: number; - - /** - * Maximum allowed size for SCTP messages. - */ maxMessageSize: number; }; +export type SctpNegotiatedCapabilities = { + negotiatedMaxOutboundStreams: number; + negotiatedMaxInboundStreams: number; +}; + /** * SCTP stream parameters describe the reliability of a certain SCTP stream. * If ordered is true then maxPacketLifeTime and maxRetransmits must be @@ -79,13 +49,3 @@ export type SctpStreamParameters = { */ maxRetransmits?: number; }; - -export type SctpParametersDump = { - port: number; - OS: number; - MIS: number; - maxMessageSize: number; - sendBufferSize: number; - sctpBufferedAmount: number; - isDataChannel: boolean; -}; diff --git a/node/src/test/test-DirectTransport.ts b/node/src/test/test-DirectTransport.ts index 18decccadd..0d471470a3 100644 --- a/node/src/test/test-DirectTransport.ts +++ b/node/src/test/test-DirectTransport.ts @@ -29,7 +29,8 @@ test('router.createDirectTransport() succeeds', async () => { ctx.router!.observer.once('newtransport', onObserverNewTransport); const directTransport = await ctx.router!.createDirectTransport({ - maxMessageSize: 1024, + maxSendMessageSize: 1024, + maxReceiveMessageSize: 1024, appData: { foo: 'bar' }, }); @@ -58,17 +59,6 @@ test('router.createDirectTransport() succeeds', async () => { expect(directTransport.closed).toBe(true); }, 2000); -test('router.createDirectTransport() with wrong arguments rejects with TypeError', async () => { - await expect( - // @ts-expect-error --- Testing purposes. - ctx.router!.createDirectTransport({ maxMessageSize: 'foo' }) - ).rejects.toThrow(TypeError); - - await expect( - ctx.router!.createDirectTransport({ maxMessageSize: -2000 }) - ).rejects.toThrow(TypeError); -}, 2000); - test('directTransport.getStats() succeeds', async () => { const directTransport = await ctx.router!.createDirectTransport(); diff --git a/node/src/test/test-PlainTransport.ts b/node/src/test/test-PlainTransport.ts index b64243d86d..9a891e7cef 100644 --- a/node/src/test/test-PlainTransport.ts +++ b/node/src/test/test-PlainTransport.ts @@ -6,7 +6,6 @@ import type { WorkerEvents, PlainTransportEvents } from '../types'; import * as utils from '../utils'; const IS_WINDOWS = os.platform() === 'win32'; -const USE_BUILD_IN_SCTP_STACK = false; type TestContext = { mediaCodecs: mediasoup.types.RouterRtpCodecCapability[]; @@ -47,9 +46,7 @@ const ctx: TestContext = { }; beforeEach(async () => { - ctx.worker = await mediasoup.createWorker({ - useBuiltInSctpStack: USE_BUILD_IN_SCTP_STACK, - }); + ctx.worker = await mediasoup.createWorker(); ctx.router = await ctx.worker.createRouter({ mediaCodecs: ctx.mediaCodecs }); }); @@ -105,13 +102,15 @@ test('router.createPlainTransport() succeeds', async () => { expect(plainTransport2.rtcpTuple).toBeUndefined(); expect(plainTransport2.sctpParameters).toMatchObject({ port: 5000, - // NOTE: When using the built-in SCTP stack, `numSctpStreams` given to the - // transport is ignored. - OS: USE_BUILD_IN_SCTP_STACK ? 65535 : 1024, - MIS: USE_BUILD_IN_SCTP_STACK ? 65535 : 1024, - maxMessageSize: 262144, + maxSendMessageSize: 262144, + maxReceiveMessageSize: 262144, + sendBufferSize: 2000000, + perStreamSendQueueLimit: 2000000, + maxReceiverWindowBufferSize: 5242880, + isDataChannel: false, }); expect(plainTransport2.sctpState).toBe('new'); + expect(plainTransport2.sctpNegotiatedCapabilities).toBeUndefined(); expect(plainTransport2.srtpParameters).toBeUndefined(); const dump1 = await plainTransport2.dump(); @@ -167,6 +166,7 @@ test('router.createPlainTransport() succeeds', async () => { expect(transport2.rtcpTuple?.protocol).toBe('udp'); expect(transport2.sctpParameters).toBeUndefined(); expect(transport2.sctpState).toBeUndefined(); + expect(transport2.sctpNegotiatedCapabilities).toBeUndefined(); const dump2 = await transport2.dump(); diff --git a/node/src/test/test-WebRtcTransport.ts b/node/src/test/test-WebRtcTransport.ts index 155346cb59..d084d463bd 100644 --- a/node/src/test/test-WebRtcTransport.ts +++ b/node/src/test/test-WebRtcTransport.ts @@ -15,8 +15,6 @@ import { import * as FbsTransport from '../fbs/transport'; import * as FbsWebRtcTransport from '../fbs/web-rtc-transport'; -const USE_BUILD_IN_SCTP_STACK = false; - type TestContext = { mediaCodecs: mediasoup.types.RouterRtpCodecCapability[]; worker?: mediasoup.types.Worker; @@ -55,9 +53,7 @@ const ctx: TestContext = { }; beforeEach(async () => { - ctx.worker = await mediasoup.createWorker({ - useBuiltInSctpStack: USE_BUILD_IN_SCTP_STACK, - }); + ctx.worker = await mediasoup.createWorker(); ctx.router = await ctx.worker.createRouter({ mediaCodecs: ctx.mediaCodecs }); }); @@ -119,8 +115,11 @@ test('router.createWebRtcTransport() succeeds', async () => { enableTcp: true, preferUdp: true, enableSctp: true, - numSctpStreams: { OS: 2048, MIS: 4096 }, - maxSctpMessageSize: 1000000, + maxSendMessageSize: 1000001, + maxReceiveMessageSize: 1000002, + sctpSendBufferSize: 2000001, + sctpPerStreamSendQueueLimit: 2000002, + sctpMaxReceiverWindowBufferSize: 2000003, appData: { foo: 'bar' }, }); @@ -141,11 +140,12 @@ test('router.createWebRtcTransport() succeeds', async () => { expect(typeof webRtcTransport.iceParameters.password).toBe('string'); expect(webRtcTransport.sctpParameters).toMatchObject({ port: 5000, - // NOTE: When using the built-in SCTP stack, `numSctpStreams` given to the - // transport is ignored. - OS: USE_BUILD_IN_SCTP_STACK ? 65535 : 2048, - MIS: USE_BUILD_IN_SCTP_STACK ? 65535 : 4096, - maxMessageSize: 1000000, + maxSendMessageSize: 1000001, + maxReceiveMessageSize: 1000002, + sendBufferSize: 2000001, + perStreamSendQueueLimit: 2000002, + maxReceiverWindowBufferSize: 2000003, + isDataChannel: true, }); expect(Array.isArray(webRtcTransport.iceCandidates)).toBe(true); expect(webRtcTransport.iceCandidates.length).toBe(7); @@ -208,6 +208,7 @@ test('router.createWebRtcTransport() succeeds', async () => { expect(webRtcTransport.dtlsState).toBe('new'); expect(webRtcTransport.dtlsRemoteCert).toBeUndefined(); expect(webRtcTransport.sctpState).toBe('new'); + expect(webRtcTransport.sctpNegotiatedCapabilities).toBeUndefined(); const dump = await webRtcTransport.dump(); @@ -349,15 +350,6 @@ test('router.createWebRtcTransport() with wrong arguments rejects with TypeError appData: 'NOT-AN-OBJECT', }) ).rejects.toThrow(TypeError); - - await expect( - ctx.router!.createWebRtcTransport({ - listenIps: ['127.0.0.1'], - enableSctp: true, - // @ts-expect-error --- Testing purposes. - numSctpStreams: 'foo', - }) - ).rejects.toThrow(TypeError); }, 2000); test('router.createWebRtcTransport() with non bindable IP rejects with Error', async () => { diff --git a/node/src/test/test-werift-sctp.ts b/node/src/test/test-werift-sctp.ts index a99eebca3c..9bdf1b21a5 100644 --- a/node/src/test/test-werift-sctp.ts +++ b/node/src/test/test-werift-sctp.ts @@ -22,9 +22,7 @@ type TestContext = { const ctx: TestContext = {}; beforeEach(async () => { - ctx.worker = await mediasoup.createWorker({ - disableLiburing: true, - }); + ctx.worker = await mediasoup.createWorker(); ctx.router = await ctx.worker.createRouter(); @@ -34,7 +32,6 @@ beforeEach(async () => { // So we don't need to call plainTransport.connect(). comedia: true, enableSctp: true, - numSctpStreams: { OS: 256, MIS: 256 }, }); // Create an explicit SCTP outgoing stream id. @@ -115,6 +112,10 @@ afterEach(async () => { test('SCTP state is connected', () => { expect(ctx.plainTransport!.sctpState).toBe('connected'); + expect(ctx.plainTransport!.sctpNegotiatedCapabilities).toEqual({ + negotiatedMaxOutboundStreams: 65535, + negotiatedMaxInboundStreams: 65535, + }); expect(ctx.sctpClient!.associationState).toBe(SCTP_STATE.ESTABLISHED); }); diff --git a/rust/CHANGELOG.md b/rust/CHANGELOG.md index 9cef30ef61..074c703154 100644 --- a/rust/CHANGELOG.md +++ b/rust/CHANGELOG.md @@ -2,7 +2,12 @@ ### NEXT -- Worker: Add `use_built_in_sctp_stack` setting (defaults to `false`) to enable mediasoup built-in SCTP stack (PR #1777). +- New built-in SCTP stack (PR #1806): + - Remove `useBuiltInSctpStack` worker option. + - `WebRtcTransport`, `PlainTransport`, `PipeTransport`: Add `sctp_negotiated_capabilities()` getter. + - `WebRtcTransport`, `PlainTransport`, `PipeTransport` options: Remove `num_sctp_streams` and `max_sctp_message_size`, and add `max_send_message_size`, `max_receive_message_size`, `sctp_per_stream_send_queue_limit` and `sctp_max_receiver_window_buffer_size`. + - `DirectTransport` options: Remove `max_message_size`, and add `max_send_message_size` and `max_receive_message_size`. + - Change `SctpParameters` type from `{ port, OS, MIS, maxMessageSize }` to `{ port, max_send_message_size, max_receive_message_size, send_buffer_size, per_stream_send_queue_limit,max_receiver_window_buffer_size, is_data_channel}`. ### 0.21.0 diff --git a/rust/src/messages.rs b/rust/src/messages.rs index dbbf67131f..01f11bddea 100644 --- a/rust/src/messages.rs +++ b/rust/src/messages.rs @@ -34,7 +34,7 @@ use mediasoup_types::data_structures::{ ListenInfo, SctpState, TransportTuple, }; use mediasoup_types::rtp_parameters::{MediaKind, RtpEncodingParameters, RtpParameters}; -use mediasoup_types::sctp_parameters::{NumSctpStreams, SctpParameters, SctpStreamParameters}; +use mediasoup_types::sctp_parameters::{SctpParameters, SctpStreamParameters}; use mediasoup_types::srtp_parameters::{SrtpCryptoSuite, SrtpParameters}; use parking_lot::Mutex; use planus::Builder; @@ -547,7 +547,8 @@ impl Request for RouterDumpRequest { pub(crate) struct RouterCreateDirectTransportData { transport_id: TransportId, direct: bool, - max_message_size: u32, + max_send_message_size: u32, + max_receive_message_size: u32, } impl RouterCreateDirectTransportData { @@ -558,7 +559,8 @@ impl RouterCreateDirectTransportData { Self { transport_id, direct: true, - max_message_size: direct_transport_options.max_message_size, + max_send_message_size: direct_transport_options.max_send_message_size, + max_receive_message_size: direct_transport_options.max_receive_message_size, } } } @@ -570,12 +572,13 @@ impl ToFbs for RouterCreateDirectTransportData { direct_transport::DirectTransportOptions { base: Box::new(transport::Options { direct: true, - max_message_size: Some(self.max_message_size), initial_available_outgoing_bitrate: None, - enable_sctp: false, - num_sctp_streams: None, - max_sctp_message_size: 0, + max_send_message_size: self.max_send_message_size, + max_receive_message_size: self.max_receive_message_size, sctp_send_buffer_size: 0, + sctp_per_stream_send_queue_limit: 0, + sctp_max_receiver_window_buffer_size: 0, + enable_sctp: false, is_data_channel: false, }), } @@ -668,9 +671,11 @@ pub(crate) struct RouterCreateWebrtcTransportData { prefer_tcp: bool, ice_consent_timeout: u8, enable_sctp: bool, - num_sctp_streams: NumSctpStreams, - max_sctp_message_size: u32, + max_send_message_size: u32, + max_receive_message_size: u32, sctp_send_buffer_size: u32, + sctp_per_stream_send_queue_limit: u32, + sctp_max_receiver_window_buffer_size: u32, is_data_channel: bool, } @@ -701,9 +706,13 @@ impl RouterCreateWebrtcTransportData { prefer_tcp: webrtc_transport_options.prefer_tcp, ice_consent_timeout: webrtc_transport_options.ice_consent_timeout, enable_sctp: webrtc_transport_options.enable_sctp, - num_sctp_streams: webrtc_transport_options.num_sctp_streams, - max_sctp_message_size: webrtc_transport_options.max_sctp_message_size, + max_send_message_size: webrtc_transport_options.max_send_message_size, + max_receive_message_size: webrtc_transport_options.max_receive_message_size, sctp_send_buffer_size: webrtc_transport_options.sctp_send_buffer_size, + sctp_per_stream_send_queue_limit: webrtc_transport_options + .sctp_per_stream_send_queue_limit, + sctp_max_receiver_window_buffer_size: webrtc_transport_options + .sctp_max_receiver_window_buffer_size, is_data_channel: true, } } @@ -716,12 +725,13 @@ impl ToFbs for RouterCreateWebrtcTransportData { web_rtc_transport::WebRtcTransportOptions { base: Box::new(transport::Options { direct: false, - max_message_size: None, initial_available_outgoing_bitrate: Some(self.initial_available_outgoing_bitrate), enable_sctp: self.enable_sctp, - num_sctp_streams: Some(Box::new(self.num_sctp_streams.to_fbs())), - max_sctp_message_size: self.max_sctp_message_size, + max_send_message_size: self.max_send_message_size, + max_receive_message_size: self.max_receive_message_size, sctp_send_buffer_size: self.sctp_send_buffer_size, + sctp_per_stream_send_queue_limit: self.sctp_per_stream_send_queue_limit, + sctp_max_receiver_window_buffer_size: self.sctp_max_receiver_window_buffer_size, is_data_channel: true, }), listen: self.listen.to_fbs(), @@ -894,12 +904,14 @@ pub(crate) struct RouterCreatePlainTransportData { rtcp_mux: bool, comedia: bool, enable_sctp: bool, - num_sctp_streams: NumSctpStreams, - max_sctp_message_size: u32, + max_send_message_size: u32, + max_receive_message_size: u32, sctp_send_buffer_size: u32, + sctp_per_stream_send_queue_limit: u32, + sctp_max_receiver_window_buffer_size: u32, + is_data_channel: bool, enable_srtp: bool, srtp_crypto_suite: SrtpCryptoSuite, - is_data_channel: bool, } impl RouterCreatePlainTransportData { @@ -914,12 +926,16 @@ impl RouterCreatePlainTransportData { rtcp_mux: plain_transport_options.rtcp_mux, comedia: plain_transport_options.comedia, enable_sctp: plain_transport_options.enable_sctp, - num_sctp_streams: plain_transport_options.num_sctp_streams, - max_sctp_message_size: plain_transport_options.max_sctp_message_size, + max_send_message_size: plain_transport_options.max_send_message_size, + max_receive_message_size: plain_transport_options.max_receive_message_size, sctp_send_buffer_size: plain_transport_options.sctp_send_buffer_size, + sctp_per_stream_send_queue_limit: plain_transport_options + .sctp_per_stream_send_queue_limit, + sctp_max_receiver_window_buffer_size: plain_transport_options + .sctp_max_receiver_window_buffer_size, + is_data_channel: false, enable_srtp: plain_transport_options.enable_srtp, srtp_crypto_suite: plain_transport_options.srtp_crypto_suite, - is_data_channel: false, } } } @@ -931,12 +947,13 @@ impl ToFbs for RouterCreatePlainTransportData { plain_transport::PlainTransportOptions { base: Box::new(transport::Options { direct: false, - max_message_size: None, initial_available_outgoing_bitrate: None, enable_sctp: self.enable_sctp, - num_sctp_streams: Some(Box::new(self.num_sctp_streams.to_fbs())), - max_sctp_message_size: self.max_sctp_message_size, + max_send_message_size: self.max_send_message_size, + max_receive_message_size: self.max_receive_message_size, sctp_send_buffer_size: self.sctp_send_buffer_size, + sctp_per_stream_send_queue_limit: self.sctp_per_stream_send_queue_limit, + sctp_max_receiver_window_buffer_size: self.sctp_max_receiver_window_buffer_size, is_data_channel: self.is_data_channel, }), listen_info: Box::new(self.listen_info.clone().to_fbs()), @@ -1029,12 +1046,14 @@ pub(crate) struct RouterCreatePipeTransportData { transport_id: TransportId, listen_info: ListenInfo, enable_sctp: bool, - num_sctp_streams: NumSctpStreams, - max_sctp_message_size: u32, + max_send_message_size: u32, + max_receive_message_size: u32, sctp_send_buffer_size: u32, + sctp_per_stream_send_queue_limit: u32, + sctp_max_receiver_window_buffer_size: u32, + is_data_channel: bool, enable_rtx: bool, enable_srtp: bool, - is_data_channel: bool, } impl RouterCreatePipeTransportData { @@ -1046,12 +1065,16 @@ impl RouterCreatePipeTransportData { transport_id, listen_info: pipe_transport_options.listen_info.clone(), enable_sctp: pipe_transport_options.enable_sctp, - num_sctp_streams: pipe_transport_options.num_sctp_streams, - max_sctp_message_size: pipe_transport_options.max_sctp_message_size, + max_send_message_size: pipe_transport_options.max_send_message_size, + max_receive_message_size: pipe_transport_options.max_receive_message_size, sctp_send_buffer_size: pipe_transport_options.sctp_send_buffer_size, + sctp_per_stream_send_queue_limit: pipe_transport_options + .sctp_per_stream_send_queue_limit, + sctp_max_receiver_window_buffer_size: pipe_transport_options + .sctp_max_receiver_window_buffer_size, + is_data_channel: false, enable_rtx: pipe_transport_options.enable_rtx, enable_srtp: pipe_transport_options.enable_srtp, - is_data_channel: false, } } } @@ -1063,12 +1086,13 @@ impl ToFbs for RouterCreatePipeTransportData { pipe_transport::PipeTransportOptions { base: Box::new(transport::Options { direct: false, - max_message_size: None, initial_available_outgoing_bitrate: None, enable_sctp: self.enable_sctp, - num_sctp_streams: Some(Box::new(self.num_sctp_streams.to_fbs())), - max_sctp_message_size: self.max_sctp_message_size, + max_send_message_size: self.max_send_message_size, + max_receive_message_size: self.max_receive_message_size, sctp_send_buffer_size: self.sctp_send_buffer_size, + sctp_per_stream_send_queue_limit: self.sctp_per_stream_send_queue_limit, + sctp_max_receiver_window_buffer_size: self.sctp_max_receiver_window_buffer_size, is_data_channel: self.is_data_channel, }), listen_info: Box::new(self.listen_info.clone().to_fbs()), @@ -1959,8 +1983,8 @@ impl Request for TransportConsumeDataRequest { self.data_consumer_id.to_string(), self.data_producer_id.to_string(), match self.r#type { - DataConsumerType::Sctp => data_producer::Type::Sctp, - DataConsumerType::Direct => data_producer::Type::Direct, + DataConsumerType::Sctp => data_consumer::Type::Sctp, + DataConsumerType::Direct => data_consumer::Type::Direct, }, ToFbs::to_fbs(&self.sctp_stream_parameters), if self.label.is_empty() { @@ -2001,8 +2025,8 @@ impl Request for TransportConsumeDataRequest { Ok(TransportConsumeDataResponse { r#type: match data.type_ { - data_producer::Type::Sctp => DataConsumerType::Sctp, - data_producer::Type::Direct => DataConsumerType::Direct, + data_consumer::Type::Sctp => DataConsumerType::Sctp, + data_consumer::Type::Direct => DataConsumerType::Direct, }, sctp_stream_parameters: data.sctp_stream_parameters.map(|stream_parameters| { SctpStreamParameters::from_fbs(stream_parameters.as_ref()) diff --git a/rust/src/router.rs b/rust/src/router.rs index 2ebec02f51..64cf155a1a 100644 --- a/rust/src/router.rs +++ b/rust/src/router.rs @@ -62,7 +62,6 @@ use mediasoup_types::data_structures::{AppData, ListenInfo, Protocol}; use mediasoup_types::rtp_parameters::{ RtpCapabilities, RtpCapabilitiesFinalized, RtpCodecCapability, }; -use mediasoup_types::sctp_parameters::NumSctpStreams; use parking_lot::{Mutex, RwLock}; use serde::{Deserialize, Serialize}; use std::fmt; @@ -134,8 +133,23 @@ pub struct PipeToRouterOptions { /// /// Default `true`. pub enable_sctp: bool, - /// SCTP streams number. - pub num_sctp_streams: NumSctpStreams, + /// Maximum allowed size for SCTP messages sent by DataConsumers (in bytes). + /// Default 262_144. + pub max_send_message_size: u32, + /// Maximum allowed size for SCTP messages received by DataProducers (in bytes). + /// Default 262_144. + pub max_receive_message_size: u32, + /// Maximum SCTP send buffer used by DataConsumers (in bytes). + /// Default 2_000_000. + pub sctp_send_buffer_size: u32, + /// Per stream send queue size limit. Similar to `sctp_send_buffer_size`, but + /// limiting the size of individual streams. + /// Default 2_000_000. + pub sctp_per_stream_send_queue_limit: u32, + /// Maximum received window buffer size (in bytes). This should be a bit larger + /// than the largest sized message you want to be able to receive. + /// Default 5_242_880. + pub sctp_max_receiver_window_buffer_size: u32, /// Enable RTX and NACK for RTP retransmission. /// /// Default `false`. @@ -165,7 +179,11 @@ impl PipeToRouterOptions { recv_buffer_size: None, }, enable_sctp: true, - num_sctp_streams: NumSctpStreams::default(), + max_send_message_size: 262_144, + max_receive_message_size: 262_144, + sctp_send_buffer_size: 2_000_000, + sctp_per_stream_send_queue_limit: 2_000_000, + sctp_max_receiver_window_buffer_size: 5_242_880, enable_rtx: false, enable_srtp: false, } @@ -1542,7 +1560,11 @@ impl Router { keep_id: _, listen_info, enable_sctp, - num_sctp_streams, + max_send_message_size, + max_receive_message_size, + sctp_send_buffer_size, + sctp_per_stream_send_queue_limit, + sctp_max_receiver_window_buffer_size, enable_rtx, enable_srtp, } = pipe_to_router_options; @@ -1551,7 +1573,11 @@ impl Router { let transport_options = PipeTransportOptions { enable_sctp, - num_sctp_streams, + max_send_message_size, + max_receive_message_size, + sctp_send_buffer_size, + sctp_per_stream_send_queue_limit, + sctp_max_receiver_window_buffer_size, enable_rtx, enable_srtp, app_data: AppData::default(), diff --git a/rust/src/router/data_consumer.rs b/rust/src/router/data_consumer.rs index 34116c8472..5566ee91d6 100644 --- a/rust/src/router/data_consumer.rs +++ b/rust/src/router/data_consumer.rs @@ -15,7 +15,7 @@ use crate::worker::{Channel, NotificationParseError, RequestError, SubscriptionH use async_executor::Executor; use event_listener_primitives::{Bag, BagOnce, HandlerId}; use log::{debug, error}; -use mediasoup_sys::fbs::{data_consumer, data_producer, notification, response}; +use mediasoup_sys::fbs::{data_consumer, notification, response}; use mediasoup_types::data_structures::{AppData, WebRtcMessage}; use mediasoup_types::sctp_parameters::SctpStreamParameters; use parking_lot::Mutex; @@ -157,6 +157,7 @@ pub struct DataConsumerDump { pub label: String, pub protocol: String, pub sctp_stream_parameters: Option, + pub buffered_amount: u32, pub buffered_amount_low_threshold: u32, pub paused: bool, pub subchannels: Vec, @@ -171,7 +172,7 @@ impl<'a> TryFromFbs<'a> for DataConsumerDump { Ok(Self { id: dump.id.parse()?, data_producer_id: dump.data_producer_id.parse()?, - r#type: if dump.type_ == data_producer::Type::Sctp { + r#type: if dump.type_ == data_consumer::Type::Sctp { DataConsumerType::Sctp } else { DataConsumerType::Direct @@ -182,6 +183,7 @@ impl<'a> TryFromFbs<'a> for DataConsumerDump { .sctp_stream_parameters .as_ref() .map(|parameters| SctpStreamParameters::from_fbs(parameters.as_ref())), + buffered_amount: dump.buffered_amount, buffered_amount_low_threshold: dump.buffered_amount_low_threshold, paused: dump.paused, subchannels: dump.subchannels.clone(), diff --git a/rust/src/router/direct_transport.rs b/rust/src/router/direct_transport.rs index 5784a36568..0c61e2f0ea 100644 --- a/rust/src/router/direct_transport.rs +++ b/rust/src/router/direct_transport.rs @@ -30,15 +30,23 @@ use serde::{Deserialize, Serialize}; use std::error::Error; use std::fmt; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::{Arc, Weak}; +use std::sync::{Arc, LazyLock, Weak}; + +static USED_SCTP_STREAM_IDS: LazyLock>> = + LazyLock::new(|| Mutex::new(IntMap::default())); + +static NEXT_SCTP_STREAM_ID: LazyLock> = LazyLock::new(|| Mutex::new(0)); /// [`DirectTransport`] options. #[derive(Debug, Clone)] #[non_exhaustive] pub struct DirectTransportOptions { - /// Maximum allowed size for direct messages sent from DataProducers. + /// Maximum allowed size for SCTP messages sent by DataConsumers (in bytes). + /// Default 262_144. + pub max_send_message_size: u32, + /// Maximum allowed size for SCTP messages received by DataProducers (in bytes). /// Default 262_144. - pub max_message_size: u32, + pub max_receive_message_size: u32, /// Custom application data. pub app_data: AppData, } @@ -46,7 +54,8 @@ pub struct DirectTransportOptions { impl Default for DirectTransportOptions { fn default() -> Self { Self { - max_message_size: 262_144, + max_send_message_size: 262_144, + max_receive_message_size: 262_144, app_data: AppData::default(), } } @@ -68,7 +77,8 @@ pub struct DirectTransportDump { pub data_consumer_ids: Vec, pub recv_rtp_header_extensions: RecvRtpHeaderExtensions, pub rtp_listener: RtpListener, - pub max_message_size: u32, + pub max_send_message_size: u32, + pub max_receive_message_size: u32, pub sctp_parameters: Option, pub sctp_state: Option, pub sctp_listener: Option, @@ -123,7 +133,8 @@ impl<'a> TryFromFbs<'a> for DirectTransportDump { dump.base.recv_rtp_header_extensions.as_ref(), ), rtp_listener: RtpListener::try_from_fbs(*dump.base.rtp_listener)?, - max_message_size: dump.base.max_message_size, + max_send_message_size: dump.base.max_send_message_size, + max_receive_message_size: dump.base.max_receive_message_size, sctp_parameters: dump .base .sctp_parameters @@ -268,7 +279,6 @@ impl<'a> TryFromFbs<'a> for Notification { struct Inner { id: TransportId, next_mid_for_consumers: AtomicUsize, - used_sctp_stream_ids: Mutex>, cname_for_producers: Mutex>, executor: Arc>, channel: Channel, @@ -349,7 +359,6 @@ impl fmt::Debug for DirectTransport { f.debug_struct("DirectTransport") .field("id", &self.inner.id) .field("next_mid_for_consumers", &self.inner.next_mid_for_consumers) - .field("used_sctp_stream_ids", &self.inner.used_sctp_stream_ids) .field("cname_for_producers", &self.inner.cname_for_producers) .field("router", &self.inner.router) .field("closed", &self.inner.closed) @@ -551,12 +560,20 @@ impl TransportImpl for DirectTransport { &self.inner.next_mid_for_consumers } + fn cname_for_producers(&self) -> &Mutex> { + &self.inner.cname_for_producers + } + + fn sctp_negotiated_max_outbound_streams(&self) -> Option { + None + } + fn used_sctp_stream_ids(&self) -> &Mutex> { - &self.inner.used_sctp_stream_ids + &USED_SCTP_STREAM_IDS } - fn cname_for_producers(&self) -> &Mutex> { - &self.inner.cname_for_producers + fn next_sctp_stream_id(&self) -> &Mutex { + &NEXT_SCTP_STREAM_ID } } @@ -595,7 +612,6 @@ impl DirectTransport { }; let next_mid_for_consumers = AtomicUsize::default(); - let used_sctp_stream_ids = Mutex::new(IntMap::default()); let cname_for_producers = Mutex::new(None); let inner_weak = Arc::>>>::default(); let on_router_close_handler = router.on_close({ @@ -612,7 +628,6 @@ impl DirectTransport { let inner = Arc::new(Inner { id, next_mid_for_consumers, - used_sctp_stream_ids, cname_for_producers, executor, channel, diff --git a/rust/src/router/pipe_transport.rs b/rust/src/router/pipe_transport.rs index 4ce7b1eb76..f05e9dfaec 100644 --- a/rust/src/router/pipe_transport.rs +++ b/rust/src/router/pipe_transport.rs @@ -19,9 +19,9 @@ use async_executor::Executor; use async_trait::async_trait; use event_listener_primitives::{Bag, BagOnce, HandlerId}; use log::{debug, error}; -use mediasoup_sys::fbs::{notification, pipe_transport, response, transport}; +use mediasoup_sys::fbs::{notification, pipe_transport, response, sctp_association, transport}; use mediasoup_types::data_structures::{AppData, ListenInfo, SctpState, TransportTuple}; -use mediasoup_types::sctp_parameters::{NumSctpStreams, SctpParameters}; +use mediasoup_types::sctp_parameters::{SctpNegotiatedCapabilities, SctpParameters}; use mediasoup_types::srtp_parameters::SrtpParameters; use nohash_hasher::IntMap; use parking_lot::Mutex; @@ -41,14 +41,23 @@ pub struct PipeTransportOptions { /// Create a SCTP association. /// Default false. pub enable_sctp: bool, - /// SCTP streams number. - pub num_sctp_streams: NumSctpStreams, - /// Maximum allowed size for SCTP messages sent by DataProducers. - /// Default 268_435_456. - pub max_sctp_message_size: u32, - /// Maximum SCTP send buffer used by DataConsumers. - /// Default 268_435_456. + /// Maximum allowed size for SCTP messages sent by DataConsumers (in bytes). + /// Default 262_144. + pub max_send_message_size: u32, + /// Maximum allowed size for SCTP messages received by DataProducers (in bytes). + /// Default 262_144. + pub max_receive_message_size: u32, + /// Maximum SCTP send buffer used by DataConsumers (in bytes). + /// Default 2_000_000. pub sctp_send_buffer_size: u32, + /// Per stream send queue size limit. Similar to `sctp_send_buffer_size`, but + /// limiting the size of individual streams. + /// Default 2_000_000. + pub sctp_per_stream_send_queue_limit: u32, + /// Maximum received window buffer size (in bytes). This should be a bit larger + /// than the largest sized message you want to be able to receive. + /// Default 5_242_880. + pub sctp_max_receiver_window_buffer_size: u32, /// Enable RTX and NACK for RTP retransmission. Useful if both Routers are located in different /// hosts and there is packet lost in the link. For this to work, both PipeTransports must /// enable this setting. @@ -69,9 +78,11 @@ impl PipeTransportOptions { Self { listen_info, enable_sctp: false, - num_sctp_streams: NumSctpStreams::default(), - max_sctp_message_size: 268_435_456, - sctp_send_buffer_size: 268_435_456, + max_send_message_size: 262_144, + max_receive_message_size: 262_144, + sctp_send_buffer_size: 2_000_000, + sctp_per_stream_send_queue_limit: 2_000_000, + sctp_max_receiver_window_buffer_size: 5_242_880, enable_rtx: false, enable_srtp: false, app_data: AppData::default(), @@ -95,7 +106,8 @@ pub struct PipeTransportDump { pub data_consumer_ids: Vec, pub recv_rtp_header_extensions: RecvRtpHeaderExtensions, pub rtp_listener: RtpListener, - pub max_message_size: u32, + pub max_send_message_size: u32, + pub max_receive_message_size: u32, pub sctp_parameters: Option, pub sctp_state: Option, pub sctp_listener: Option, @@ -155,7 +167,8 @@ impl<'a> TryFromFbs<'a> for PipeTransportDump { dump.base.recv_rtp_header_extensions.as_ref(), ), rtp_listener: RtpListener::try_from_fbs(*dump.base.rtp_listener)?, - max_message_size: dump.base.max_message_size, + max_send_message_size: dump.base.max_send_message_size, + max_receive_message_size: dump.base.max_receive_message_size, sctp_parameters: dump .base .sctp_parameters @@ -286,6 +299,10 @@ enum Notification { SctpStateChange { sctp_state: SctpState, }, + #[serde(rename_all = "camelCase")] + SctpNegotiatedCapabilities { + negotiated_capabilities: SctpNegotiatedCapabilities, + }, Trace(TransportTraceEventData), } @@ -306,6 +323,25 @@ impl<'a> TryFromFbs<'a> for Notification { Ok(Notification::SctpStateChange { sctp_state }) } + notification::Event::TransportSctpNegotiatedCapabilities => { + let Ok(Some( + notification::BodyRef::TransportSctpNegotiatedCapabilitiesNotification(body), + )) = notification.body() + else { + panic!("Wrong message from worker: {notification:?}"); + }; + + let negotiated_capabilities = SctpNegotiatedCapabilities::from_fbs( + &sctp_association::SctpNegotiatedCapabilities::try_from( + body.negotiated_capabilities().unwrap().unwrap(), + ) + .unwrap(), + ); + + Ok(Notification::SctpNegotiatedCapabilities { + negotiated_capabilities, + }) + } notification::Event::TransportTrace => { let Ok(Some(notification::BodyRef::TransportTraceNotification(body))) = notification.body() @@ -327,6 +363,7 @@ struct Inner { id: TransportId, next_mid_for_consumers: AtomicUsize, used_sctp_stream_ids: Mutex>, + next_sctp_stream_id: Mutex, cname_for_producers: Mutex>, executor: Arc>, channel: Channel, @@ -335,6 +372,7 @@ struct Inner { app_data: AppData, // Make sure router is not dropped until this transport is not dropped router: Router, + sctp_negotiated_capabilities: Mutex>, closed: AtomicBool, // Drop subscription to transport-specific notifications when transport itself is dropped _subscription_handler: Mutex>, @@ -598,12 +636,23 @@ impl TransportImpl for PipeTransport { &self.inner.next_mid_for_consumers } + fn cname_for_producers(&self) -> &Mutex> { + &self.inner.cname_for_producers + } + + fn sctp_negotiated_max_outbound_streams(&self) -> Option { + self.inner + .sctp_negotiated_capabilities + .lock() + .map(|caps| caps.negotiated_max_outbound_streams) + } + fn used_sctp_stream_ids(&self) -> &Mutex> { &self.inner.used_sctp_stream_ids } - fn cname_for_producers(&self) -> &Mutex> { - &self.inner.cname_for_producers + fn next_sctp_stream_id(&self) -> &Mutex { + &self.inner.next_sctp_stream_id } } @@ -620,10 +669,12 @@ impl PipeTransport { let handlers = Arc::::default(); let data = Arc::new(data); + let sctp_negotiated_capabilities = Arc::new(Mutex::new(None::)); let subscription_handler = { let handlers = Arc::clone(&handlers); let data = Arc::clone(&data); + let sctp_negotiated_capabilities = Arc::clone(&sctp_negotiated_capabilities); channel.subscribe_to_notifications(id.into(), move |notification| { match Notification::try_from_fbs(notification) { @@ -635,6 +686,13 @@ impl PipeTransport { callback(sctp_state); }); } + Notification::SctpNegotiatedCapabilities { + negotiated_capabilities, + } => { + sctp_negotiated_capabilities + .lock() + .replace(negotiated_capabilities); + } Notification::Trace(trace_event_data) => { handlers.trace.call_simple(&trace_event_data); } @@ -648,15 +706,17 @@ impl PipeTransport { let next_mid_for_consumers = AtomicUsize::default(); let used_sctp_stream_ids = Mutex::new({ - let mut used_used_sctp_stream_ids = IntMap::default(); - if let Some(sctp_parameters) = &data.sctp_parameters { - for i in 0..sctp_parameters.mis { - used_used_sctp_stream_ids.insert(i, false); - } + let mut used_sctp_stream_ids = IntMap::default(); + + for i in 0..=65535 { + used_sctp_stream_ids.insert(i, false); } - used_used_sctp_stream_ids + + used_sctp_stream_ids }); + let next_sctp_stream_id = Mutex::new(0); let cname_for_producers = Mutex::new(None); + let sctp_negotiated_capabilities = Mutex::new(None); let inner_weak = Arc::>>>::default(); let on_router_close_handler = router.on_close({ let inner_weak = Arc::clone(&inner_weak); @@ -673,6 +733,7 @@ impl PipeTransport { id, next_mid_for_consumers, used_sctp_stream_ids, + next_sctp_stream_id, cname_for_producers, executor, channel, @@ -680,6 +741,7 @@ impl PipeTransport { data, app_data, router, + sctp_negotiated_capabilities, closed: AtomicBool::new(false), _subscription_handler: Mutex::new(subscription_handler), _on_router_close_handler: Mutex::new(on_router_close_handler), @@ -748,6 +810,12 @@ impl PipeTransport { *self.inner.data.sctp_state.lock() } + /// SCTP negotiated capabilities. Or `None` if SCTP is not connected. + #[must_use] + pub fn sctp_negotiated_capabilities(&self) -> Option { + *self.inner.sctp_negotiated_capabilities.lock() + } + /// Local SRTP parameters representing the crypto suite and key material used to encrypt sending /// RTP and SRTP. Those parameters must be given to the paired `PipeTransport` in the /// `connect()` method. diff --git a/rust/src/router/plain_transport.rs b/rust/src/router/plain_transport.rs index 98571040f2..454bf67b3d 100644 --- a/rust/src/router/plain_transport.rs +++ b/rust/src/router/plain_transport.rs @@ -19,9 +19,9 @@ use async_executor::Executor; use async_trait::async_trait; use event_listener_primitives::{Bag, BagOnce, HandlerId}; use log::{debug, error}; -use mediasoup_sys::fbs::{notification, plain_transport, response, transport}; +use mediasoup_sys::fbs::{notification, plain_transport, response, sctp_association, transport}; use mediasoup_types::data_structures::{AppData, ListenInfo, SctpState, TransportTuple}; -use mediasoup_types::sctp_parameters::{NumSctpStreams, SctpParameters}; +use mediasoup_types::sctp_parameters::{SctpNegotiatedCapabilities, SctpParameters}; use mediasoup_types::srtp_parameters::{SrtpCryptoSuite, SrtpParameters}; use nohash_hasher::IntMap; use parking_lot::Mutex; @@ -60,14 +60,23 @@ pub struct PlainTransportOptions { /// Create a SCTP association. /// Default false. pub enable_sctp: bool, - /// SCTP streams number. - pub num_sctp_streams: NumSctpStreams, - /// Maximum allowed size for SCTP messages sent by DataProducers. - /// Default 262144. - pub max_sctp_message_size: u32, - /// Maximum SCTP send buffer used by DataConsumers. - /// Default 262144. + /// Maximum allowed size for SCTP messages sent by DataConsumers (in bytes). + /// Default 262_144. + pub max_send_message_size: u32, + /// Maximum allowed size for SCTP messages received by DataProducers (in bytes). + /// Default 262_144. + pub max_receive_message_size: u32, + /// Maximum SCTP send buffer used by DataConsumers (in bytes). + /// Default 2_000_000. pub sctp_send_buffer_size: u32, + /// Per stream send queue size limit. Similar to `sctp_send_buffer_size`, but + /// limiting the size of individual streams. + /// Default 2_000_000. + pub sctp_per_stream_send_queue_limit: u32, + /// Maximum received window buffer size (in bytes). This should be a bit larger + /// than the largest sized message you want to be able to receive. + /// Default 5_242_880. + pub sctp_max_receiver_window_buffer_size: u32, /// Enable SRTP. For this to work, connect() must be called with remote SRTP parameters. /// Default false. pub enable_srtp: bool, @@ -88,9 +97,11 @@ impl PlainTransportOptions { rtcp_mux: true, comedia: false, enable_sctp: false, - num_sctp_streams: NumSctpStreams::default(), - max_sctp_message_size: 262_144, - sctp_send_buffer_size: 262_144, + max_send_message_size: 262_144, + max_receive_message_size: 262_144, + sctp_send_buffer_size: 2_000_000, + sctp_per_stream_send_queue_limit: 2_000_000, + sctp_max_receiver_window_buffer_size: 5_242_880, enable_srtp: false, srtp_crypto_suite: SrtpCryptoSuite::default(), app_data: AppData::default(), @@ -114,7 +125,8 @@ pub struct PlainTransportDump { pub data_consumer_ids: Vec, pub recv_rtp_header_extensions: RecvRtpHeaderExtensions, pub rtp_listener: RtpListener, - pub max_message_size: u32, + pub max_send_message_size: u32, + pub max_receive_message_size: u32, pub sctp_parameters: Option, pub sctp_state: Option, pub sctp_listener: Option, @@ -176,7 +188,8 @@ impl<'a> TryFromFbs<'a> for PlainTransportDump { dump.base.recv_rtp_header_extensions.as_ref(), ), rtp_listener: RtpListener::try_from_fbs(*dump.base.rtp_listener)?, - max_message_size: dump.base.max_message_size, + max_send_message_size: dump.base.max_send_message_size, + max_receive_message_size: dump.base.max_receive_message_size, sctp_parameters: dump .base .sctp_parameters @@ -340,6 +353,10 @@ enum Notification { SctpStateChange { sctp_state: SctpState, }, + #[serde(rename_all = "camelCase")] + SctpNegotiatedCapabilities { + negotiated_capabilities: SctpNegotiatedCapabilities, + }, Trace(TransportTraceEventData), } @@ -384,6 +401,25 @@ impl<'a> TryFromFbs<'a> for Notification { Ok(Notification::SctpStateChange { sctp_state }) } + notification::Event::TransportSctpNegotiatedCapabilities => { + let Ok(Some( + notification::BodyRef::TransportSctpNegotiatedCapabilitiesNotification(body), + )) = notification.body() + else { + panic!("Wrong message from worker: {notification:?}"); + }; + + let negotiated_capabilities = SctpNegotiatedCapabilities::from_fbs( + &sctp_association::SctpNegotiatedCapabilities::try_from( + body.negotiated_capabilities().unwrap().unwrap(), + ) + .unwrap(), + ); + + Ok(Notification::SctpNegotiatedCapabilities { + negotiated_capabilities, + }) + } notification::Event::TransportTrace => { let Ok(Some(notification::BodyRef::TransportTraceNotification(body))) = notification.body() @@ -405,6 +441,7 @@ struct Inner { id: TransportId, next_mid_for_consumers: AtomicUsize, used_sctp_stream_ids: Mutex>, + next_sctp_stream_id: Mutex, cname_for_producers: Mutex>, executor: Arc>, channel: Channel, @@ -413,6 +450,7 @@ struct Inner { app_data: AppData, // Make sure router is not dropped until this transport is not dropped router: Router, + sctp_negotiated_capabilities: Mutex>, closed: AtomicBool, // Drop subscription to transport-specific notifications when transport itself is dropped _subscription_handler: Mutex>, @@ -669,12 +707,23 @@ impl TransportImpl for PlainTransport { &self.inner.next_mid_for_consumers } + fn cname_for_producers(&self) -> &Mutex> { + &self.inner.cname_for_producers + } + + fn sctp_negotiated_max_outbound_streams(&self) -> Option { + self.inner + .sctp_negotiated_capabilities + .lock() + .map(|caps| caps.negotiated_max_outbound_streams) + } + fn used_sctp_stream_ids(&self) -> &Mutex> { &self.inner.used_sctp_stream_ids } - fn cname_for_producers(&self) -> &Mutex> { - &self.inner.cname_for_producers + fn next_sctp_stream_id(&self) -> &Mutex { + &self.inner.next_sctp_stream_id } } @@ -691,10 +740,12 @@ impl PlainTransport { let handlers = Arc::::default(); let data = Arc::new(data); + let sctp_negotiated_capabilities = Arc::new(Mutex::new(None::)); let subscription_handler = { let handlers = Arc::clone(&handlers); let data = Arc::clone(&data); + let sctp_negotiated_capabilities = Arc::clone(&sctp_negotiated_capabilities); channel.subscribe_to_notifications(id.into(), move |notification| { match Notification::try_from_fbs(notification) { @@ -716,6 +767,13 @@ impl PlainTransport { callback(sctp_state); }); } + Notification::SctpNegotiatedCapabilities { + negotiated_capabilities, + } => { + sctp_negotiated_capabilities + .lock() + .replace(negotiated_capabilities); + } Notification::Trace(trace_event_data) => { handlers.trace.call_simple(&trace_event_data); } @@ -729,15 +787,17 @@ impl PlainTransport { let next_mid_for_consumers = AtomicUsize::default(); let used_sctp_stream_ids = Mutex::new({ - let mut used_used_sctp_stream_ids = IntMap::default(); - if let Some(sctp_parameters) = &data.sctp_parameters { - for i in 0..sctp_parameters.mis { - used_used_sctp_stream_ids.insert(i, false); - } + let mut used_sctp_stream_ids = IntMap::default(); + + for i in 0..=65535 { + used_sctp_stream_ids.insert(i, false); } - used_used_sctp_stream_ids + + used_sctp_stream_ids }); + let next_sctp_stream_id = Mutex::new(0); let cname_for_producers = Mutex::new(None); + let sctp_negotiated_capabilities = Mutex::new(None); let inner_weak = Arc::>>>::default(); let on_router_close_handler = router.on_close({ let inner_weak = Arc::clone(&inner_weak); @@ -754,6 +814,7 @@ impl PlainTransport { id, next_mid_for_consumers, used_sctp_stream_ids, + next_sctp_stream_id, cname_for_producers, executor, channel, @@ -761,6 +822,7 @@ impl PlainTransport { data, app_data, router, + sctp_negotiated_capabilities, closed: AtomicBool::new(false), _subscription_handler: Mutex::new(subscription_handler), _on_router_close_handler: Mutex::new(on_router_close_handler), @@ -952,6 +1014,12 @@ impl PlainTransport { *self.inner.data.sctp_state.lock() } + /// SCTP negotiated capabilities. Or `None` if SCTP is not connected. + #[must_use] + pub fn sctp_negotiated_capabilities(&self) -> Option { + *self.inner.sctp_negotiated_capabilities.lock() + } + /// Local SRTP parameters representing the crypto suite and key material used to encrypt sending /// RTP and SRTP. Note that, if `comedia` mode is set, these local SRTP parameters may change /// after calling `connect()` with the remote SRTP parameters (to override the local SRTP crypto diff --git a/rust/src/router/transport.rs b/rust/src/router/transport.rs index 27898e9f19..c728f37509 100644 --- a/rust/src/router/transport.rs +++ b/rust/src/router/transport.rs @@ -435,17 +435,41 @@ pub(super) trait TransportImpl: TransportGeneric { fn next_mid_for_consumers(&self) -> &AtomicUsize; + fn cname_for_producers(&self) -> &Mutex>; + + /// Returns the negotiated max outbound SCTP streams (only known once the SCTP + /// association is connected). + /// Used by allocate_sctp_stream_id() to guard against exceeding negotiated limit. + fn sctp_negotiated_max_outbound_streams(&self) -> Option; + fn used_sctp_stream_ids(&self) -> &Mutex>; - fn cname_for_producers(&self) -> &Mutex>; + fn next_sctp_stream_id(&self) -> &Mutex; fn allocate_sctp_stream_id(&self) -> Option { - let mut used_sctp_stream_ids = self.used_sctp_stream_ids().lock(); - // This is simple, but not the fastest implementation, maybe worth improving - for (index, used) in used_sctp_stream_ids.iter_mut() { - if !*used { - *used = true; - return Some(*index); + let mut used = self.used_sctp_stream_ids().lock(); + let mut next_guard = self.next_sctp_stream_id().lock(); + + if let Some(max) = self.sctp_negotiated_max_outbound_streams() { + if *next_guard >= max { + warn!( + "SCTP next stream id exceeds negotiated max outbound streams, resetting to 0" + ); + *next_guard = 0; + } + } + + let len = 65535u32; + let start = *next_guard as u32; + + for i in 0..len { + let candidate = ((start + i) % len) as u16; + if let Some(is_used) = used.get_mut(&candidate) { + if !*is_used { + *is_used = true; + *next_guard = candidate.wrapping_add(1); + return Some(candidate); + } } } diff --git a/rust/src/router/webrtc_transport.rs b/rust/src/router/webrtc_transport.rs index 5a2db32615..a5fffe5585 100644 --- a/rust/src/router/webrtc_transport.rs +++ b/rust/src/router/webrtc_transport.rs @@ -23,12 +23,12 @@ use async_executor::Executor; use async_trait::async_trait; use event_listener_primitives::{Bag, BagOnce, HandlerId}; use log::{debug, error}; -use mediasoup_sys::fbs::{notification, response, transport, web_rtc_transport}; +use mediasoup_sys::fbs::{notification, response, sctp_association, transport, web_rtc_transport}; use mediasoup_types::data_structures::{ AppData, DtlsParameters, DtlsState, IceCandidate, IceParameters, IceRole, IceState, ListenInfo, SctpState, TransportTuple, }; -use mediasoup_types::sctp_parameters::{NumSctpStreams, SctpParameters}; +use mediasoup_types::sctp_parameters::{SctpNegotiatedCapabilities, SctpParameters}; use nohash_hasher::IntMap; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; @@ -136,14 +136,23 @@ pub struct WebRtcTransportOptions { /// Create a SCTP association. /// Default false. pub enable_sctp: bool, - /// SCTP streams number. - pub num_sctp_streams: NumSctpStreams, - /// Maximum allowed size for SCTP messages sent by DataProducers. - // Default 262144. - pub max_sctp_message_size: u32, - /// Maximum SCTP send buffer used by DataConsumers. - /// Default 262144. + /// Maximum allowed size for SCTP messages sent by DataConsumers (in bytes). + /// Default 262_144. + pub max_send_message_size: u32, + /// Maximum allowed size for SCTP messages received by DataProducers (in bytes). + /// Default 262_144. + pub max_receive_message_size: u32, + /// Maximum SCTP send buffer used by DataConsumers (in bytes). + /// Default 2_000_000. pub sctp_send_buffer_size: u32, + /// Per stream send queue size limit. Similar to `sctp_send_buffer_size`, but + /// limiting the size of individual streams. + /// Default 2_000_000. + pub sctp_per_stream_send_queue_limit: u32, + /// Maximum received window buffer size (in bytes). This should be a bit larger + /// than the largest sized message you want to be able to receive. + /// Default 5_242_880. + pub sctp_max_receiver_window_buffer_size: u32, /// Custom application data. pub app_data: AppData, } @@ -161,9 +170,11 @@ impl WebRtcTransportOptions { prefer_tcp: false, ice_consent_timeout: 30, enable_sctp: false, - num_sctp_streams: NumSctpStreams::default(), - max_sctp_message_size: 262_144, - sctp_send_buffer_size: 262_144, + max_send_message_size: 262_144, + max_receive_message_size: 262_144, + sctp_send_buffer_size: 2_000_000, + sctp_per_stream_send_queue_limit: 2_000_000, + sctp_max_receiver_window_buffer_size: 5_242_880, app_data: AppData::default(), } } @@ -179,9 +190,11 @@ impl WebRtcTransportOptions { prefer_tcp: false, ice_consent_timeout: 30, enable_sctp: false, - num_sctp_streams: NumSctpStreams::default(), - max_sctp_message_size: 262_144, - sctp_send_buffer_size: 262_144, + max_send_message_size: 262_144, + max_receive_message_size: 262_144, + sctp_send_buffer_size: 2_000_000, + sctp_per_stream_send_queue_limit: 2_000_000, + sctp_max_receiver_window_buffer_size: 5_242_880, app_data: AppData::default(), } } @@ -203,7 +216,8 @@ pub struct WebRtcTransportDump { pub data_consumer_ids: Vec, pub recv_rtp_header_extensions: RecvRtpHeaderExtensions, pub rtp_listener: RtpListener, - pub max_message_size: u32, + pub max_send_message_size: u32, + pub max_receive_message_size: u32, pub sctp_parameters: Option, pub sctp_state: Option, pub sctp_listener: Option, @@ -267,7 +281,8 @@ impl<'a> TryFromFbs<'a> for WebRtcTransportDump { dump.base.recv_rtp_header_extensions.as_ref(), ), rtp_listener: RtpListener::try_from_fbs(*dump.base.rtp_listener)?, - max_message_size: dump.base.max_message_size, + max_send_message_size: dump.base.max_send_message_size, + max_receive_message_size: dump.base.max_receive_message_size, sctp_parameters: dump .base .sctp_parameters @@ -431,6 +446,10 @@ enum Notification { SctpStateChange { sctp_state: SctpState, }, + #[serde(rename_all = "camelCase")] + SctpNegotiatedCapabilities { + negotiated_capabilities: SctpNegotiatedCapabilities, + }, Trace(TransportTraceEventData), } @@ -492,6 +511,25 @@ impl<'a> TryFromFbs<'a> for Notification { Ok(Notification::SctpStateChange { sctp_state }) } + notification::Event::TransportSctpNegotiatedCapabilities => { + let Ok(Some( + notification::BodyRef::TransportSctpNegotiatedCapabilitiesNotification(body), + )) = notification.body() + else { + panic!("Wrong message from worker: {notification:?}"); + }; + + let negotiated_capabilities = SctpNegotiatedCapabilities::from_fbs( + &sctp_association::SctpNegotiatedCapabilities::try_from( + body.negotiated_capabilities().unwrap().unwrap(), + ) + .unwrap(), + ); + + Ok(Notification::SctpNegotiatedCapabilities { + negotiated_capabilities, + }) + } notification::Event::TransportTrace => { let Ok(Some(notification::BodyRef::TransportTraceNotification(body))) = notification.body() @@ -513,6 +551,7 @@ struct Inner { id: TransportId, next_mid_for_consumers: AtomicUsize, used_sctp_stream_ids: Mutex>, + next_sctp_stream_id: Mutex, cname_for_producers: Mutex>, executor: Arc>, channel: Channel, @@ -523,6 +562,7 @@ struct Inner { webrtc_server: Option, // Make sure router is not dropped until this transport is not dropped router: Router, + sctp_negotiated_capabilities: Mutex>, closed: AtomicBool, // Drop subscription to transport-specific notifications when transport itself is dropped _subscription_handler: Mutex>, @@ -790,12 +830,23 @@ impl TransportImpl for WebRtcTransport { &self.inner.next_mid_for_consumers } + fn cname_for_producers(&self) -> &Mutex> { + &self.inner.cname_for_producers + } + + fn sctp_negotiated_max_outbound_streams(&self) -> Option { + self.inner + .sctp_negotiated_capabilities + .lock() + .map(|caps| caps.negotiated_max_outbound_streams) + } + fn used_sctp_stream_ids(&self) -> &Mutex> { &self.inner.used_sctp_stream_ids } - fn cname_for_producers(&self) -> &Mutex> { - &self.inner.cname_for_producers + fn next_sctp_stream_id(&self) -> &Mutex { + &self.inner.next_sctp_stream_id } } @@ -814,10 +865,12 @@ impl WebRtcTransport { let handlers = Arc::::default(); let data = Arc::new(data); + let sctp_negotiated_capabilities = Arc::new(Mutex::new(None::)); let subscription_handler = { let handlers = Arc::clone(&handlers); let data = Arc::clone(&data); + let sctp_negotiated_capabilities = Arc::clone(&sctp_negotiated_capabilities); channel.subscribe_to_notifications(id.into(), move |notification| { match Notification::try_from_fbs(notification) { @@ -857,6 +910,13 @@ impl WebRtcTransport { callback(sctp_state); }); } + Notification::SctpNegotiatedCapabilities { + negotiated_capabilities, + } => { + sctp_negotiated_capabilities + .lock() + .replace(negotiated_capabilities); + } Notification::Trace(trace_event_data) => { handlers.trace.call_simple(&trace_event_data); } @@ -870,15 +930,17 @@ impl WebRtcTransport { let next_mid_for_consumers = AtomicUsize::default(); let used_sctp_stream_ids = Mutex::new({ - let mut used_used_sctp_stream_ids = IntMap::default(); - if let Some(sctp_parameters) = &data.sctp_parameters { - for i in 0..sctp_parameters.mis { - used_used_sctp_stream_ids.insert(i, false); - } + let mut used_sctp_stream_ids = IntMap::default(); + + for i in 0..=65535 { + used_sctp_stream_ids.insert(i, false); } - used_used_sctp_stream_ids + + used_sctp_stream_ids }); + let next_sctp_stream_id = Mutex::new(0); let cname_for_producers = Mutex::new(None); + let sctp_negotiated_capabilities = Mutex::new(None); let inner_weak = Arc::>>>::default(); let on_webrtc_server_close_handler = webrtc_server.as_ref().map(|webrtc_server| { webrtc_server.on_close({ @@ -908,6 +970,7 @@ impl WebRtcTransport { id, next_mid_for_consumers, used_sctp_stream_ids, + next_sctp_stream_id, cname_for_producers, executor, channel, @@ -916,6 +979,7 @@ impl WebRtcTransport { app_data, webrtc_server, router, + sctp_negotiated_capabilities, closed: AtomicBool::new(false), _subscription_handler: Mutex::new(subscription_handler), _on_webrtc_server_close_handler: Mutex::new(on_webrtc_server_close_handler), @@ -1080,6 +1144,12 @@ impl WebRtcTransport { *self.inner.data.sctp_state.lock() } + /// SCTP negotiated capabilities. Or `None` if SCTP is not connected. + #[must_use] + pub fn sctp_negotiated_capabilities(&self) -> Option { + *self.inner.sctp_negotiated_capabilities.lock() + } + /// Restarts the ICE layer by generating new local ICE parameters that must be signaled to the /// remote endpoint. pub async fn restart_ice(&self) -> Result { diff --git a/rust/src/sctp_parameters.rs b/rust/src/sctp_parameters.rs index dfc44ec88e..6422d42f3e 100644 --- a/rust/src/sctp_parameters.rs +++ b/rust/src/sctp_parameters.rs @@ -1,29 +1,38 @@ //! SCTP parameters. use crate::fbs::{FromFbs, ToFbs}; -use mediasoup_sys::fbs::sctp_parameters; +use mediasoup_sys::fbs::{sctp_association, sctp_parameters}; use mediasoup_types::sctp_parameters::*; -impl ToFbs for NumSctpStreams { - type FbsType = sctp_parameters::NumSctpStreams; - - fn to_fbs(&self) -> Self::FbsType { - sctp_parameters::NumSctpStreams { - os: self.os, - mis: self.mis, - } - } -} - impl FromFbs for SctpParameters { type FbsType = sctp_parameters::SctpParameters; fn from_fbs(parameters: &Self::FbsType) -> Self { Self { port: parameters.port, - os: parameters.os, - mis: parameters.mis, - max_message_size: parameters.max_message_size, + max_send_message_size: parameters.max_send_message_size, + max_receive_message_size: parameters.max_receive_message_size, + send_buffer_size: parameters.send_buffer_size, + per_stream_send_queue_limit: parameters.per_stream_send_queue_limit, + max_receiver_window_buffer_size: parameters.max_receiver_window_buffer_size, + is_data_channel: parameters.is_data_channel, + + // TODO: SCTP: For backwards compatibility. Remove them in the future. + os: 65535, + mis: 65535, + max_message_size: parameters.max_receive_message_size, + } + } +} + +impl FromFbs for SctpNegotiatedCapabilities { + type FbsType = sctp_association::SctpNegotiatedCapabilities; + + fn from_fbs(negotiated_capabilities: &Self::FbsType) -> Self { + SctpNegotiatedCapabilities { + negotiated_max_outbound_streams: negotiated_capabilities + .negotiated_max_outbound_streams, + negotiated_max_inbound_streams: negotiated_capabilities.negotiated_max_inbound_streams, } } } diff --git a/rust/src/worker.rs b/rust/src/worker.rs index 5fe4d0e594..22be7036c7 100644 --- a/rust/src/worker.rs +++ b/rust/src/worker.rs @@ -192,10 +192,6 @@ pub struct WorkerSettings { /// /// Default `true`. pub enable_liburing: bool, - /// Use the mediasoup built-in SCTP stack instead usrsctp. - /// - /// Default `false`. - pub use_built_in_sctp_stack: bool, /// Function that will be called under worker thread before worker starts, can be used for /// pinning worker threads to CPU cores. pub thread_initializer: Option>, @@ -226,7 +222,6 @@ impl Default for WorkerSettings { dtls_files: None, libwebrtc_field_trials: None, enable_liburing: true, - use_built_in_sctp_stack: false, thread_initializer: None, app_data: AppData::default(), } @@ -242,7 +237,6 @@ impl fmt::Debug for WorkerSettings { dtls_files, libwebrtc_field_trials, enable_liburing, - use_built_in_sctp_stack, thread_initializer, app_data, } = self; @@ -254,7 +248,6 @@ impl fmt::Debug for WorkerSettings { .field("dtls_files", &dtls_files) .field("libwebrtc_field_trials", &libwebrtc_field_trials) .field("enable_liburing", &enable_liburing) - .field("use_built_in_sctp_stack", &use_built_in_sctp_stack) .field( "thread_initializer", &thread_initializer.as_ref().map(|_| "ThreadInitializer"), @@ -367,7 +360,6 @@ impl Inner { dtls_files, libwebrtc_field_trials, enable_liburing, - use_built_in_sctp_stack, thread_initializer, app_data, }: WorkerSettings, @@ -420,12 +412,6 @@ impl Inner { spawn_args.push("--disableLiburing=true".to_string()); } - if use_built_in_sctp_stack { - spawn_args.push("--useBuiltInSctpStack=true".to_string()); - } else { - spawn_args.push("--useBuiltInSctpStack=false".to_string()); - } - let id = WorkerId::new(); debug!( "spawning worker with arguments [id:{}]: {}", diff --git a/rust/tests/integration/direct_transport.rs b/rust/tests/integration/direct_transport.rs index 937940211e..f3cfe0090e 100644 --- a/rust/tests/integration/direct_transport.rs +++ b/rust/tests/integration/direct_transport.rs @@ -77,7 +77,8 @@ fn create_succeeds() { let transport1 = router .create_direct_transport({ let mut direct_transport_options = DirectTransportOptions::default(); - direct_transport_options.max_message_size = 1024; + direct_transport_options.max_send_message_size = 1024; + direct_transport_options.max_receive_message_size = 1024; direct_transport_options.app_data = AppData::new(CustomAppData { foo: "bar" }); direct_transport_options diff --git a/rust/tests/integration/plain_transport.rs b/rust/tests/integration/plain_transport.rs index 6009ed2988..fc929a41eb 100644 --- a/rust/tests/integration/plain_transport.rs +++ b/rust/tests/integration/plain_transport.rs @@ -180,13 +180,22 @@ fn create_succeeds() { assert_eq!( transport1.sctp_parameters(), Some(SctpParameters { - port: 5000, - os: 1024, - mis: 1024, + port: 5_000, + max_send_message_size: 262_144, + max_receive_message_size: 262_144, + send_buffer_size: 2_000_000, + per_stream_send_queue_limit: 2_000_000, + max_receiver_window_buffer_size: 5_242_880, + is_data_channel: false, + + // TODO: SCTP: For backwards compatibility. Remove them in the future. + os: 65535, + mis: 65535, max_message_size: 262_144, }), ); assert_eq!(transport1.sctp_state(), Some(SctpState::New)); + assert_eq!(transport1.sctp_negotiated_capabilities(), None); assert_eq!(transport1.srtp_parameters(), None); { diff --git a/rust/tests/integration/webrtc_transport.rs b/rust/tests/integration/webrtc_transport.rs index d07e4020b3..a90ae51df0 100644 --- a/rust/tests/integration/webrtc_transport.rs +++ b/rust/tests/integration/webrtc_transport.rs @@ -15,7 +15,7 @@ use mediasoup_types::data_structures::{ use mediasoup_types::rtp_parameters::{ MimeTypeAudio, MimeTypeVideo, RtpCodecCapability, RtpCodecParametersParameters, }; -use mediasoup_types::sctp_parameters::{NumSctpStreams, SctpParameters}; +use mediasoup_types::sctp_parameters::SctpParameters; use portpicker::pick_unused_port; use std::convert::TryInto; use std::env; @@ -173,11 +173,11 @@ fn create_succeeds() { .unwrap(), ); webrtc_transport_options.enable_sctp = true; - webrtc_transport_options.num_sctp_streams = NumSctpStreams { - os: 2048, - mis: 2048, - }; - webrtc_transport_options.max_sctp_message_size = 1000000; + webrtc_transport_options.max_send_message_size = 1000001; + webrtc_transport_options.max_receive_message_size = 1000002; + webrtc_transport_options.sctp_send_buffer_size = 2000001; + webrtc_transport_options.sctp_per_stream_send_queue_limit = 2000002; + webrtc_transport_options.sctp_max_receiver_window_buffer_size = 2000003; webrtc_transport_options.app_data = AppData::new(CustomAppData { foo: "bar" }); webrtc_transport_options @@ -199,10 +199,18 @@ fn create_succeeds() { assert_eq!( transport1.sctp_parameters(), Some(SctpParameters { - port: 5000, - os: 2048, - mis: 2048, - max_message_size: 1000000, + port: 5_000, + max_send_message_size: 1_000_001, + max_receive_message_size: 1_000_002, + send_buffer_size: 2000001, + per_stream_send_queue_limit: 2_000_002, + max_receiver_window_buffer_size: 2_000_003, + is_data_channel: true, + + // TODO: SCTP: For backwards compatibility. Remove them in the future. + os: 65535, + mis: 65535, + max_message_size: 1_000_002, }), ); { @@ -238,6 +246,7 @@ fn create_succeeds() { assert_eq!(transport1.dtls_parameters().role, DtlsRole::Auto); assert_eq!(transport1.dtls_state(), DtlsState::New); assert_eq!(transport1.sctp_state(), Some(SctpState::New)); + assert_eq!(transport1.sctp_negotiated_capabilities(), None); { let transport_dump = transport1 diff --git a/rust/types/CHANGELOG.md b/rust/types/CHANGELOG.md index 125238e3df..a04bbad4dd 100644 --- a/rust/types/CHANGELOG.md +++ b/rust/types/CHANGELOG.md @@ -2,6 +2,10 @@ ### NEXT +- New built-in SCTP stack (PR #1806): + - Remove `NumSctpStreams` type. + - Add `SctpNegotiatedCapabilities` type. + ### 0.3.0 - `RtpHeaderExtensionUri`: Add `SsrcAudioLevel`, `AbsSendTime`, `TransportWideCcDraft01`, `DependencyDescriptor`, `AbsCaptureTime`, `PlayoutDelay` and `MediasoupPacketId` variants. Rename `AudioLevel` to `SsrcAudioLevel` (PR #1631). diff --git a/rust/types/src/sctp_parameters.rs b/rust/types/src/sctp_parameters.rs index d56e9a1aa1..80e0cec9d5 100644 --- a/rust/types/src/sctp_parameters.rs +++ b/rust/types/src/sctp_parameters.rs @@ -2,62 +2,40 @@ use serde::{Deserialize, Serialize}; -/// Number of SCTP streams. -/// -/// Both OS and MIS are part of the SCTP INIT+ACK handshake. OS refers to the initial number of -/// outgoing SCTP streams that the server side transport creates (to be used by -/// [DataConsumer](https://docs.rs/mediasoup/latest/mediasoup/data_consumer/enum.DataConsumer.html)s), -/// while MIS refers to the maximum number of incoming SCTP streams that the server side transport -/// can receive (to be used by [DataProducer](https://docs.rs/mediasoup/latest/mediasoup/data_producer/enum.DataProducer.html)s). -/// So, if the server side transport will just re used to create data producers (but no data consumers), -/// OS can be low (~1). However, if data consumers are desired on the server side transport, OS must -/// have a proper value and such a proper value depends on whether the remote endpoint supports -/// `SCTP_ADD_STREAMS` extension or not. -/// -/// libwebrtc (Chrome, Safari, etc) does not enable `SCTP_ADD_STREAMS` so, if data consumers are -/// required, OS should be 1024 (the maximum number of DataChannels that libwebrtc enables). -/// -/// Firefox does enable `SCTP_ADD_STREAMS` so, if data consumers are required, OS can be lower (16 -/// for instance). The mediasoup transport will allocate and announce more outgoing SCTP streams -/// when needed. -/// -/// mediasoup-client provides specific per browser/version OS and MIS values via the -/// device.sctpCapabilities getter. -#[derive(Debug, Serialize, Copy, Clone)] -pub struct NumSctpStreams { - /// Initially requested number of outgoing SCTP streams. - #[serde(rename = "OS")] - pub os: u16, - /// Maximum number of incoming SCTP streams. - #[serde(rename = "MIS")] - pub mis: u16, -} - -impl Default for NumSctpStreams { - fn default() -> Self { - Self { - os: 1024, - mis: 1024, - } - } -} - /// Parameters of the SCTP association. #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct SctpParameters { - /// Must always equal 5000. pub port: u16, - /// Initially requested number of outgoing SCTP streams. + /// Maximum allowed size for SCTP send messages. + pub max_send_message_size: u32, + /// Maximum allowed size for SCTP receive messages. + pub max_receive_message_size: u32, + /// Size of the SCTP send buffer. + pub send_buffer_size: u32, + /// Per-stream send queue limit. + pub per_stream_send_queue_limit: u32, + /// Maximum receiver window buffer size. + pub max_receiver_window_buffer_size: u32, + /// Whether this is a DataChannel SCTP association. + pub is_data_channel: bool, + + // TODO: SCTP: For backwards compatibility. Remove them in the future. #[serde(rename = "OS")] pub os: u16, - /// Maximum number of incoming SCTP streams. #[serde(rename = "MIS")] pub mis: u16, - /// Maximum allowed size for SCTP messages. pub max_message_size: u32, } +/// SCTP negotiated capabilities (only available once SCTP association is connected). +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SctpNegotiatedCapabilities { + pub negotiated_max_outbound_streams: u16, + pub negotiated_max_inbound_streams: u16, +} + /// SCTP stream parameters describe the reliability of a certain SCTP stream. /// /// If ordered is true then `max_packet_life_time` and `max_retransmits` must be `false`. diff --git a/worker/.clang-format b/worker/.clang-format index 7ca24bba9b..004eccd5aa 100644 --- a/worker/.clang-format +++ b/worker/.clang-format @@ -54,14 +54,18 @@ FixNamespaceComments: true IncludeCategories: - Regex: '"common.hpp"' Priority: 1 - - Regex: '^"(Channel|PayloadChannel|FBS|RTC|Utils|handles)/' - Priority: 3 - - Regex: '"*"' + - Regex: '^"(Channel|PayloadChannel|FBS|Utils|handles)/' Priority: 2 - - Regex: '^<(flatbuffers|uv|openssl|srtp|usrsctp|libwebrtc)(.|/)' + - Regex: '^"(test|fuzzer)/' Priority: 4 - - Regex: '<*>' + - Regex: '^"(mocks)/' Priority: 5 + - Regex: '"*"' + Priority: 3 + - Regex: '^<(flatbuffers|uv|openssl|srtp|libwebrtc)(.|/)' + Priority: 6 + - Regex: '<*>' + Priority: 7 IncludeIsMainRegex: '$' IndentCaseLabels: true IndentWidth: 2 diff --git a/worker/deps/libwebrtc/libwebrtc/mediasoup_helpers.h b/worker/deps/libwebrtc/libwebrtc/mediasoup_helpers.h index 290818a37f..474ec31b5d 100644 --- a/worker/deps/libwebrtc/libwebrtc/mediasoup_helpers.h +++ b/worker/deps/libwebrtc/libwebrtc/mediasoup_helpers.h @@ -1,8 +1,8 @@ #ifndef LIBWEBRTC_MEDIASOUP_HELPERS_H #define LIBWEBRTC_MEDIASOUP_HELPERS_H -#include "modules/rtp_rtcp/source/rtp_packet/transport_feedback.h" #include "RTC/RTCP/FeedbackRtpTransport.hpp" +#include "modules/rtp_rtcp/source/rtp_packet/transport_feedback.h" #include #include diff --git a/worker/fbs/dataConsumer.fbs b/worker/fbs/dataConsumer.fbs index 0ad709b16f..99443ccf4a 100644 --- a/worker/fbs/dataConsumer.fbs +++ b/worker/fbs/dataConsumer.fbs @@ -1,9 +1,13 @@ include "common.fbs"; -include "dataProducer.fbs"; include "sctpParameters.fbs"; namespace FBS.DataConsumer; +enum Type: uint8 { + SCTP, + DIRECT +} + table GetBufferedAmountResponse { buffered_amount: uint32; } @@ -15,10 +19,11 @@ table SetBufferedAmountLowThresholdRequest { table DumpResponse { id: string (required); data_producer_id: string (required); - type: FBS.DataProducer.Type; + type: Type; sctp_stream_parameters: FBS.SctpParameters.SctpStreamParameters; label: string (required); protocol: string (required); + buffered_amount: uint32; buffered_amount_low_threshold: uint32; paused: bool; data_producer_paused: bool; diff --git a/worker/fbs/dataProducer.fbs b/worker/fbs/dataProducer.fbs index 69276b585f..4a5bba06d4 100644 --- a/worker/fbs/dataProducer.fbs +++ b/worker/fbs/dataProducer.fbs @@ -1,3 +1,4 @@ +include "common.fbs"; include "sctpParameters.fbs"; namespace FBS.DataProducer; diff --git a/worker/fbs/notification.fbs b/worker/fbs/notification.fbs index 35f029df25..1563687d5f 100644 --- a/worker/fbs/notification.fbs +++ b/worker/fbs/notification.fbs @@ -20,6 +20,7 @@ enum Event: uint8 { // Notifications from worker. WORKER_RUNNING, TRANSPORT_SCTP_STATE_CHANGE, + TRANSPORT_SCTP_NEGOTIATED_CAPABILITIES, TRANSPORT_TRACE, WEBRTCTRANSPORT_ICE_SELECTED_TUPLE_CHANGE, WEBRTCTRANSPORT_ICE_STATE_CHANGE, @@ -52,6 +53,7 @@ union Body { // Notifications to worker. Transport_SendRtcpNotification: FBS.Transport.SendRtcpNotification, Transport_SctpStateChangeNotification: FBS.Transport.SctpStateChangeNotification, + Transport_SctpNegotiatedCapabilitiesNotification: FBS.Transport.SctpNegotiatedCapabilitiesNotification, Producer_SendNotification: FBS.Producer.SendNotification, DataProducer_SendNotification: FBS.DataProducer.SendNotification, diff --git a/worker/fbs/sctpAssociation.fbs b/worker/fbs/sctpAssociation.fbs index 85e83c12a6..55d40c6bea 100644 --- a/worker/fbs/sctpAssociation.fbs +++ b/worker/fbs/sctpAssociation.fbs @@ -8,3 +8,7 @@ enum SctpState: uint8 { CLOSED, } +table SctpNegotiatedCapabilities { + negotiated_max_outbound_streams: uint16; + negotiated_max_inbound_streams: uint16; +} diff --git a/worker/fbs/sctpParameters.fbs b/worker/fbs/sctpParameters.fbs index 019eecd9b2..52efa74c4e 100644 --- a/worker/fbs/sctpParameters.fbs +++ b/worker/fbs/sctpParameters.fbs @@ -1,18 +1,12 @@ namespace FBS.SctpParameters; -table NumSctpStreams { - os: uint16 = 1024; - mis: uint16 = 1024; -} - table SctpParameters { - // Port is always 5000. - port: uint16 = 5000; - os: uint16; - mis: uint16; - max_message_size: uint32; + port: uint16; + max_send_message_size: uint32; + max_receive_message_size: uint32; send_buffer_size: uint32; - sctp_buffered_amount: uint32; + per_stream_send_queue_limit: uint32; + max_receiver_window_buffer_size: uint32; is_data_channel: bool; } @@ -22,4 +16,3 @@ table SctpStreamParameters { max_packet_life_time: uint16 = null; max_retransmits: uint16 = null; } - diff --git a/worker/fbs/transport.fbs b/worker/fbs/transport.fbs index 225cdd1171..6ecb53a2b0 100644 --- a/worker/fbs/transport.fbs +++ b/worker/fbs/transport.fbs @@ -1,6 +1,7 @@ include "common.fbs"; include "consumer.fbs"; include "dataProducer.fbs"; +include "dataConsumer.fbs"; include "rtpParameters.fbs"; include "sctpAssociation.fbs"; include "sctpParameters.fbs"; @@ -86,7 +87,7 @@ table ProduceDataRequest { table ConsumeDataRequest { data_consumer_id: string (required); data_producer_id: string (required); - type: FBS.DataProducer.Type; + type: FBS.DataConsumer.Type; sctp_stream_parameters: FBS.SctpParameters.SctpStreamParameters; label: string; protocol: string; @@ -122,14 +123,13 @@ table RecvRtpHeaderExtensions { table Options { direct: bool = false; - - /// Only needed for DirectTransport. This value is handled by base Transport. - max_message_size: uint32 = null; initial_available_outgoing_bitrate: uint32 = null; enable_sctp: bool = false; - num_sctp_streams: FBS.SctpParameters.NumSctpStreams; - max_sctp_message_size: uint32; + max_send_message_size: uint32; + max_receive_message_size: uint32; sctp_send_buffer_size: uint32; + sctp_per_stream_send_queue_limit: uint32; + sctp_max_receiver_window_buffer_size: uint32; is_data_channel: bool = false; } @@ -149,7 +149,8 @@ table Dump { data_consumer_ids: [string] (required); recv_rtp_header_extensions: RecvRtpHeaderExtensions (required); rtp_listener: RtpListener (required); - max_message_size: uint32; + max_send_message_size: uint32; + max_receive_message_size: uint32; sctp_parameters: FBS.SctpParameters.SctpParameters; sctp_state: FBS.SctpAssociation.SctpState = null; sctp_listener: SctpListener; @@ -227,6 +228,10 @@ table SctpStateChangeNotification { sctp_state: FBS.SctpAssociation.SctpState; } +table SctpNegotiatedCapabilitiesNotification { + negotiatedCapabilities: FBS.SctpAssociation.SctpNegotiatedCapabilities; +} + union TraceInfo { BweTraceInfo, } @@ -253,4 +258,3 @@ table TraceNotification { direction: FBS.Common.TraceDirection; info: TraceInfo; } - diff --git a/worker/fuzzer/src/RTC/FuzzerRateCalculator.cpp b/worker/fuzzer/src/RTC/FuzzerRateCalculator.cpp index d41c48a187..d063592efe 100644 --- a/worker/fuzzer/src/RTC/FuzzerRateCalculator.cpp +++ b/worker/fuzzer/src/RTC/FuzzerRateCalculator.cpp @@ -1,8 +1,8 @@ #include "RTC/FuzzerRateCalculator.hpp" #include "DepLibUV.hpp" -#include "Utils.hpp" #include "RTC/Consts.hpp" #include "RTC/RateCalculator.hpp" +#include "Utils.hpp" namespace { diff --git a/worker/fuzzer/src/RTC/FuzzerSeqManager.cpp b/worker/fuzzer/src/RTC/FuzzerSeqManager.cpp index 563d8d1b90..8c09c57fed 100644 --- a/worker/fuzzer/src/RTC/FuzzerSeqManager.cpp +++ b/worker/fuzzer/src/RTC/FuzzerSeqManager.cpp @@ -1,6 +1,6 @@ #include "RTC/FuzzerSeqManager.hpp" -#include "Utils.hpp" #include "RTC/SeqManager.hpp" +#include "Utils.hpp" #include void FuzzerRtcSeqManager::Fuzz(const uint8_t* data, size_t len) diff --git a/worker/fuzzer/src/RTC/FuzzerTrendCalculator.cpp b/worker/fuzzer/src/RTC/FuzzerTrendCalculator.cpp index 76d99e5dd4..5f663079f4 100644 --- a/worker/fuzzer/src/RTC/FuzzerTrendCalculator.cpp +++ b/worker/fuzzer/src/RTC/FuzzerTrendCalculator.cpp @@ -1,7 +1,7 @@ #include "RTC/FuzzerTrendCalculator.hpp" #include "DepLibUV.hpp" -#include "Utils.hpp" #include "RTC/TrendCalculator.hpp" +#include "Utils.hpp" void FuzzerRtcTrendCalculator::Fuzz(const uint8_t* data, size_t len) { diff --git a/worker/fuzzer/src/RTC/RTP/FuzzerRetransmissionBuffer.cpp b/worker/fuzzer/src/RTC/RTP/FuzzerRetransmissionBuffer.cpp index 5b31bece15..77b33419d0 100644 --- a/worker/fuzzer/src/RTC/RTP/FuzzerRetransmissionBuffer.cpp +++ b/worker/fuzzer/src/RTC/RTP/FuzzerRetransmissionBuffer.cpp @@ -1,8 +1,8 @@ #include "RTC/RTP/FuzzerRetransmissionBuffer.hpp" -#include "Utils.hpp" #include "RTC/RTP/Packet.hpp" #include "RTC/RTP/RetransmissionBuffer.hpp" #include "RTC/RTP/SharedPacket.hpp" +#include "Utils.hpp" void FuzzerRtcRtpRetransmissionBuffer::Fuzz(const uint8_t* data, size_t len) { diff --git a/worker/fuzzer/src/RTC/RTP/FuzzerRtpStreamSend.cpp b/worker/fuzzer/src/RTC/RTP/FuzzerRtpStreamSend.cpp index 1d0b2502ec..6ac1304fb7 100644 --- a/worker/fuzzer/src/RTC/RTP/FuzzerRtpStreamSend.cpp +++ b/worker/fuzzer/src/RTC/RTP/FuzzerRtpStreamSend.cpp @@ -1,7 +1,7 @@ #include "RTC/RTP/FuzzerRtpStreamSend.hpp" +#include "RTC/RTP/SharedPacket.hpp" #include "Utils.hpp" #include "mocks/include/MockShared.hpp" -#include "RTC/RTP/SharedPacket.hpp" namespace { diff --git a/worker/fuzzer/src/RTC/SCTP/association/FuzzerStateCookie.cpp b/worker/fuzzer/src/RTC/SCTP/association/FuzzerStateCookie.cpp index 0f826e9c04..131d455032 100644 --- a/worker/fuzzer/src/RTC/SCTP/association/FuzzerStateCookie.cpp +++ b/worker/fuzzer/src/RTC/SCTP/association/FuzzerStateCookie.cpp @@ -1,6 +1,6 @@ #include "RTC/SCTP/FuzzerStateCookie.hpp" -#include "Utils.hpp" #include "RTC/SCTP/association/StateCookie.hpp" +#include "Utils.hpp" #include // std::memcpy() namespace diff --git a/worker/fuzzer/src/fuzzer.cpp b/worker/fuzzer/src/fuzzer.cpp index d70434afd7..e661e68e13 100644 --- a/worker/fuzzer/src/fuzzer.cpp +++ b/worker/fuzzer/src/fuzzer.cpp @@ -5,11 +5,7 @@ #include "DepLibUV.hpp" #include "DepLibWebRTC.hpp" #include "DepOpenSSL.hpp" -// TODO: Remove once we only use built-in SCTP stack. -#include "DepUsrSCTP.hpp" #include "FuzzerUtils.hpp" -#include "Settings.hpp" -#include "Utils.hpp" #include "RTC/DtlsTransport.hpp" #include "RTC/FuzzerDtlsTransport.hpp" #include "RTC/FuzzerRateCalculator.hpp" @@ -29,6 +25,8 @@ #include "RTC/RTP/FuzzerRtpStreamSend.hpp" #include "RTC/SCTP/FuzzerStateCookie.hpp" #include "RTC/SCTP/packet/FuzzerPacket.hpp" +#include "Settings.hpp" +#include "Utils.hpp" #include // std::getenv() #include #include // std::istringstream() @@ -146,11 +144,6 @@ namespace DepLibUV::ClassInit(); DepOpenSSL::ClassInit(); DepLibSRTP::ClassInit(); - // TODO: Remove once we only use built-in SCTP stack. - if (!Settings::configuration.useBuiltInSctpStack) - { - DepUsrSCTP::ClassInit(); - } DepLibWebRTC::ClassInit(); Utils::Crypto::ClassInit(); RTC::DtlsTransport::ClassInit(); diff --git a/worker/include/DepUsrSCTP.hpp b/worker/include/DepUsrSCTP.hpp deleted file mode 100644 index 2f7e7342e5..0000000000 --- a/worker/include/DepUsrSCTP.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef MS_DEP_USRSCTP_HPP -#define MS_DEP_USRSCTP_HPP - -#include "common.hpp" -#include "SharedInterface.hpp" -#include "RTC/SctpAssociation.hpp" -#include "handles/TimerHandleInterface.hpp" -#include - -class DepUsrSCTP -{ -private: - class Checker : public TimerHandleInterface::Listener - { - public: - explicit Checker(SharedInterface* shared); - ~Checker() override; - - public: - void Start(); - void Stop(); - - /* Pure virtual methods inherited from TimerHandleInterface::Listener. */ - public: - void OnTimer(TimerHandleInterface* timer) override; - - private: - TimerHandleInterface* timer{ nullptr }; - uint64_t lastCalledAtMs{ 0u }; - }; - -public: - static void ClassInit(); - static void ClassDestroy(); - static void CreateChecker(SharedInterface* shared); - static void CloseChecker(); - static uintptr_t GetNextSctpAssociationId(); - static void RegisterSctpAssociation(RTC::SctpAssociation* sctpAssociation); - static void DeregisterSctpAssociation(RTC::SctpAssociation* sctpAssociation); - static RTC::SctpAssociation* RetrieveSctpAssociation(uintptr_t id); - -private: - static thread_local Checker* checker; - static uint64_t numSctpAssociations; - static uintptr_t nextSctpAssociationId; - static absl::flat_hash_map mapIdSctpAssociation; -}; - -#endif diff --git a/worker/include/Logger.hpp b/worker/include/Logger.hpp index 8d480f05c0..24092d64f5 100644 --- a/worker/include/Logger.hpp +++ b/worker/include/Logger.hpp @@ -96,9 +96,9 @@ #define MS_LOGGER_HPP #include "common.hpp" +#include "Channel/ChannelSocket.hpp" #include "LogLevel.hpp" #include "Settings.hpp" -#include "Channel/ChannelSocket.hpp" #include // std::snprintf(), std::fprintf(), stdout, stderr #include // std::abort() #include diff --git a/worker/include/RTC/ActiveSpeakerObserver.hpp b/worker/include/RTC/ActiveSpeakerObserver.hpp index f7e9f9dcd2..a5723f531d 100644 --- a/worker/include/RTC/ActiveSpeakerObserver.hpp +++ b/worker/include/RTC/ActiveSpeakerObserver.hpp @@ -1,9 +1,9 @@ #ifndef MS_RTC_ACTIVE_SPEAKER_OBSERVER_HPP #define MS_RTC_ACTIVE_SPEAKER_OBSERVER_HPP -#include "SharedInterface.hpp" -#include "RTC/RtpObserver.hpp" #include "handles/TimerHandleInterface.hpp" +#include "RTC/RtpObserver.hpp" +#include "SharedInterface.hpp" #include #include diff --git a/worker/include/RTC/AudioLevelObserver.hpp b/worker/include/RTC/AudioLevelObserver.hpp index 4cca750eda..ba2d4581a6 100644 --- a/worker/include/RTC/AudioLevelObserver.hpp +++ b/worker/include/RTC/AudioLevelObserver.hpp @@ -1,9 +1,9 @@ #ifndef MS_RTC_AUDIO_LEVEL_OBSERVER_HPP #define MS_RTC_AUDIO_LEVEL_OBSERVER_HPP -#include "SharedInterface.hpp" -#include "RTC/RtpObserver.hpp" #include "handles/TimerHandleInterface.hpp" +#include "RTC/RtpObserver.hpp" +#include "SharedInterface.hpp" #include namespace RTC diff --git a/worker/include/RTC/Consumer.hpp b/worker/include/RTC/Consumer.hpp index 51b4d9e5ac..4d34754058 100644 --- a/worker/include/RTC/Consumer.hpp +++ b/worker/include/RTC/Consumer.hpp @@ -2,7 +2,6 @@ #define MS_RTC_CONSUMER_HPP #include "common.hpp" -#include "SharedInterface.hpp" #include "Channel/ChannelRequest.hpp" #include "Channel/ChannelSocket.hpp" #include "FBS/consumer.h" @@ -17,6 +16,7 @@ #include "RTC/RTP/RtpStreamSend.hpp" #include "RTC/RTP/SharedPacket.hpp" #include "RTC/RtpDictionaries.hpp" +#include "SharedInterface.hpp" #include #include #include diff --git a/worker/include/RTC/DataConsumer.hpp b/worker/include/RTC/DataConsumer.hpp index 2dcac9341f..7b7c746101 100644 --- a/worker/include/RTC/DataConsumer.hpp +++ b/worker/include/RTC/DataConsumer.hpp @@ -2,11 +2,11 @@ #define MS_RTC_DATA_CONSUMER_HPP #include "common.hpp" -#include "SharedInterface.hpp" #include "Channel/ChannelRequest.hpp" #include "Channel/ChannelSocket.hpp" #include "RTC/SCTP/public/Message.hpp" #include "RTC/SctpDictionaries.hpp" +#include "SharedInterface.hpp" #include #include @@ -24,17 +24,14 @@ namespace RTC virtual ~Listener() = default; public: - // TODO: SCTP: Remove when we migrate to the new SCTP stack. - virtual void OnDataConsumerSendMessage( - RTC::DataConsumer* dataConsumer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - onQueuedCallback* cb) = 0; virtual void OnDataConsumerSendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, onQueuedCallback* cb) = 0; virtual void OnDataConsumerNeedBufferedAmount( - RTC::DataConsumer* dataConsumer, uint32_t& bufferedAmount) = 0; + const RTC::DataConsumer* dataConsumer, uint32_t& bufferedAmount) const = 0; + virtual void OnDataConsumerNeedBufferedAmountLowThreshold( + const RTC::DataConsumer* dataConsumer, uint32_t& bufferedAmountLowThreshold) const = 0; + virtual void OnDataConsumerSetBufferedAmountLowThreshold( + const RTC::DataConsumer* dataConsumer, uint32_t bytes) const = 0; virtual void OnDataConsumerDataProducerClosed(RTC::DataConsumer* dataConsumer) = 0; }; @@ -96,17 +93,9 @@ namespace RTC void DataProducerResumed(); void SctpAssociationConnected(); void SctpAssociationClosed(); - void SetSctpAssociationBufferedAmount(uint32_t bufferedAmount); - void SctpAssociationSendBufferFull(); + void SctpBufferedAmountLow(uint32_t bufferedAmount) const; + void SctpSendBufferFull() const; void DataProducerClosed(); - // TODO: SCTP: Remove when we migrate to the new SCTP stack. - bool SendMessage( - const uint8_t* msg, - size_t len, - uint32_t ppid, - std::vector& subchannels, - std::optional requiredSubchannel, - const onQueuedCallback* cb = nullptr); bool SendMessage( RTC::SCTP::Message message, std::vector& subchannels, @@ -140,9 +129,6 @@ namespace RTC bool dataProducerClosed{ false }; size_t messagesSent{ 0u }; size_t bytesSent{ 0u }; - uint32_t bufferedAmount{ 0u }; - uint32_t bufferedAmountLowThreshold{ 0u }; - bool forceTriggerBufferedAmountLow{ false }; }; } // namespace RTC diff --git a/worker/include/RTC/DataProducer.hpp b/worker/include/RTC/DataProducer.hpp index 920b249384..64c654fb09 100644 --- a/worker/include/RTC/DataProducer.hpp +++ b/worker/include/RTC/DataProducer.hpp @@ -2,11 +2,11 @@ #define MS_RTC_DATA_PRODUCER_HPP #include "common.hpp" -#include "SharedInterface.hpp" #include "Channel/ChannelRequest.hpp" #include "Channel/ChannelSocket.hpp" #include "RTC/SCTP/public/Message.hpp" #include "RTC/SctpDictionaries.hpp" +#include "SharedInterface.hpp" #include #include @@ -23,14 +23,6 @@ namespace RTC public: virtual void OnDataProducerReceiveData(RTC::DataProducer* producer, size_t len) = 0; - // TODO: SCTP: Remove when we migrate to the new SCTP stack. - virtual void OnDataProducerMessageReceived( - RTC::DataProducer* dataProducer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - std::vector& subchannels, - std::optional requiredSubchannel) = 0; virtual void OnDataProducerMessageReceived( RTC::DataProducer* dataProducer, RTC::SCTP::Message message, @@ -73,13 +65,6 @@ namespace RTC { return this->paused; } - // TODO: SCTP: Remove when we migrate to the new SCTP stack. - void ReceiveMessage( - const uint8_t* msg, - size_t len, - uint32_t ppid, - std::vector& subchannels, - std::optional requiredSubchannel); void ReceiveMessage( RTC::SCTP::Message message, std::vector& subchannels, diff --git a/worker/include/RTC/DirectTransport.hpp b/worker/include/RTC/DirectTransport.hpp index 9c1ecd4428..f5200c713d 100644 --- a/worker/include/RTC/DirectTransport.hpp +++ b/worker/include/RTC/DirectTransport.hpp @@ -1,8 +1,8 @@ #ifndef MS_RTC_DIRECT_TRANSPORT_HPP #define MS_RTC_DIRECT_TRANSPORT_HPP -#include "SharedInterface.hpp" #include "RTC/Transport.hpp" +#include "SharedInterface.hpp" namespace RTC { @@ -30,13 +30,6 @@ namespace RTC RTC::Transport::onSendCallback* cb = nullptr) override; void SendRtcpPacket(RTC::RTCP::Packet* packet) override; void SendRtcpCompoundPacket(RTC::RTCP::CompoundPacket* packet) override; - // TODO: SCTP: Remove once we only use built-in SCTP stack. - void SendMessage( - RTC::DataConsumer* dataConsumer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - onQueuedCallback* cb = nullptr) override; void SendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, diff --git a/worker/include/RTC/DtlsTransport.hpp b/worker/include/RTC/DtlsTransport.hpp index 833918de9e..82c6f4ddd5 100644 --- a/worker/include/RTC/DtlsTransport.hpp +++ b/worker/include/RTC/DtlsTransport.hpp @@ -2,10 +2,10 @@ #define MS_RTC_DTLS_TRANSPORT_HPP #include "common.hpp" -#include "SharedInterface.hpp" #include "FBS/webRtcTransport.h" -#include "RTC/SrtpSession.hpp" #include "handles/TimerHandleInterface.hpp" +#include "RTC/SrtpSession.hpp" +#include "SharedInterface.hpp" #include #include #include diff --git a/worker/include/RTC/ICE/IceServer.hpp b/worker/include/RTC/ICE/IceServer.hpp index a47628906a..c67b2e80dd 100644 --- a/worker/include/RTC/ICE/IceServer.hpp +++ b/worker/include/RTC/ICE/IceServer.hpp @@ -2,11 +2,11 @@ #define MS_RTC_ICE_ICE_SERVER_HPP #include "common.hpp" -#include "SharedInterface.hpp" #include "FBS/webRtcTransport.h" +#include "handles/TimerHandleInterface.hpp" #include "RTC/ICE/StunPacket.hpp" #include "RTC/TransportTuple.hpp" -#include "handles/TimerHandleInterface.hpp" +#include "SharedInterface.hpp" #include #include #include diff --git a/worker/include/RTC/ICE/StunPacket.hpp b/worker/include/RTC/ICE/StunPacket.hpp index 86f9050f6f..5859a63a0f 100644 --- a/worker/include/RTC/ICE/StunPacket.hpp +++ b/worker/include/RTC/ICE/StunPacket.hpp @@ -2,8 +2,8 @@ #define MS_RTC_ICE_STUN_PACKET_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/Serializable.hpp" +#include "Utils.hpp" #include #include diff --git a/worker/include/RTC/KeyFrameRequestManager.hpp b/worker/include/RTC/KeyFrameRequestManager.hpp index 2ef55e5123..db15b9075a 100644 --- a/worker/include/RTC/KeyFrameRequestManager.hpp +++ b/worker/include/RTC/KeyFrameRequestManager.hpp @@ -1,8 +1,8 @@ #ifndef MS_KEY_FRAME_REQUEST_MANAGER_HPP #define MS_KEY_FRAME_REQUEST_MANAGER_HPP -#include "SharedInterface.hpp" #include "handles/TimerHandleInterface.hpp" +#include "SharedInterface.hpp" #include namespace RTC diff --git a/worker/include/RTC/NackGenerator.hpp b/worker/include/RTC/NackGenerator.hpp index 4b0eab51eb..f3d7e4c59c 100644 --- a/worker/include/RTC/NackGenerator.hpp +++ b/worker/include/RTC/NackGenerator.hpp @@ -2,10 +2,10 @@ #define MS_RTC_NACK_GENERATOR_HPP #include "common.hpp" -#include "SharedInterface.hpp" +#include "handles/TimerHandleInterface.hpp" #include "RTC/RTP/Packet.hpp" #include "RTC/SeqManager.hpp" -#include "handles/TimerHandleInterface.hpp" +#include "SharedInterface.hpp" #include #include #include diff --git a/worker/include/RTC/PipeTransport.hpp b/worker/include/RTC/PipeTransport.hpp index 59f3abdd4f..75318ea091 100644 --- a/worker/include/RTC/PipeTransport.hpp +++ b/worker/include/RTC/PipeTransport.hpp @@ -1,12 +1,12 @@ #ifndef MS_RTC_PIPE_TRANSPORT_HPP #define MS_RTC_PIPE_TRANSPORT_HPP -#include "SharedInterface.hpp" #include "FBS/pipeTransport.h" #include "RTC/SrtpSession.hpp" #include "RTC/Transport.hpp" #include "RTC/TransportTuple.hpp" #include "RTC/UdpSocket.hpp" +#include "SharedInterface.hpp" namespace RTC { @@ -48,13 +48,6 @@ namespace RTC RTC::Transport::onSendCallback* cb = nullptr) override; void SendRtcpPacket(RTC::RTCP::Packet* packet) override; void SendRtcpCompoundPacket(RTC::RTCP::CompoundPacket* packet) override; - // TODO: SCTP: Remove once we only use built-in SCTP stack. - void SendMessage( - RTC::DataConsumer* dataConsumer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - onQueuedCallback* cb = nullptr) override; void SendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, diff --git a/worker/include/RTC/PlainTransport.hpp b/worker/include/RTC/PlainTransport.hpp index 34c0e07e3b..ee2ac4fdaa 100644 --- a/worker/include/RTC/PlainTransport.hpp +++ b/worker/include/RTC/PlainTransport.hpp @@ -1,12 +1,12 @@ #ifndef MS_RTC_PLAIN_TRANSPORT_HPP #define MS_RTC_PLAIN_TRANSPORT_HPP -#include "SharedInterface.hpp" #include "FBS/plainTransport.h" #include "RTC/SrtpSession.hpp" #include "RTC/Transport.hpp" #include "RTC/TransportTuple.hpp" #include "RTC/UdpSocket.hpp" +#include "SharedInterface.hpp" #include namespace RTC @@ -42,13 +42,6 @@ namespace RTC RTC::Transport::onSendCallback* cb = nullptr) override; void SendRtcpPacket(RTC::RTCP::Packet* packet) override; void SendRtcpCompoundPacket(RTC::RTCP::CompoundPacket* packet) override; - // TODO: SCTP: Remove once we only use built-in SCTP stack. - void SendMessage( - RTC::DataConsumer* dataConsumer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - onQueuedCallback* cb = nullptr) override; void SendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, diff --git a/worker/include/RTC/Producer.hpp b/worker/include/RTC/Producer.hpp index 65f2e37fe2..533238a6cb 100644 --- a/worker/include/RTC/Producer.hpp +++ b/worker/include/RTC/Producer.hpp @@ -2,7 +2,6 @@ #define MS_RTC_PRODUCER_HPP #include "common.hpp" -#include "SharedInterface.hpp" #include "Channel/ChannelRequest.hpp" #include "Channel/ChannelSocket.hpp" #include "RTC/KeyFrameRequestManager.hpp" @@ -14,6 +13,7 @@ #include "RTC/RTP/Packet.hpp" #include "RTC/RTP/RtpStreamRecv.hpp" #include "RTC/RtpDictionaries.hpp" +#include "SharedInterface.hpp" #include #include diff --git a/worker/include/RTC/RTCP/FeedbackRtpNack.hpp b/worker/include/RTC/RTCP/FeedbackRtpNack.hpp index 0ace152ff0..371b1f7245 100644 --- a/worker/include/RTC/RTCP/FeedbackRtpNack.hpp +++ b/worker/include/RTC/RTCP/FeedbackRtpNack.hpp @@ -2,8 +2,8 @@ #define MS_RTC_RTCP_FEEDBACK_RTP_NACK_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/RTCP/FeedbackRtp.hpp" +#include "Utils.hpp" /* RFC 4585 * Generic NACK message (NACK) diff --git a/worker/include/RTC/RTCP/ReceiverReport.hpp b/worker/include/RTC/RTCP/ReceiverReport.hpp index a1d5b02a0e..fb2aa65286 100644 --- a/worker/include/RTC/RTCP/ReceiverReport.hpp +++ b/worker/include/RTC/RTCP/ReceiverReport.hpp @@ -2,8 +2,8 @@ #define MS_RTC_RTCP_RECEIVER_REPORT_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/RTCP/Packet.hpp" +#include "Utils.hpp" #include namespace RTC diff --git a/worker/include/RTC/RTP/Packet.hpp b/worker/include/RTC/RTP/Packet.hpp index 4bc8359cd3..e3a30e811c 100644 --- a/worker/include/RTC/RTP/Packet.hpp +++ b/worker/include/RTC/RTP/Packet.hpp @@ -2,13 +2,13 @@ #define MS_RTC_RTP_PACKET_HPP #include "common.hpp" -#include "Utils.hpp" #include "FBS/rtpPacket.h" #include "RTC/RTP/Codecs/DependencyDescriptor.hpp" #include "RTC/RTP/Codecs/PayloadDescriptorHandler.hpp" #include "RTC/RTP/HeaderExtensionIds.hpp" #include "RTC/RtpDictionaries.hpp" #include "RTC/Serializable.hpp" +#include "Utils.hpp" #ifdef MS_RTC_LOGGER_RTP #include "RTC/RtcLogger.hpp" #endif diff --git a/worker/include/RTC/RTP/RtpStream.hpp b/worker/include/RTC/RTP/RtpStream.hpp index 87edbe04a0..53f96ea48c 100644 --- a/worker/include/RTC/RTP/RtpStream.hpp +++ b/worker/include/RTC/RTP/RtpStream.hpp @@ -2,7 +2,6 @@ #define MS_RTC_RTP_RTP_STREAM_HPP #include "common.hpp" -#include "SharedInterface.hpp" #include "FBS/rtpStream.h" #include "RTC/RTCP/FeedbackPsFir.hpp" #include "RTC/RTCP/FeedbackPsPli.hpp" @@ -16,6 +15,7 @@ #include "RTC/RTP/Packet.hpp" #include "RTC/RTP/RtxStream.hpp" #include "RTC/RtpDictionaries.hpp" +#include "SharedInterface.hpp" #include #include diff --git a/worker/include/RTC/RTP/RtpStreamRecv.hpp b/worker/include/RTC/RTP/RtpStreamRecv.hpp index 4650488741..8f3d4a3b90 100644 --- a/worker/include/RTC/RTP/RtpStreamRecv.hpp +++ b/worker/include/RTC/RTP/RtpStreamRecv.hpp @@ -1,11 +1,11 @@ #ifndef MS_RTC_RTP_RTP_STREAM_RECV_HPP #define MS_RTC_RTP_RTP_STREAM_RECV_HPP +#include "handles/TimerHandleInterface.hpp" #include "RTC/NackGenerator.hpp" #include "RTC/RTCP/XrDelaySinceLastRr.hpp" #include "RTC/RTP/RtpStream.hpp" #include "RTC/RateCalculator.hpp" -#include "handles/TimerHandleInterface.hpp" #include namespace RTC diff --git a/worker/include/RTC/RTP/RtxStream.hpp b/worker/include/RTC/RTP/RtxStream.hpp index 627a89aae6..364c4e8586 100644 --- a/worker/include/RTC/RTP/RtxStream.hpp +++ b/worker/include/RTC/RTP/RtxStream.hpp @@ -2,12 +2,12 @@ #define MS_RTC_RTP_RTX_STREAM_HPP #include "common.hpp" -#include "SharedInterface.hpp" #include "FBS/rtxStream.h" #include "RTC/RTCP/ReceiverReport.hpp" #include "RTC/RTCP/SenderReport.hpp" #include "RTC/RTP/Packet.hpp" #include "RTC/RtpDictionaries.hpp" +#include "SharedInterface.hpp" #include namespace RTC diff --git a/worker/include/RTC/RateCalculator.hpp b/worker/include/RTC/RateCalculator.hpp index 17958e1a78..0be86398f5 100644 --- a/worker/include/RTC/RateCalculator.hpp +++ b/worker/include/RTC/RateCalculator.hpp @@ -2,8 +2,8 @@ #define MS_RTC_RATE_CALCULATOR_HPP #include "common.hpp" -#include "SharedInterface.hpp" #include "RTC/RTP/Packet.hpp" +#include "SharedInterface.hpp" #include namespace RTC diff --git a/worker/include/RTC/Router.hpp b/worker/include/RTC/Router.hpp index 371a335fd4..aae1f8a5c9 100644 --- a/worker/include/RTC/Router.hpp +++ b/worker/include/RTC/Router.hpp @@ -2,7 +2,6 @@ #define MS_RTC_ROUTER_HPP #include "common.hpp" -#include "SharedInterface.hpp" #include "Channel/ChannelRequest.hpp" #include "RTC/Consumer.hpp" #include "RTC/DataConsumer.hpp" @@ -14,6 +13,7 @@ #include "RTC/SCTP/public/Message.hpp" #include "RTC/Transport.hpp" #include "RTC/WebRtcServer.hpp" +#include "SharedInterface.hpp" #include #include #include @@ -49,8 +49,8 @@ namespace RTC void HandleRequest(Channel::ChannelRequest* request) override; private: - RTC::Transport* GetTransportById(const std::string& transportId) const; - RTC::RtpObserver* GetRtpObserverById(const std::string& rtpObserverId) const; + RTC::Transport* AssertAndGetTransportById(const std::string& transportId) const; + RTC::RtpObserver* AssertAndGetRtpObserverById(const std::string& rtpObserverId) const; void CheckNoTransport(const std::string& transportId) const; void CheckNoRtpObserver(const std::string& rtpObserverId) const; @@ -94,15 +94,6 @@ namespace RTC void OnTransportDataProducerPaused(RTC::Transport* transport, RTC::DataProducer* dataProducer) override; void OnTransportDataProducerResumed( RTC::Transport* transport, RTC::DataProducer* dataProducer) override; - // TODO: SCTP: Remove when we migrate to the new SCTP stack. - void OnTransportDataProducerMessageReceived( - RTC::Transport* transport, - RTC::DataProducer* dataProducer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - std::vector& subchannels, - std::optional requiredSubchannel) override; void OnTransportDataProducerMessageReceived( RTC::Transport* transport, RTC::DataProducer* dataProducer, diff --git a/worker/include/RTC/RtpObserver.hpp b/worker/include/RTC/RtpObserver.hpp index 296f07931d..bec8dea218 100644 --- a/worker/include/RTC/RtpObserver.hpp +++ b/worker/include/RTC/RtpObserver.hpp @@ -1,9 +1,9 @@ #ifndef MS_RTC_RTP_OBSERVER_HPP #define MS_RTC_RTP_OBSERVER_HPP -#include "SharedInterface.hpp" #include "RTC/Producer.hpp" #include "RTC/RTP/Packet.hpp" +#include "SharedInterface.hpp" #include namespace RTC diff --git a/worker/include/RTC/SCTP/TODO_SCTP.md b/worker/include/RTC/SCTP/TODO_SCTP.md deleted file mode 100644 index fa58370f9e..0000000000 --- a/worker/include/RTC/SCTP/TODO_SCTP.md +++ /dev/null @@ -1,103 +0,0 @@ -# TODO STCP - -## Related to mediasoup SCTP implementation - -- dcsctp uses µs (webrtc::Timestamp::Micros()) internally, while mediasoup uses ms (`DepLibUV::GetTimeMs()`). When porting dcsctp timeout/duration logic, make sure to convert accordingly. Do not mix units in the same field. - -- `Association`: When transitioning to CLOSED (due to failure while connecting or closure) we should emit a new event "stcpclosed" in all `DataProducers/Consumers`. - -- When receiving SCTP RE-CONFIG, we should emit "streamclosed" in those `DataProducers/DataConsumers` whose stream ID have been closed. - -- `OnAssociationFailed()` and `OnAssociationClosed()` should report an error (if present) to JS. - -- Rename all "Packet", "Chunk", "Parameter", "Error Cause", "Association", etc to lowcase everywhere (in code and comments). - -- Rename all "I_DATA" etc to `I-DATA" everywhere (in code and comments). - -- Probably add many more fields in `SctpOptions` given to the `Association` in `Transport.cpp`. - -- Must check those `maxSctpMessageSize`, `sctpSendBufferSize` in `Router.createXxxxTransport()` (also in Rust) which have default value of 262144. - -- Must consider also an option to set `SctpOptions::perStreamSendQueueLimit` which defaults to 2000000 bytes. - -- When running `test-PipeTransport.ts` and `test-werift-sctp.ts` with `useBuiltInSctpStack: true`, tests pass but those errors show up: - - ``` - mediasoup:ERROR:Worker (stderr) UnixStreamSocketHandle::Write() | uv_try_write() failed, trying uv_write(): broken pipe - ``` - -- We must remove `numSctpStreams` option given to `router.createXxxTransport()` and `NumSctpStreams` type. `OS` and `MIS` in `numSctpStreams` are just the max announced number of outbound and incoming SCTP streams, but in the new SCTP stack those should always be 65535. The max number of incoming and outgoing streams will be negotiated later with the SCTP INIT and INIT_ACK and will be the minimum of our values (65535) and the OS and MIS that the peer announces in its INIT or INIT_ACK. - - This is a breaking change. - - Remove it from `sctpParameters.fbs` and other FBS types (look for `MIS` or `mis`, etc). - - Remove it in Rust layer. - - We must also remove `device.sctpCapabilities` getter from mediasoup-client because anyway we are making up those values! - - Also must update the website documentation. - -- When we invoke `close()` on a `DataProducer/Consumer` in server, we must end calling `sctpAssociation->ResetStream([streamId])` so it sends `ReConfig` to peer. - -- In `transport.dump()` (maybe also in `getStats()`) we must properly obtain `OS` and `MIS` according to the number of SCTP streams negotiated via INIT + INIT_ACK. And if SCTP is not yet established, then... not sure. - - In `Association::FillBuffer()` we should not pass `this->sctpOptions.negotiatedMaxOutboundStreams/negotiatedMaxInboundStreams` but the current values. - -- We need to pass `isDataChannel` to `SCTP::Association` constructor as we do in former `SctpAssociation`. Also use it in `Association::FillBuffer()`. - - Well, let's see. If it's only for when changing number of OS/MIS... then the new SCTP stack doesn't support it so... - -- Fix `dataConsumer.getBufferedAmount()` which in usrsctp returns the data buffered for all data consumers in the transport but now it will be per `DataConsumer` (SCTP stream). - - In `DataConsumer` class rename `SetAssociationBufferedAmount()` to `SetBufferedAmount()`. - - In `DataConsumer` class revisit `SctpAssociationSendBufferFull()` method. - - Fix the documentation in the website which says: "The underlaying SCTP association uses a common send buffer for all data consumers, hence the value given by this method indicates the data buffered for all data consumers in the transport." - -- Look for "TODO: SCTP" everywhere (also in `worker/test/`). - -- Test Chrome/Canary with I-DATA (message interleaving): - - ```bash - /Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary \ - --force-fieldtrials="WebRTC-DataChannelMessageInterleaving/Enabled/" \ - --enable-logging=stderr \ - --v=1 \ - ``` - - ### Problem in ReassemblyQueue - - In dsctp there is an `absl::AnyInvocable`, which is a move-only callable, unlike `std::function` which requires the callable to be copyable. The standard equivalent is `std::move_only_function`, introduced in C++23. - - If you use C++23: - - ```cpp - std::vector> deferredActions; - ``` - - In C++20 there is no `std::move_only_function` (that is C++23). The problem is that `absl::AnyInvocable` accepts move-only callables, while `std::function` requires them to be copyable. - - This is relevant because in dcsctp the lambda captures `data = std::move(data)`, and `UserData` has its copy constructor deleted, so the resulting lambda is not copyable and `std::function` will reject it. - - The solution for C++20 is to move the `UserData` into a `shared_ptr` so that the lambda becomes copyable: - - ```cpp - std::vector> deferredActions; - ``` - - And when adding the action, instead of: - - ```cpp - // dcsctp - It works because AnyInvocable accepts move-only callables - deferred_actions.push_back( - [this, tsn, data = std::move(data)]() mutable { - queued_bytes_ -= data.size(); - Add(tsn, std::move(data)); - }); - ``` - - In your code: - - ```cpp - // C++20 - UserData is not copyable, so it is wrapped in shared_ptr - auto sharedData = std::make_shared(std::move(data)); - - this->deferredResetStreams->deferredActions.push_back( - [this, tsn, sharedData]() mutable - { - this->queuedBytes -= sharedData->GetPayloadLength(); - this->Add(tsn, std::move(*sharedData)); - }); - ``` diff --git a/worker/include/RTC/SCTP/association/Association.hpp b/worker/include/RTC/SCTP/association/Association.hpp index 22a31c2098..81140f1f9e 100644 --- a/worker/include/RTC/SCTP/association/Association.hpp +++ b/worker/include/RTC/SCTP/association/Association.hpp @@ -2,7 +2,7 @@ #define MS_RTC_SCTP_ASSOCIATION_HPP #include "common.hpp" -#include "SharedInterface.hpp" +#include "handles/BackoffTimerHandleInterface.hpp" #include "RTC/SCTP/association/AssociationListenerDeferrer.hpp" #include "RTC/SCTP/association/NegotiatedCapabilities.hpp" #include "RTC/SCTP/association/PacketSender.hpp" @@ -38,7 +38,7 @@ #include "RTC/SCTP/public/SctpOptions.hpp" #include "RTC/SCTP/public/SctpTypes.hpp" #include "RTC/SCTP/tx/RoundRobinSendQueue.hpp" -#include "handles/BackoffTimerHandleInterface.hpp" +#include "SharedInterface.hpp" #include #include #include @@ -171,7 +171,8 @@ namespace RTC explicit Association( const SctpOptions& sctpOptions, AssociationListenerInterface* listener, - SharedInterface* shared); + SharedInterface* shared, + bool isDataChannel); ~Association() override; @@ -225,7 +226,7 @@ namespace RTC * Retrieves the latest metrics. If the Association is not fully connected, * `std::nullopt` will be returned. */ - std::optional GetMetrics() const override; + std::optional MakeMetrics() const override; /** * Returns the currently set priority for an outgoing stream. The initial @@ -245,6 +246,12 @@ namespace RTC */ void SetMaxSendMessageSize(size_t maxMessageSize) override; + /** + * Returns the number of bytes of data currently queued to be sent in + * total. + */ + size_t GetTotalBufferedAmount() const override; + /** * Returns the number of bytes of data currently queued to be sent on a * given stream. @@ -262,7 +269,7 @@ namespace RTC * considered "low" for a given stream, which will trigger * `OnAssociationStreamBufferedAmountLow()` event. The default value is 0. */ - void SetBufferedAmountLowThreshold(uint16_t streamId, size_t bytes) override; + void SetStreamBufferedAmountLowThreshold(uint16_t streamId, size_t bytes) override; /** * Resetting streams is an asynchronous operation and the results will be @@ -325,6 +332,23 @@ namespace RTC */ void ReceiveSctpData(const uint8_t* data, size_t len) override; + /** + * Get negotiated max outbound streams. Returns 0 if the association is + * not yet connected. + */ + uint16_t GetNegotiatedMaxOutboundStreams() const override; + + /** + * Get negotiated max inbound streams. Returns 0 if the association is + * not yet connected. + */ + uint16_t GetNegotiatedMaxInboundStreams() const override; + + bool IsDataChannel() const override + { + return this->isDataChannel; + } + private: void InternalClose(Types::ErrorKind errorKind, const std::string_view& message); @@ -500,6 +524,8 @@ namespace RTC const std::unique_ptr t2ShutdownTimer; // Max SCTP Packet length. const size_t maxPacketLength; + // Whether this is DataChannel based SCTP. + bool isDataChannel; }; } // namespace SCTP } // namespace RTC diff --git a/worker/include/RTC/SCTP/association/HeartbeatHandler.hpp b/worker/include/RTC/SCTP/association/HeartbeatHandler.hpp index 99a32c8df8..c6d779a994 100644 --- a/worker/include/RTC/SCTP/association/HeartbeatHandler.hpp +++ b/worker/include/RTC/SCTP/association/HeartbeatHandler.hpp @@ -2,13 +2,13 @@ #define MS_RTC_SCTP_HEARTBEAT_HANDLER_HPP #include "common.hpp" -#include "SharedInterface.hpp" +#include "handles/BackoffTimerHandleInterface.hpp" #include "RTC/SCTP/association/TransmissionControlBlockContextInterface.hpp" #include "RTC/SCTP/packet/chunks/HeartbeatAckChunk.hpp" #include "RTC/SCTP/packet/chunks/HeartbeatRequestChunk.hpp" #include "RTC/SCTP/public/AssociationListenerInterface.hpp" #include "RTC/SCTP/public/SctpOptions.hpp" -#include "handles/BackoffTimerHandleInterface.hpp" +#include "SharedInterface.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/association/StateCookie.hpp b/worker/include/RTC/SCTP/association/StateCookie.hpp index 98e2b62ad7..f32d8609e9 100644 --- a/worker/include/RTC/SCTP/association/StateCookie.hpp +++ b/worker/include/RTC/SCTP/association/StateCookie.hpp @@ -2,10 +2,10 @@ #define MS_RTC_SCTP_STATE_COOKIE_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/association/NegotiatedCapabilities.hpp" #include "RTC/SCTP/public/SctpTypes.hpp" #include "RTC/Serializable.hpp" +#include "Utils.hpp" #include namespace RTC diff --git a/worker/include/RTC/SCTP/association/StreamResetHandler.hpp b/worker/include/RTC/SCTP/association/StreamResetHandler.hpp index 36d52d824f..2f4e6b0006 100644 --- a/worker/include/RTC/SCTP/association/StreamResetHandler.hpp +++ b/worker/include/RTC/SCTP/association/StreamResetHandler.hpp @@ -2,7 +2,8 @@ #define MS_RTC_SCTP_STREAM_RESET_HANDLER_HPP #include "common.hpp" -#include "SharedInterface.hpp" +#include "Utils/UnwrappedSequenceNumber.hpp" +#include "handles/BackoffTimerHandleInterface.hpp" #include "RTC/SCTP/association/TransmissionControlBlockContextInterface.hpp" #include "RTC/SCTP/packet/Packet.hpp" #include "RTC/SCTP/packet/chunks/ReConfigChunk.hpp" @@ -13,8 +14,7 @@ #include "RTC/SCTP/rx/DataTracker.hpp" #include "RTC/SCTP/rx/ReassemblyQueue.hpp" #include "RTC/SCTP/tx/RetransmissionQueue.hpp" -#include "Utils/UnwrappedSequenceNumber.hpp" -#include "handles/BackoffTimerHandleInterface.hpp" +#include "SharedInterface.hpp" #include #include diff --git a/worker/include/RTC/SCTP/association/TransmissionControlBlock.hpp b/worker/include/RTC/SCTP/association/TransmissionControlBlock.hpp index 1202a67982..6a435788e0 100644 --- a/worker/include/RTC/SCTP/association/TransmissionControlBlock.hpp +++ b/worker/include/RTC/SCTP/association/TransmissionControlBlock.hpp @@ -2,7 +2,7 @@ #define MS_RTC_SCTP_TRANSMISSION_CONTROL_BLOCK_HPP #include "common.hpp" -#include "SharedInterface.hpp" +#include "handles/BackoffTimerHandleInterface.hpp" #include "RTC/SCTP/association/HeartbeatHandler.hpp" #include "RTC/SCTP/association/NegotiatedCapabilities.hpp" #include "RTC/SCTP/association/PacketSender.hpp" @@ -17,7 +17,7 @@ #include "RTC/SCTP/tx/RetransmissionQueue.hpp" #include "RTC/SCTP/tx/RetransmissionTimeout.hpp" #include "RTC/SCTP/tx/SendQueueInterface.hpp" -#include "handles/BackoffTimerHandleInterface.hpp" +#include "SharedInterface.hpp" #include #include diff --git a/worker/include/RTC/SCTP/packet/TLV.hpp b/worker/include/RTC/SCTP/packet/TLV.hpp index e7390cb946..5ec7e35475 100644 --- a/worker/include/RTC/SCTP/packet/TLV.hpp +++ b/worker/include/RTC/SCTP/packet/TLV.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_TLV_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/Serializable.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/chunks/AnyInitChunk.hpp b/worker/include/RTC/SCTP/packet/chunks/AnyInitChunk.hpp index 7e0a3b6a3d..8381632072 100644 --- a/worker/include/RTC/SCTP/packet/chunks/AnyInitChunk.hpp +++ b/worker/include/RTC/SCTP/packet/chunks/AnyInitChunk.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_ANY_INIT_CHUNK_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Chunk.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/chunks/DataChunk.hpp b/worker/include/RTC/SCTP/packet/chunks/DataChunk.hpp index 4a1d8a0779..7415bf8608 100644 --- a/worker/include/RTC/SCTP/packet/chunks/DataChunk.hpp +++ b/worker/include/RTC/SCTP/packet/chunks/DataChunk.hpp @@ -2,9 +2,9 @@ #define MS_RTC_SCTP_DATA_CHUNK_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/UserData.hpp" #include "RTC/SCTP/packet/chunks/AnyDataChunk.hpp" +#include "Utils.hpp" #include namespace RTC diff --git a/worker/include/RTC/SCTP/packet/chunks/ForwardTsnChunk.hpp b/worker/include/RTC/SCTP/packet/chunks/ForwardTsnChunk.hpp index 3cc2b6e184..e021c2b4ec 100644 --- a/worker/include/RTC/SCTP/packet/chunks/ForwardTsnChunk.hpp +++ b/worker/include/RTC/SCTP/packet/chunks/ForwardTsnChunk.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_FORWARD_TSN_CHUNK_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/chunks/AnyForwardTsnChunk.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/chunks/IDataChunk.hpp b/worker/include/RTC/SCTP/packet/chunks/IDataChunk.hpp index d66839d0a0..30c375bc3a 100644 --- a/worker/include/RTC/SCTP/packet/chunks/IDataChunk.hpp +++ b/worker/include/RTC/SCTP/packet/chunks/IDataChunk.hpp @@ -2,9 +2,9 @@ #define MS_RTC_SCTP_I_DATA_CHUNK_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/UserData.hpp" #include "RTC/SCTP/packet/chunks/AnyDataChunk.hpp" +#include "Utils.hpp" #include namespace RTC diff --git a/worker/include/RTC/SCTP/packet/chunks/IForwardTsnChunk.hpp b/worker/include/RTC/SCTP/packet/chunks/IForwardTsnChunk.hpp index 423bcb59c8..029c0dbf85 100644 --- a/worker/include/RTC/SCTP/packet/chunks/IForwardTsnChunk.hpp +++ b/worker/include/RTC/SCTP/packet/chunks/IForwardTsnChunk.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_I_FORWARD_TSN_CHUNK_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/chunks/AnyForwardTsnChunk.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/chunks/InitAckChunk.hpp b/worker/include/RTC/SCTP/packet/chunks/InitAckChunk.hpp index fd7046c179..dfbc09fc46 100644 --- a/worker/include/RTC/SCTP/packet/chunks/InitAckChunk.hpp +++ b/worker/include/RTC/SCTP/packet/chunks/InitAckChunk.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_INIT_ACK_CHUNK_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/chunks/AnyInitChunk.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/chunks/InitChunk.hpp b/worker/include/RTC/SCTP/packet/chunks/InitChunk.hpp index 596f59fadf..827d74bdd5 100644 --- a/worker/include/RTC/SCTP/packet/chunks/InitChunk.hpp +++ b/worker/include/RTC/SCTP/packet/chunks/InitChunk.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_INIT_CHUNK_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/chunks/AnyInitChunk.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/chunks/SackChunk.hpp b/worker/include/RTC/SCTP/packet/chunks/SackChunk.hpp index 20d5fa26e6..bba7164092 100644 --- a/worker/include/RTC/SCTP/packet/chunks/SackChunk.hpp +++ b/worker/include/RTC/SCTP/packet/chunks/SackChunk.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_SACK_CHUNK_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Chunk.hpp" +#include "Utils.hpp" #include #include diff --git a/worker/include/RTC/SCTP/packet/chunks/ShutdownChunk.hpp b/worker/include/RTC/SCTP/packet/chunks/ShutdownChunk.hpp index 20d4c62e0c..bfc96e3a97 100644 --- a/worker/include/RTC/SCTP/packet/chunks/ShutdownChunk.hpp +++ b/worker/include/RTC/SCTP/packet/chunks/ShutdownChunk.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_SHUTDOWN_CHUNK_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Chunk.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/errorCauses/InvalidStreamIdentifierErrorCause.hpp b/worker/include/RTC/SCTP/packet/errorCauses/InvalidStreamIdentifierErrorCause.hpp index 8400c4cf89..e577a6ac97 100644 --- a/worker/include/RTC/SCTP/packet/errorCauses/InvalidStreamIdentifierErrorCause.hpp +++ b/worker/include/RTC/SCTP/packet/errorCauses/InvalidStreamIdentifierErrorCause.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_INVALID_STREAM_IDENTIFIER_ERROR_CAUSE_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/errorCauses/MissingMandatoryParameterErrorCause.hpp b/worker/include/RTC/SCTP/packet/errorCauses/MissingMandatoryParameterErrorCause.hpp index 08ee872635..61c207a9a3 100644 --- a/worker/include/RTC/SCTP/packet/errorCauses/MissingMandatoryParameterErrorCause.hpp +++ b/worker/include/RTC/SCTP/packet/errorCauses/MissingMandatoryParameterErrorCause.hpp @@ -2,9 +2,9 @@ #define MS_RTC_SCTP_MISSING_MANDATORY_PARAMETER_ERROR_CAUSE_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/Parameter.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/errorCauses/NoUserDataErrorCause.hpp b/worker/include/RTC/SCTP/packet/errorCauses/NoUserDataErrorCause.hpp index 3c497e2b9d..53388efba7 100644 --- a/worker/include/RTC/SCTP/packet/errorCauses/NoUserDataErrorCause.hpp +++ b/worker/include/RTC/SCTP/packet/errorCauses/NoUserDataErrorCause.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_NO_USER_DATA_ERROR_CAUSE_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/errorCauses/StaleCookieErrorCause.hpp b/worker/include/RTC/SCTP/packet/errorCauses/StaleCookieErrorCause.hpp index 88fbca98cd..c37ae3b55d 100644 --- a/worker/include/RTC/SCTP/packet/errorCauses/StaleCookieErrorCause.hpp +++ b/worker/include/RTC/SCTP/packet/errorCauses/StaleCookieErrorCause.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_STALE_COOKIE_ERROR_CAUSE_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/parameters/AddIncomingStreamsRequestParameter.hpp b/worker/include/RTC/SCTP/packet/parameters/AddIncomingStreamsRequestParameter.hpp index a6034551c3..52cff8f4c7 100644 --- a/worker/include/RTC/SCTP/packet/parameters/AddIncomingStreamsRequestParameter.hpp +++ b/worker/include/RTC/SCTP/packet/parameters/AddIncomingStreamsRequestParameter.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Parameter.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/parameters/AddOutgoingStreamsRequestParameter.hpp b/worker/include/RTC/SCTP/packet/parameters/AddOutgoingStreamsRequestParameter.hpp index 6361038902..8d8be88548 100644 --- a/worker/include/RTC/SCTP/packet/parameters/AddOutgoingStreamsRequestParameter.hpp +++ b/worker/include/RTC/SCTP/packet/parameters/AddOutgoingStreamsRequestParameter.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Parameter.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/parameters/CookiePreservativeParameter.hpp b/worker/include/RTC/SCTP/packet/parameters/CookiePreservativeParameter.hpp index 2ad769ee42..429cf9c929 100644 --- a/worker/include/RTC/SCTP/packet/parameters/CookiePreservativeParameter.hpp +++ b/worker/include/RTC/SCTP/packet/parameters/CookiePreservativeParameter.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_COOKIE_PRESERVATIVE_PARAMETER_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Parameter.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/parameters/IncomingSsnResetRequestParameter.hpp b/worker/include/RTC/SCTP/packet/parameters/IncomingSsnResetRequestParameter.hpp index 3d39f5e57f..b7d7b63893 100644 --- a/worker/include/RTC/SCTP/packet/parameters/IncomingSsnResetRequestParameter.hpp +++ b/worker/include/RTC/SCTP/packet/parameters/IncomingSsnResetRequestParameter.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_INCOMING_SSN_RESET_REQUEST_PARAMETER_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Parameter.hpp" +#include "Utils.hpp" #include namespace RTC diff --git a/worker/include/RTC/SCTP/packet/parameters/OutgoingSsnResetRequestParameter.hpp b/worker/include/RTC/SCTP/packet/parameters/OutgoingSsnResetRequestParameter.hpp index 5797f870ef..6539a3b419 100644 --- a/worker/include/RTC/SCTP/packet/parameters/OutgoingSsnResetRequestParameter.hpp +++ b/worker/include/RTC/SCTP/packet/parameters/OutgoingSsnResetRequestParameter.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_OUTGOING_SSN_RESET_REQUEST_PARAMETER_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Parameter.hpp" +#include "Utils.hpp" #include namespace RTC diff --git a/worker/include/RTC/SCTP/packet/parameters/ReconfigurationResponseParameter.hpp b/worker/include/RTC/SCTP/packet/parameters/ReconfigurationResponseParameter.hpp index 02d68d9193..b60f11b2c9 100644 --- a/worker/include/RTC/SCTP/packet/parameters/ReconfigurationResponseParameter.hpp +++ b/worker/include/RTC/SCTP/packet/parameters/ReconfigurationResponseParameter.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_RECONFIGURATION_RESPONSE_PARAMETER_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Parameter.hpp" +#include "Utils.hpp" #include #include diff --git a/worker/include/RTC/SCTP/packet/parameters/SsnTsnResetRequestParameter.hpp b/worker/include/RTC/SCTP/packet/parameters/SsnTsnResetRequestParameter.hpp index df1bc15794..9e74af680d 100644 --- a/worker/include/RTC/SCTP/packet/parameters/SsnTsnResetRequestParameter.hpp +++ b/worker/include/RTC/SCTP/packet/parameters/SsnTsnResetRequestParameter.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Parameter.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/parameters/SupportedAddressTypesParameter.hpp b/worker/include/RTC/SCTP/packet/parameters/SupportedAddressTypesParameter.hpp index 52e9813409..8a59e2f9aa 100644 --- a/worker/include/RTC/SCTP/packet/parameters/SupportedAddressTypesParameter.hpp +++ b/worker/include/RTC/SCTP/packet/parameters/SupportedAddressTypesParameter.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_SUPPORTED_ADDRESS_TYPES_PARAMETER_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Parameter.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/parameters/SupportedExtensionsParameter.hpp b/worker/include/RTC/SCTP/packet/parameters/SupportedExtensionsParameter.hpp index c1c930eed9..c2335f8464 100644 --- a/worker/include/RTC/SCTP/packet/parameters/SupportedExtensionsParameter.hpp +++ b/worker/include/RTC/SCTP/packet/parameters/SupportedExtensionsParameter.hpp @@ -2,9 +2,9 @@ #define MS_RTC_SCTP_SUPPORTED_EXTENSIONS_PARAMETER_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/Parameter.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/include/RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp b/worker/include/RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp index 118fff9cd2..24062f6e06 100644 --- a/worker/include/RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp +++ b/worker/include/RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp @@ -2,8 +2,8 @@ #define MS_RTC_SCTP_ZERO_CHECKSUM_ACCEPTABLE_PARAMETER_HPP #include "common.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/Parameter.hpp" +#include "Utils.hpp" #include #include diff --git a/worker/include/RTC/SCTP/public/AssociationInterface.hpp b/worker/include/RTC/SCTP/public/AssociationInterface.hpp index b528fac69c..e84b3a8cdc 100644 --- a/worker/include/RTC/SCTP/public/AssociationInterface.hpp +++ b/worker/include/RTC/SCTP/public/AssociationInterface.hpp @@ -72,7 +72,7 @@ namespace RTC * Retrieves the latest metrics. If the Association is not fully connected, * `std::nullopt` will be returned. */ - virtual std::optional GetMetrics() const = 0; + virtual std::optional MakeMetrics() const = 0; /** * Returns the currently set priority for an outgoing stream. The initial @@ -92,6 +92,12 @@ namespace RTC */ virtual void SetMaxSendMessageSize(size_t maxMessageSize) = 0; + /** + * Returns the number of bytes of data currently queued to be sent in + * total. + */ + virtual size_t GetTotalBufferedAmount() const = 0; + /** * Returns the number of bytes of data currently queued to be sent on a * given stream. @@ -109,7 +115,7 @@ namespace RTC * considered "low" for a given stream, which will trigger * `OnAssociationStreamBufferedAmountLow()` event. The default value is 0. */ - virtual void SetBufferedAmountLowThreshold(uint16_t streamId, size_t bytes) = 0; + virtual void SetStreamBufferedAmountLowThreshold(uint16_t streamId, size_t bytes) = 0; /** * Resetting streams is an asynchronous operation and the results will be @@ -171,6 +177,20 @@ namespace RTC * Receives SCTP data (hopefully an SCTP Packet) from the remote peer. */ virtual void ReceiveSctpData(const uint8_t* data, size_t len) = 0; + + /** + * Get negotiated max outbound streams. Returns 0 if the association is + * not yet connected. + */ + virtual uint16_t GetNegotiatedMaxOutboundStreams() const = 0; + + /** + * Get negotiated max inbound streams. Returns 0 if the association is + * not yet connected. + */ + virtual uint16_t GetNegotiatedMaxInboundStreams() const = 0; + + virtual bool IsDataChannel() const = 0; }; } // namespace SCTP } // namespace RTC diff --git a/worker/include/RTC/SCTP/public/AssociationListenerInterface.hpp b/worker/include/RTC/SCTP/public/AssociationListenerInterface.hpp index c568dc8dba..89a0ecc048 100644 --- a/worker/include/RTC/SCTP/public/AssociationListenerInterface.hpp +++ b/worker/include/RTC/SCTP/public/AssociationListenerInterface.hpp @@ -136,7 +136,7 @@ namespace RTC /** * Called when the total amount of data buffered (in the entire send * buffer, for all streams) falls to or below the threshold specified in - * SctpOptions::totalBufferedAmountLowThreshold`. + * `SctpOptions::totalBufferedAmountLowThreshold`. * * @remarks * - It is allowed to call methods in Association within this callback. diff --git a/worker/include/RTC/SCTP/public/SctpOptions.hpp b/worker/include/RTC/SCTP/public/SctpOptions.hpp index 09fbfa4443..310da32019 100644 --- a/worker/include/RTC/SCTP/public/SctpOptions.hpp +++ b/worker/include/RTC/SCTP/public/SctpOptions.hpp @@ -66,6 +66,12 @@ namespace RTC */ size_t perStreamSendQueueLimit{ 2000000 }; + /** + * The largest allowed message payload to be received. This value should + * be smaller than `maxReceiverWindowBufferSize`. + */ + size_t maxReceiveMessageSize{ 256 * 1024 }; + /** * Maximum received window buffer size. This should be a bit larger than * the largest sized message you want to be able to receive. This @@ -228,6 +234,7 @@ namespace RTC /** * Enable Partial Reliability Extension. + * * @see RFC 3758. */ bool enablePartialReliability{ true }; diff --git a/worker/include/RTC/SCTP/rx/DataTracker.hpp b/worker/include/RTC/SCTP/rx/DataTracker.hpp index c7f480c107..318ab3d599 100644 --- a/worker/include/RTC/SCTP/rx/DataTracker.hpp +++ b/worker/include/RTC/SCTP/rx/DataTracker.hpp @@ -2,12 +2,12 @@ #define MS_RTC_SCTP_DATA_TRACKER_HPP #include "common.hpp" +#include "Utils/UnwrappedSequenceNumber.hpp" +#include "handles/BackoffTimerHandleInterface.hpp" #include "RTC/SCTP/packet/Packet.hpp" #include "RTC/SCTP/packet/UserData.hpp" #include "RTC/SCTP/packet/chunks/SackChunk.hpp" #include "RTC/SCTP/public/SctpTypes.hpp" -#include "Utils/UnwrappedSequenceNumber.hpp" -#include "handles/BackoffTimerHandleInterface.hpp" #include #include #include diff --git a/worker/include/RTC/SCTP/rx/ReassemblyQueue.hpp b/worker/include/RTC/SCTP/rx/ReassemblyQueue.hpp index 67a1d240cc..3036b8b3d7 100644 --- a/worker/include/RTC/SCTP/rx/ReassemblyQueue.hpp +++ b/worker/include/RTC/SCTP/rx/ReassemblyQueue.hpp @@ -70,7 +70,7 @@ namespace RTC Types::UnwrappedTsn senderLastAssignedTsn; std::set streamIds; std::vector> deferredActions; - // TODO: Once we upgrade to C++23, replace with: + // TODO: SCTP: Once we upgrade to C++23, replace with: // std::vector> deferredActions; }; diff --git a/worker/include/RTC/SCTP/tx/RetransmissionQueue.hpp b/worker/include/RTC/SCTP/tx/RetransmissionQueue.hpp index b9488395eb..997faddfc2 100644 --- a/worker/include/RTC/SCTP/tx/RetransmissionQueue.hpp +++ b/worker/include/RTC/SCTP/tx/RetransmissionQueue.hpp @@ -2,6 +2,7 @@ #define MS_RTC_SCTP_RETRANSMISSION_QUEUE_HPP #include "common.hpp" +#include "handles/BackoffTimerHandleInterface.hpp" #include "RTC/SCTP/packet/Packet.hpp" #include "RTC/SCTP/packet/UserData.hpp" #include "RTC/SCTP/packet/chunks/ForwardTsnChunk.hpp" @@ -11,7 +12,6 @@ #include "RTC/SCTP/public/SctpOptions.hpp" #include "RTC/SCTP/tx/OutstandingData.hpp" #include "RTC/SCTP/tx/SendQueueInterface.hpp" -#include "handles/BackoffTimerHandleInterface.hpp" #include namespace RTC diff --git a/worker/include/RTC/SctpAssociation.hpp b/worker/include/RTC/SctpAssociation.hpp deleted file mode 100644 index e3fdcc222c..0000000000 --- a/worker/include/RTC/SctpAssociation.hpp +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef MS_RTC_OLD_SCTP_ASSOCIATION_HPP -#define MS_RTC_OLD_SCTP_ASSOCIATION_HPP - -#include "common.hpp" -#include "Utils.hpp" -#include "RTC/DataConsumer.hpp" -#include "RTC/DataProducer.hpp" -#include - -namespace RTC -{ - class SctpAssociation - { - public: - enum class SctpState : uint8_t - { - NEW = 1, - CONNECTING, - CONNECTED, - FAILED, - CLOSED - }; - - private: - enum class StreamDirection : uint8_t - { - INCOMING = 1, - OUTGOING - }; - - protected: - using onQueuedCallback = const std::function; - - public: - class Listener - { - public: - virtual ~Listener() = default; - - public: - virtual void OnSctpAssociationConnecting(RTC::SctpAssociation* sctpAssociation) = 0; - virtual void OnSctpAssociationConnected(RTC::SctpAssociation* sctpAssociation) = 0; - virtual void OnSctpAssociationFailed(RTC::SctpAssociation* sctpAssociation) = 0; - virtual void OnSctpAssociationClosed(RTC::SctpAssociation* sctpAssociation) = 0; - virtual void OnSctpAssociationSendData( - RTC::SctpAssociation* sctpAssociation, const uint8_t* data, size_t len) = 0; - virtual void OnSctpAssociationMessageReceived( - RTC::SctpAssociation* sctpAssociation, - uint16_t streamId, - const uint8_t* msg, - size_t len, - uint32_t ppid) = 0; - virtual void OnSctpAssociationBufferedAmount( - RTC::SctpAssociation* sctpAssociation, uint32_t len) = 0; - }; - - public: - static bool IsSctp(const uint8_t* data, size_t len) - { - // clang-format off - return ( - (len >= 12) && - // Must have Source Port Number and Destination Port Number set to 5000 (hack). - (Utils::Byte::Get2Bytes(data, 0) == 5000) && - (Utils::Byte::Get2Bytes(data, 2) == 5000) - ); - // clang-format on - } - - public: - SctpAssociation( - Listener* listener, - uint16_t os, - uint16_t mis, - size_t maxSctpMessageSize, - size_t sctpSendBufferSize, - bool isDataChannel); - ~SctpAssociation(); - - public: - flatbuffers::Offset FillBuffer( - flatbuffers::FlatBufferBuilder& builder) const; - void TransportConnected(); - void TransportDisconnected(); - SctpState GetState() const - { - return this->state; - } - size_t GetSctpBufferedAmount() const - { - return this->sctpBufferedAmount; - } - void ProcessSctpData(const uint8_t* data, size_t len); - void SendSctpMessage( - RTC::DataConsumer* dataConsumer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - onQueuedCallback* cb = nullptr); - void HandleDataProducer(RTC::DataProducer* dataProducer); - void HandleDataConsumer(RTC::DataConsumer* dataConsumer); - void DataProducerClosed(RTC::DataProducer* dataProducer); - void DataConsumerClosed(RTC::DataConsumer* dataConsumer); - - private: - void MayConnect(); - void ResetSctpStream(uint16_t streamId, StreamDirection direction) const; - void AddOutgoingStreams(bool force = false); - - /* Callbacks fired by usrsctp events. */ - public: - void OnUsrSctpSendSctpData(void* buffer, size_t len); - void OnUsrSctpReceiveSctpData( - uint16_t streamId, uint16_t ssn, uint32_t ppid, int flags, const uint8_t* data, size_t len); - void OnUsrSctpReceiveSctpNotification(union sctp_notification* notification, size_t len); - void OnUsrSctpSentData(uint32_t freeBuffer); - - public: - uintptr_t id{ 0u }; - - private: - // Passed by argument. - Listener* listener{ nullptr }; - uint16_t os{ 1024u }; - uint16_t mis{ 1024u }; - size_t maxSctpMessageSize{ 262144u }; - size_t sctpSendBufferSize{ 262144u }; - size_t sctpBufferedAmount{ 0u }; - bool isDataChannel{ false }; - // Allocated by this. - uint8_t* messageBuffer{ nullptr }; - // Others. - SctpState state{ SctpState::NEW }; - struct socket* socket{ nullptr }; - uint16_t desiredOs{ 0u }; - size_t messageBufferLen{ 0u }; - bool transportConnected{ false }; - // Whether at least one SCTP stream (AKA DataProducer or DataConsumer) has - // already been created, no matter it's still alive. - bool firstStreamCreated{ false }; - // Whether we have received STCP data from the remote peer. - bool sctpDataReceived{ false }; - uint16_t lastSsnReceived{ 0u }; // Valid for us since no SCTP I-DATA support. - }; -} // namespace RTC - -#endif diff --git a/worker/include/RTC/SenderBandwidthEstimator.hpp b/worker/include/RTC/SenderBandwidthEstimator.hpp index a1c0515369..31ae556e3b 100644 --- a/worker/include/RTC/SenderBandwidthEstimator.hpp +++ b/worker/include/RTC/SenderBandwidthEstimator.hpp @@ -2,11 +2,11 @@ #define MS_RTC_SENDER_BANDWIDTH_ESTIMATOR_HPP #include "common.hpp" -#include "SharedInterface.hpp" #include "RTC/RTCP/FeedbackRtpTransport.hpp" #include "RTC/RateCalculator.hpp" #include "RTC/SeqManager.hpp" #include "RTC/TrendCalculator.hpp" +#include "SharedInterface.hpp" #include namespace RTC diff --git a/worker/include/RTC/TcpServer.hpp b/worker/include/RTC/TcpServer.hpp index 383ae16ef4..08c8bdbf5d 100644 --- a/worker/include/RTC/TcpServer.hpp +++ b/worker/include/RTC/TcpServer.hpp @@ -2,10 +2,10 @@ #define MS_RTC_TCP_SERVER_HPP #include "common.hpp" -#include "RTC/TcpConnection.hpp" -#include "RTC/Transport.hpp" #include "handles/TcpConnectionHandle.hpp" #include "handles/TcpServerHandle.hpp" +#include "RTC/TcpConnection.hpp" +#include "RTC/Transport.hpp" #include namespace RTC diff --git a/worker/include/RTC/Transport.hpp b/worker/include/RTC/Transport.hpp index fa5fbc77bd..32ad92b484 100644 --- a/worker/include/RTC/Transport.hpp +++ b/worker/include/RTC/Transport.hpp @@ -22,16 +22,14 @@ #include "RTC/SCTP/public/AssociationListenerInterface.hpp" #include "RTC/SCTP/public/Message.hpp" #include "RTC/SCTP/public/SctpTypes.hpp" -// TODO: SCTP: Remove once we only use built-in SCTP stack. -#include "SharedInterface.hpp" -#include "RTC/SctpAssociation.hpp" #include "RTC/SctpListener.hpp" +#include "SharedInterface.hpp" #ifdef ENABLE_RTC_SENDER_BANDWIDTH_ESTIMATOR #include "RTC/SenderBandwidthEstimator.hpp" #endif +#include "handles/TimerHandleInterface.hpp" #include "RTC/TransportCongestionControlClient.hpp" #include "RTC/TransportCongestionControlServer.hpp" -#include "handles/TimerHandleInterface.hpp" #include #include #include @@ -43,8 +41,6 @@ namespace RTC public RTC::DataProducer::Listener, public RTC::DataConsumer::Listener, public RTC::SCTP::AssociationListenerInterface, - // TODO: SCTP: Remove once we only use built-in SCTP stack. - public RTC::SctpAssociation::Listener, public RTC::TransportCongestionControlClient::Listener, public RTC::TransportCongestionControlServer::Listener, public Channel::ChannelSocket::RequestHandler, @@ -107,15 +103,6 @@ namespace RTC RTC::Transport* transport, RTC::DataProducer* dataProducer) = 0; virtual void OnTransportDataProducerClosed( RTC::Transport* transport, RTC::DataProducer* dataProducer) = 0; - // TODO: SCTP: Remove when we migrate to the new SCTP stack. - virtual void OnTransportDataProducerMessageReceived( - RTC::Transport* transport, - RTC::DataProducer* dataProducer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - std::vector& subchannels, - std::optional requiredSubchannel) = 0; virtual void OnTransportDataProducerMessageReceived( RTC::Transport* transport, RTC::DataProducer* dataProducer, @@ -201,23 +188,17 @@ namespace RTC virtual void ReceiveRtpPacket(RTC::RTP::Packet* packet) final; virtual void ReceiveRtcpPacket(RTC::RTCP::Packet* packet) final; virtual void ReceiveSctpData(const uint8_t* data, size_t len) final; - // TODO: SCTP: Remove once we only use built-in SCTP stack. - virtual void SendSctpMessage( - RTC::DataConsumer* dataConsumer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - onQueuedCallback* cb = nullptr) final; virtual void SendSctpMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, onQueuedCallback* cb = nullptr) final; - virtual RTC::Producer* GetProducerById(const std::string& producerId) const final; - virtual RTC::Consumer* GetConsumerById(const std::string& consumerId) const final; - virtual RTC::Consumer* GetConsumerByMediaSsrc(uint32_t ssrc) const final; - virtual RTC::Consumer* GetConsumerByRtxSsrc(uint32_t ssrc) const final; - virtual RTC::DataProducer* GetDataProducerById(const std::string& dataProducerId) const final; - virtual RTC::DataConsumer* GetDataConsumerById(const std::string& dataConsumerId) const final; private: + virtual RTC::Producer* AssertAndGetProducerById(const std::string& producerId) const final; + virtual RTC::Consumer* AssertAndGetConsumerById(const std::string& consumerId) const final; + virtual RTC::Consumer* GetConsumerByMediaSsrc(uint32_t ssrc) const final; + virtual RTC::Consumer* GetConsumerByRtxSsrc(uint32_t ssrc) const final; + virtual RTC::DataProducer* AssertAndGetDataProducerById(const std::string& dataProducerId) const final; + virtual RTC::DataConsumer* AssertAndGetDataConsumerById(const std::string& dataConsumerId) const final; + virtual RTC::DataConsumer* GetSctpDataConsumerByStreamId(uint16_t streamId) const final; virtual bool IsConnected() const = 0; virtual void SendRtpPacket( RTC::Consumer* consumer, RTC::RTP::Packet* packet, const onSendCallback* cb = nullptr) = 0; @@ -225,13 +206,6 @@ namespace RTC virtual void SendRtcp(uint64_t nowMs) final; virtual void SendRtcpPacket(RTC::RTCP::Packet* packet) = 0; virtual void SendRtcpCompoundPacket(RTC::RTCP::CompoundPacket* packet) = 0; - // TODO: SCTP: Remove once we only use built-in SCTP stack. - virtual void SendMessage( - RTC::DataConsumer* dataConsumer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - onQueuedCallback* cb = nullptr) = 0; virtual void SendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, onQueuedCallback* cb = nullptr) = 0; virtual bool SendData(const uint8_t* data, size_t len) = 0; @@ -244,6 +218,7 @@ namespace RTC RTC::TransportCongestionControlClient::Bitrates& bitrates) const final; virtual void CheckNoDataProducer(const std::string& dataProducerId) const final; virtual void CheckNoDataConsumer(const std::string& dataConsumerId) const final; + virtual void CheckNoSctpDataConsumer(uint16_t streamId) const final; /* Pure virtual methods inherited from RTC::Producer::Listener. */ public: @@ -286,13 +261,6 @@ namespace RTC { this->DataReceived(len); } - void OnDataProducerMessageReceived( - RTC::DataProducer* dataProducer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - std::vector& subchannels, - std::optional requiredSubchannel) override; void OnDataProducerMessageReceived( RTC::DataProducer* dataProducer, RTC::SCTP::Message message, @@ -303,17 +271,14 @@ namespace RTC /* Pure virtual methods inherited from RTC::DataConsumer::Listener. */ public: - // TODO: SCTP: Remove when we migrate to the new SCTP stack. - void OnDataConsumerSendMessage( - RTC::DataConsumer* dataConsumer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - onQueuedCallback* cb = nullptr) override; void OnDataConsumerSendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, onQueuedCallback* cb) override; void OnDataConsumerNeedBufferedAmount( - RTC::DataConsumer* dataConsumer, uint32_t& bufferedAmount) override; + const RTC::DataConsumer* dataConsumer, uint32_t& bufferedAmount) const override; + void OnDataConsumerNeedBufferedAmountLowThreshold( + const RTC::DataConsumer* dataConsumer, uint32_t& bufferedAmountLowThreshold) const override; + void OnDataConsumerSetBufferedAmountLowThreshold( + const RTC::DataConsumer* dataConsumer, uint32_t bytes) const override; void OnDataConsumerDataProducerClosed(RTC::DataConsumer* dataConsumer) override; /* Pure virtual methods inherited from RTC::SCTP::AssociationListenerInterface. */ @@ -333,25 +298,6 @@ namespace RTC void OnAssociationStreamBufferedAmountLow(uint16_t streamId) override; void OnAssociationTotalBufferedAmountLow() override; bool OnAssociationIsTransportReadyForSctp() override; - // TODO: SCTP: Add OnAssociationLifecycleMessageXxxxxx() methods. - - /* Pure virtual methods inherited from RTC::SctpAssociation::Listener. */ - // TODO: SCTP: Remove once we only use built-in SCTP stack. - public: - void OnSctpAssociationConnecting(RTC::SctpAssociation* sctpAssociation) override; - void OnSctpAssociationConnected(RTC::SctpAssociation* sctpAssociation) override; - void OnSctpAssociationFailed(RTC::SctpAssociation* sctpAssociation) override; - void OnSctpAssociationClosed(RTC::SctpAssociation* sctpAssociation) override; - void OnSctpAssociationSendData( - RTC::SctpAssociation* sctpAssociation, const uint8_t* data, size_t len) override; - void OnSctpAssociationMessageReceived( - RTC::SctpAssociation* sctpAssociation, - uint16_t streamId, - const uint8_t* msg, - size_t len, - uint32_t ppid) override; - void OnSctpAssociationBufferedAmount( - RTC::SctpAssociation* sctpAssociation, uint32_t bufferedAmount) override; /* Pure virtual methods inherited from RTC::TransportCongestionControlClient::Listener. */ public: @@ -396,13 +342,12 @@ namespace RTC absl::flat_hash_map mapConsumers; absl::flat_hash_map mapDataProducers; absl::flat_hash_map mapDataConsumers; + absl::flat_hash_map mapSctpStreamIdDataConsumers; absl::flat_hash_map mapSsrcConsumer; absl::flat_hash_map mapRtxSsrcConsumer; TimerHandleInterface* rtcpTimer{ nullptr }; // Allocated by this. std::unique_ptr sctpAssociation{ nullptr }; - // TODO: SCTP: Remove once we only use built-in SCTP stack. - RTC::SctpAssociation* oldSctpAssociation{ nullptr }; std::shared_ptr tccClient{ nullptr }; std::shared_ptr tccServer{ nullptr }; #ifdef ENABLE_RTC_SENDER_BANDWIDTH_ESTIMATOR @@ -426,7 +371,14 @@ namespace RTC uint32_t maxIncomingBitrate{ 0u }; uint32_t maxOutgoingBitrate{ 0u }; uint32_t minOutgoingBitrate{ 0u }; - size_t maxMessageSize{ 262144u }; + // For SCTP capable transports and for direct transport. + size_t maxSendMessageSize{ 0u }; + size_t maxReceiveMessageSize{ 0u }; + // For SCTP capable transports. + size_t sctpSendBufferSize{ 0u }; + size_t sctpPerStreamSendQueueLimit{ 0u }; + size_t sctpMaxReceiverWindowBufferSize{ 0u }; + struct TraceEventTypes traceEventTypes; }; } // namespace RTC diff --git a/worker/include/RTC/TransportCongestionControlClient.hpp b/worker/include/RTC/TransportCongestionControlClient.hpp index f28f1848ef..17f37673fe 100644 --- a/worker/include/RTC/TransportCongestionControlClient.hpp +++ b/worker/include/RTC/TransportCongestionControlClient.hpp @@ -2,14 +2,14 @@ #define MS_RTC_TRANSPORT_CONGESTION_CONTROL_CLIENT_HPP #include "common.hpp" -#include "SharedInterface.hpp" +#include "handles/TimerHandleInterface.hpp" #include "RTC/BweType.hpp" #include "RTC/RTCP/FeedbackRtpTransport.hpp" #include "RTC/RTCP/ReceiverReport.hpp" #include "RTC/RTP/Packet.hpp" #include "RTC/RTP/ProbationGenerator.hpp" #include "RTC/TrendCalculator.hpp" -#include "handles/TimerHandleInterface.hpp" +#include "SharedInterface.hpp" #include #include #include diff --git a/worker/include/RTC/TransportCongestionControlServer.hpp b/worker/include/RTC/TransportCongestionControlServer.hpp index 737dbb67e0..54a0a9ae3a 100644 --- a/worker/include/RTC/TransportCongestionControlServer.hpp +++ b/worker/include/RTC/TransportCongestionControlServer.hpp @@ -2,13 +2,13 @@ #define MS_RTC_TRANSPORT_CONGESTION_CONTROL_SERVER_HPP #include "common.hpp" -#include "SharedInterface.hpp" +#include "handles/TimerHandleInterface.hpp" #include "RTC/BweType.hpp" #include "RTC/RTCP/FeedbackRtpTransport.hpp" #include "RTC/RTCP/Packet.hpp" #include "RTC/RTP/Packet.hpp" #include "RTC/SeqManager.hpp" -#include "handles/TimerHandleInterface.hpp" +#include "SharedInterface.hpp" #include #include diff --git a/worker/include/RTC/TransportTuple.hpp b/worker/include/RTC/TransportTuple.hpp index 518a87716c..aa69d6d11a 100644 --- a/worker/include/RTC/TransportTuple.hpp +++ b/worker/include/RTC/TransportTuple.hpp @@ -2,10 +2,10 @@ #define MS_RTC_TRANSPORT_TUPLE_HPP #include "common.hpp" -#include "Utils.hpp" #include "FBS/transport.h" #include "RTC/TcpConnection.hpp" #include "RTC/UdpSocket.hpp" +#include "Utils.hpp" #include #include diff --git a/worker/include/RTC/UdpSocket.hpp b/worker/include/RTC/UdpSocket.hpp index 97875ca346..d995ee251b 100644 --- a/worker/include/RTC/UdpSocket.hpp +++ b/worker/include/RTC/UdpSocket.hpp @@ -2,8 +2,8 @@ #define MS_RTC_UDP_SOCKET_HPP #include "common.hpp" -#include "RTC/Transport.hpp" #include "handles/UdpSocketHandle.hpp" +#include "RTC/Transport.hpp" #include namespace RTC diff --git a/worker/include/RTC/WebRtcServer.hpp b/worker/include/RTC/WebRtcServer.hpp index 17ccbf6c06..b59432e1a4 100644 --- a/worker/include/RTC/WebRtcServer.hpp +++ b/worker/include/RTC/WebRtcServer.hpp @@ -1,7 +1,6 @@ #ifndef MS_RTC_WEBRTC_SERVER_HPP #define MS_RTC_WEBRTC_SERVER_HPP -#include "SharedInterface.hpp" #include "Channel/ChannelRequest.hpp" #include "RTC/ICE/IceCandidate.hpp" #include "RTC/ICE/StunPacket.hpp" @@ -10,6 +9,7 @@ #include "RTC/TransportTuple.hpp" #include "RTC/UdpSocket.hpp" #include "RTC/WebRtcTransport.hpp" +#include "SharedInterface.hpp" #include #include #include diff --git a/worker/include/RTC/WebRtcTransport.hpp b/worker/include/RTC/WebRtcTransport.hpp index 58f18be047..4cc03b2138 100644 --- a/worker/include/RTC/WebRtcTransport.hpp +++ b/worker/include/RTC/WebRtcTransport.hpp @@ -1,7 +1,6 @@ #ifndef MS_RTC_WEBRTC_TRANSPORT_HPP #define MS_RTC_WEBRTC_TRANSPORT_HPP -#include "SharedInterface.hpp" #include "RTC/DtlsTransport.hpp" #include "RTC/ICE/IceCandidate.hpp" #include "RTC/ICE/IceServer.hpp" @@ -12,6 +11,7 @@ #include "RTC/Transport.hpp" #include "RTC/TransportTuple.hpp" #include "RTC/UdpSocket.hpp" +#include "SharedInterface.hpp" #include namespace RTC @@ -85,13 +85,6 @@ namespace RTC RTC::Transport::onSendCallback* cb = nullptr) override; void SendRtcpPacket(RTC::RTCP::Packet* packet) override; void SendRtcpCompoundPacket(RTC::RTCP::CompoundPacket* packet) override; - // TODO: SCTP: Remove once we only use built-in SCTP stack. - void SendMessage( - RTC::DataConsumer* dataConsumer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - onQueuedCallback* cb = nullptr) override; void SendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, diff --git a/worker/include/Settings.hpp b/worker/include/Settings.hpp index 16ead61896..9c9463ab41 100644 --- a/worker/include/Settings.hpp +++ b/worker/include/Settings.hpp @@ -2,8 +2,8 @@ #define MS_SETTINGS_HPP #include "common.hpp" -#include "LogLevel.hpp" #include "Channel/ChannelRequest.hpp" +#include "LogLevel.hpp" #include #include #include @@ -40,7 +40,6 @@ class Settings std::string dtlsPrivateKeyFile; std::string libwebrtcFieldTrials{ "WebRTC-Bwe-AlrLimitedBackoff/Enabled/" }; bool disableLiburing{ false }; - bool useBuiltInSctpStack{ false }; }; public: diff --git a/worker/include/Shared.hpp b/worker/include/Shared.hpp index ef57f092b0..df80c4bb65 100644 --- a/worker/include/Shared.hpp +++ b/worker/include/Shared.hpp @@ -1,10 +1,10 @@ #ifndef MS_SHARED_HPP #define MS_SHARED_HPP -#include "DepLibUV.hpp" -#include "SharedInterface.hpp" #include "Channel/ChannelMessageRegistrator.hpp" #include "Channel/ChannelNotifier.hpp" +#include "DepLibUV.hpp" +#include "SharedInterface.hpp" class Shared : public SharedInterface { diff --git a/worker/include/Worker.hpp b/worker/include/Worker.hpp index 1c5ac988df..280e4533c8 100644 --- a/worker/include/Worker.hpp +++ b/worker/include/Worker.hpp @@ -1,13 +1,13 @@ #ifndef MS_WORKER_HPP #define MS_WORKER_HPP -#include "SharedInterface.hpp" #include "Channel/ChannelRequest.hpp" #include "Channel/ChannelSocket.hpp" #include "FBS/worker.h" +#include "handles/SignalHandle.hpp" #include "RTC/Router.hpp" #include "RTC/WebRtcServer.hpp" -#include "handles/SignalHandle.hpp" +#include "SharedInterface.hpp" #include #include #include @@ -26,8 +26,8 @@ class Worker : public Channel::ChannelSocket::Listener, flatbuffers::Offset FillBufferResourceUsage( flatbuffers::FlatBufferBuilder& builder) const; void SetNewRouterId(std::string& routerId) const; - RTC::WebRtcServer* GetWebRtcServer(const std::string& webRtcServerId) const; - RTC::Router* GetRouter(const std::string& routerId) const; + RTC::WebRtcServer* AssertAndGetWebRtcServerById(const std::string& webRtcServerId) const; + RTC::Router* AssertAndGetRouterById(const std::string& routerId) const; void CheckNoWebRtcServer(const std::string& webRtcServerId) const; void CheckNoRouter(const std::string& routerId) const; diff --git a/worker/meson.build b/worker/meson.build index 09eb898221..7b94108934 100644 --- a/worker/meson.build +++ b/worker/meson.build @@ -88,8 +88,6 @@ common_sources = [ 'src/DepLibUV.cpp', 'src/DepLibWebRTC.cpp', 'src/DepOpenSSL.cpp', - # TODO: Remove once we only use built-in SCTP stack. - 'src/DepUsrSCTP.cpp', 'src/Logger.cpp', 'src/MediaSoupErrors.cpp', 'src/Settings.cpp', @@ -131,8 +129,6 @@ common_sources = [ 'src/RTC/RtcLogger.cpp', 'src/RTC/RtpListener.cpp', 'src/RTC/RtpObserver.cpp', - # TODO: Remove once we only use built-in SCTP stack. - 'src/RTC/SctpAssociation.cpp', 'src/RTC/SctpListener.cpp', 'src/RTC/SenderBandwidthEstimator.cpp', 'src/RTC/SeqManager.cpp', @@ -310,14 +306,6 @@ libsrtp3_proj = subproject( ], ) -usrsctp_proj = subproject( - 'usrsctp', - default_options: [ - 'warning_level=0', - 'sctp_build_programs=false', - ], -) - abseil_cpp_proj = subproject( 'abseil-cpp', default_options: [ @@ -345,7 +333,6 @@ dependencies = [ openssl_proj.get_variable('openssl_dep'), libuv_proj.get_variable('libuv_dep'), libsrtp3_proj.get_variable('libsrtp3_dep'), - usrsctp_proj.get_variable('usrsctp_dep'), flatbuffers_proj.get_variable('flatbuffers_dep'), flatbuffers_generator_dep, libwebrtc_dep, @@ -357,7 +344,6 @@ link_whole = [ openssl_proj.get_variable('libssl_lib'), libuv_proj.get_variable('libuv'), libsrtp3_proj.get_variable('libsrtp3'), - usrsctp_proj.get_variable('usrsctp'), flatbuffers_proj.get_variable('flatbuffers_lib'), libwebrtc, ] @@ -506,6 +492,7 @@ test_sources = [ 'test/src/RTC/SCTP/association/TestHeartbeatHandler.cpp', 'test/src/RTC/SCTP/association/TestNegotiatedCapabilities.cpp', 'test/src/RTC/SCTP/association/TestStateCookie.cpp', + 'test/src/RTC/SCTP/association/TestTransmissionControlBlock.cpp', 'test/src/RTC/SCTP/rx/TestDataTracker.cpp', 'test/src/RTC/SCTP/rx/TestInterleavedReassemblyStreams.cpp', 'test/src/RTC/SCTP/rx/TestReassemblyQueue.cpp', @@ -589,8 +576,6 @@ mediasoup_worker_test = executable( sources: common_sources + test_sources + mock_sources, include_directories: include_directories( 'include', - 'test/include', - 'mocks/include', ), cpp_args: cpp_args, ) @@ -610,8 +595,6 @@ mediasoup_worker_test_asan_address = executable( sources: common_sources + test_sources + mock_sources, include_directories: include_directories( 'include', - 'test/include', - 'mocks/include', ), cpp_args: cpp_args + [ '-g', @@ -639,8 +622,6 @@ mediasoup_worker_test_asan_undefined = executable( sources: common_sources + test_sources + mock_sources, include_directories: include_directories( 'include', - 'test/include', - 'mocks/include', ), cpp_args: cpp_args + [ '-g', @@ -713,8 +694,7 @@ executable( sources: common_sources + fuzzer_sources + mock_sources, include_directories: include_directories( 'include', - 'fuzzer/include', - 'mocks/include', + 'fuzzer/include' ), cpp_args: cpp_args + [ '-g', diff --git a/worker/mocks/include/MockShared.hpp b/worker/mocks/include/MockShared.hpp index a726db5b0e..cb0bd6166c 100644 --- a/worker/mocks/include/MockShared.hpp +++ b/worker/mocks/include/MockShared.hpp @@ -1,11 +1,11 @@ #ifndef MS_MOCKS_MOCK_SHARED_HPP #define MS_MOCKS_MOCK_SHARED_HPP +#include "Channel/ChannelNotifier.hpp" +#include "Channel/ChannelSocket.hpp" #include "SharedInterface.hpp" #include "mocks/include/Channel/MockChannelMessageRegistrator.hpp" #include "mocks/include/handles/MockBackoffTimerHandle.hpp" -#include "Channel/ChannelNotifier.hpp" -#include "Channel/ChannelSocket.hpp" #include #include #include diff --git a/worker/mocks/include/RTC/SCTP/association/MockTransmissionControlBlockContext.hpp b/worker/mocks/include/RTC/SCTP/association/MockTransmissionControlBlockContext.hpp index ccd0e63717..253ce2419a 100644 --- a/worker/mocks/include/RTC/SCTP/association/MockTransmissionControlBlockContext.hpp +++ b/worker/mocks/include/RTC/SCTP/association/MockTransmissionControlBlockContext.hpp @@ -2,11 +2,11 @@ #define MS_MOCKS_RTC_SCTP_MOCK_TRANSMISSION_CONTROL_BLOCK_HPP #include "common.hpp" -#include "mocks/include/mockTypes.hpp" #include "RTC/SCTP/association/TransmissionControlBlockContextInterface.hpp" #include "RTC/SCTP/packet/Packet.hpp" #include "RTC/SCTP/public/AssociationListenerInterface.hpp" #include "RTC/SCTP/public/SctpOptions.hpp" +#include "mocks/include/mockTypes.hpp" #include #include #include diff --git a/worker/mocks/include/RTC/SCTP/tx/MockSendQueue.hpp b/worker/mocks/include/RTC/SCTP/tx/MockSendQueue.hpp index 392c5b7d64..747c5c2eca 100644 --- a/worker/mocks/include/RTC/SCTP/tx/MockSendQueue.hpp +++ b/worker/mocks/include/RTC/SCTP/tx/MockSendQueue.hpp @@ -2,8 +2,8 @@ #define MS_MOCKS_RTC_SCTP_MOCK_SEND_QUEUE_HPP #include "common.hpp" -#include "mocks/include/mockTypes.hpp" #include "RTC/SCTP/tx/SendQueueInterface.hpp" +#include "mocks/include/mockTypes.hpp" #include #include #include @@ -35,8 +35,9 @@ namespace mocks ~MockSendQueue() override = default; public: - void EnableMessageInterleaving(bool /*enabled*/) override + void EnableMessageInterleaving(bool enabled) override { + this->messageInterleavingCalledWith = enabled; } std::optional Produce(uint64_t nowMs, size_t maxLength) override @@ -142,6 +143,13 @@ namespace mocks // Methods for testing. public: + MockSendQueue& ExpectEnableMessageInterleavingCalledWith(bool enabled) + { + this->expectedMessageInterleavingCalledWith = enabled; + + return *this; + } + MockSendQueue& WillProduceOnce(ProduceAction action) { this->produceOnceActions.push(std::move(action)); @@ -189,6 +197,17 @@ namespace mocks mocks::VerificationResult VerifyExpectations() const { + if ( + this->expectedMessageInterleavingCalledWith.has_value() && + this->messageInterleavingCalledWith != this->expectedMessageInterleavingCalledWith.value()) + { + return { .ok = false, + .errorMessage = + std::string("EnableMessageInterleaving() call mismatch [expected:") + + (this->expectedMessageInterleavingCalledWith.value() ? "true" : "false") + + ", got:" + (this->messageInterleavingCalledWith ? "true" : "false") + "]" }; + } + if ( this->expectedProduceCallCount.has_value() && this->produceCallCount != this->expectedProduceCallCount.value()) @@ -221,6 +240,10 @@ namespace mocks } private: + // EnableMessageInterleaving(). + bool messageInterleavingCalledWith{ false }; + std::optional expectedMessageInterleavingCalledWith; + // Produce(). std::queue produceOnceActions; ProduceAction produceRepeatedlyAction; diff --git a/worker/src/DepUsrSCTP.cpp b/worker/src/DepUsrSCTP.cpp deleted file mode 100644 index 1b72badaae..0000000000 --- a/worker/src/DepUsrSCTP.cpp +++ /dev/null @@ -1,283 +0,0 @@ -#define MS_CLASS "DepUsrSCTP" -// #define MS_LOG_DEV_LEVEL 3 - -#include "DepUsrSCTP.hpp" -#ifdef MS_LIBURING_SUPPORTED -#include "DepLibUring.hpp" -#endif -#include "DepLibUV.hpp" -#include "Logger.hpp" -#include -#include // std::vsnprintf() -#include - -/* Static. */ - -static constexpr size_t CheckerInterval{ 10u }; // In ms. -static std::mutex GlobalSyncMutex; -static size_t GlobalInstances{ 0u }; - -/* Static methods for usrsctp global callbacks. */ - -inline static int onSendSctpData(void* addr, void* data, size_t len, uint8_t /*tos*/, uint8_t /*setDf*/) -{ - auto* sctpAssociation = DepUsrSCTP::RetrieveSctpAssociation(reinterpret_cast(addr)); - - if (!sctpAssociation) - { - MS_WARN_TAG(sctp, "no SctpAssociation found"); - - return -1; - } - - sctpAssociation->OnUsrSctpSendSctpData(data, len); - - // NOTE: Must not free data, usrsctp lib does it. - - return 0; -} - -// Static method for printing usrsctp debug. -inline static void sctpDebug(const char* format, ...) -{ - char buffer[10000]; - va_list ap; - - va_start(ap, format); - vsnprintf(buffer, sizeof(buffer), format, ap); - - // Remove the artificial carriage return set by usrsctp. - buffer[std::strlen(buffer) - 1] = '\0'; - - MS_DEBUG_TAG(sctp, "%s", buffer); - - va_end(ap); -} - -/* Class variables. */ - -thread_local DepUsrSCTP::Checker* DepUsrSCTP::checker{ nullptr }; -uint64_t DepUsrSCTP::numSctpAssociations{ 0u }; -uintptr_t DepUsrSCTP::nextSctpAssociationId{ 0u }; -absl::flat_hash_map DepUsrSCTP::mapIdSctpAssociation; - -/* Static methods. */ - -void DepUsrSCTP::ClassInit() -{ - MS_TRACE(); - - MS_DEBUG_TAG(info, "usrsctp"); - - const std::scoped_lock lock(GlobalSyncMutex); - - if (GlobalInstances == 0) - { - usrsctp_init_nothreads(0, onSendSctpData, sctpDebug); - - // See https://github.com/sctplab/usrsctp/blob/master/Manual.md#usrsctp_sysctl_set_sctp_sendspace. - // - // TODO: This doesn't have any effect. So let's comment it. - // usrsctp_sysctl_set_sctp_sendspace(std::numeric_limits::max()); - // usrsctp_sysctl_set_sctp_recvspace(std::numeric_limits::max()); - - // Disable explicit congestion notifications (ecn). - usrsctp_sysctl_set_sctp_ecn_enable(0); - -#ifdef SCTP_DEBUG - usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); -#endif - } - - ++GlobalInstances; -} - -void DepUsrSCTP::ClassDestroy() -{ - MS_TRACE(); - - const std::scoped_lock lock(GlobalSyncMutex); - - --GlobalInstances; - - if (GlobalInstances == 0) - { - usrsctp_finish(); - - numSctpAssociations = 0u; - nextSctpAssociationId = 0u; - - DepUsrSCTP::mapIdSctpAssociation.clear(); - } -} - -void DepUsrSCTP::CreateChecker(SharedInterface* shared) -{ - MS_TRACE(); - - MS_ASSERT(DepUsrSCTP::checker == nullptr, "Checker already created"); - - DepUsrSCTP::checker = new DepUsrSCTP::Checker(shared); -} - -void DepUsrSCTP::CloseChecker() -{ - MS_TRACE(); - - MS_ASSERT(DepUsrSCTP::checker != nullptr, "Checker not created"); - - delete DepUsrSCTP::checker; -} - -uintptr_t DepUsrSCTP::GetNextSctpAssociationId() -{ - MS_TRACE(); - - const std::scoped_lock lock(GlobalSyncMutex); - - // NOTE: usrsctp_connect() fails with a value of 0. - if (DepUsrSCTP::nextSctpAssociationId == 0u) - { - ++DepUsrSCTP::nextSctpAssociationId; - } - - // In case we've wrapped around and need to find an empty spot from a removed - // SctpAssociation. Assumes we'll never be full. - while (DepUsrSCTP::mapIdSctpAssociation.find(DepUsrSCTP::nextSctpAssociationId) != - DepUsrSCTP::mapIdSctpAssociation.end()) - { - ++DepUsrSCTP::nextSctpAssociationId; - - if (DepUsrSCTP::nextSctpAssociationId == 0u) - { - ++DepUsrSCTP::nextSctpAssociationId; - } - } - - return DepUsrSCTP::nextSctpAssociationId++; -} - -void DepUsrSCTP::RegisterSctpAssociation(RTC::SctpAssociation* sctpAssociation) -{ - MS_TRACE(); - - const std::scoped_lock lock(GlobalSyncMutex); - - MS_ASSERT(DepUsrSCTP::checker != nullptr, "Checker not created"); - - auto it = DepUsrSCTP::mapIdSctpAssociation.find(sctpAssociation->id); - - MS_ASSERT( - it == DepUsrSCTP::mapIdSctpAssociation.end(), - "the id of the SctpAssociation is already in the map"); - - DepUsrSCTP::mapIdSctpAssociation[sctpAssociation->id] = sctpAssociation; - - if (++DepUsrSCTP::numSctpAssociations == 1u) - { - DepUsrSCTP::checker->Start(); - } -} - -void DepUsrSCTP::DeregisterSctpAssociation(RTC::SctpAssociation* sctpAssociation) -{ - MS_TRACE(); - - const std::scoped_lock lock(GlobalSyncMutex); - - MS_ASSERT(DepUsrSCTP::checker != nullptr, "Checker not created"); - - auto found = DepUsrSCTP::mapIdSctpAssociation.erase(sctpAssociation->id); - - MS_ASSERT(found > 0, "SctpAssociation not found"); - MS_ASSERT(DepUsrSCTP::numSctpAssociations > 0u, "numSctpAssociations was not higher than 0"); - - if (--DepUsrSCTP::numSctpAssociations == 0u) - { - DepUsrSCTP::checker->Stop(); - } -} - -RTC::SctpAssociation* DepUsrSCTP::RetrieveSctpAssociation(uintptr_t id) -{ - MS_TRACE(); - - const std::scoped_lock lock(GlobalSyncMutex); - - auto it = DepUsrSCTP::mapIdSctpAssociation.find(id); - - if (it == DepUsrSCTP::mapIdSctpAssociation.end()) - { - return nullptr; - } - - return it->second; -} - -/* DepUsrSCTP::Checker instance methods. */ - -DepUsrSCTP::Checker::Checker(SharedInterface* shared) : timer(shared->CreateTimer(this)) -{ - MS_TRACE(); -} - -DepUsrSCTP::Checker::~Checker() -{ - MS_TRACE(); - - delete this->timer; -} - -void DepUsrSCTP::Checker::Start() -{ - MS_TRACE(); - - MS_DEBUG_TAG(sctp, "usrsctp periodic check started"); - - this->lastCalledAtMs = 0u; - - this->timer->Start(CheckerInterval, CheckerInterval); -} - -void DepUsrSCTP::Checker::Stop() -{ - MS_TRACE(); - - MS_DEBUG_TAG(sctp, "usrsctp periodic check stopped"); - - this->lastCalledAtMs = 0u; - - this->timer->Stop(); -} - -void DepUsrSCTP::Checker::OnTimer(TimerHandleInterface* /*timer*/) -{ - MS_TRACE(); - - auto nowMs = DepLibUV::GetTimeMs(); - const int elapsedMs = this->lastCalledAtMs ? static_cast(nowMs - this->lastCalledAtMs) : 0; - -#ifdef MS_LIBURING_SUPPORTED - if (DepLibUring::IsEnabled()) - { - // Activate liburing usage. - // 'usrsctp_handle_timers()' will synchronously call the send/recv - // callbacks for the pending data. If there are multiple messages to be - // sent over the network then we will send those messages within a single - // system call. - DepLibUring::SetActive(); - } -#endif - - usrsctp_handle_timers(elapsedMs); - -#ifdef MS_LIBURING_SUPPORTED - if (DepLibUring::IsEnabled()) - { - // Submit all prepared submission entries. - DepLibUring::Submit(); - } -#endif - - this->lastCalledAtMs = nowMs; -} diff --git a/worker/src/RTC/DataConsumer.cpp b/worker/src/RTC/DataConsumer.cpp index bb17493a93..07adb8e38e 100644 --- a/worker/src/RTC/DataConsumer.cpp +++ b/worker/src/RTC/DataConsumer.cpp @@ -4,7 +4,6 @@ #include "RTC/DataConsumer.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" -#include "Settings.hpp" namespace RTC { @@ -27,13 +26,13 @@ namespace RTC switch (data->type()) { - case FBS::DataProducer::Type::SCTP: + case FBS::DataConsumer::Type::SCTP: { this->type = DataConsumer::Type::SCTP; break; } - case FBS::DataProducer::Type::DIRECT: + case FBS::DataConsumer::Type::DIRECT: { this->type = DataConsumer::Type::DIRECT; @@ -110,16 +109,28 @@ namespace RTC subchannels.emplace_back(subchannel); } + uint32_t bufferedAmount{ 0 }; + + this->listener->OnDataConsumerNeedBufferedAmount(this, bufferedAmount); + + uint32_t bufferedAmountLowThreshold{ 0 }; + + if (this->type == DataConsumer::Type::SCTP) + { + this->listener->OnDataConsumerNeedBufferedAmountLowThreshold(this, bufferedAmountLowThreshold); + } + return FBS::DataConsumer::CreateDumpResponseDirect( builder, this->id.c_str(), this->dataProducerId.c_str(), - this->type == DataConsumer::Type::SCTP ? FBS::DataProducer::Type::SCTP - : FBS::DataProducer::Type::DIRECT, + this->type == DataConsumer::Type::SCTP ? FBS::DataConsumer::Type::SCTP + : FBS::DataConsumer::Type::DIRECT, sctpStreamParameters, this->label.c_str(), this->protocol.c_str(), - this->bufferedAmountLowThreshold, + bufferedAmount, + bufferedAmountLowThreshold, this->paused, this->dataProducerPaused, std::addressof(subchannels)); @@ -130,6 +141,10 @@ namespace RTC { MS_TRACE(); + uint32_t bufferedAmount{ 0 }; + + this->listener->OnDataConsumerNeedBufferedAmount(this, bufferedAmount); + return FBS::DataConsumer::CreateGetStatsResponseDirect( builder, // timestamp. @@ -143,7 +158,7 @@ namespace RTC // bytesSent. this->bytesSent, // bufferedAmount. - this->bufferedAmount); + bufferedAmount); } void DataConsumer::HandleRequest(Channel::ChannelRequest* request) @@ -234,32 +249,12 @@ namespace RTC const auto* body = request->data->body_as(); + const auto bufferedAmountLowThreshold = static_cast(body->threshold()); - this->bufferedAmountLowThreshold = body->threshold(); + this->listener->OnDataConsumerSetBufferedAmountLowThreshold(this, bufferedAmountLowThreshold); request->Accept(); - // There is less or same buffered data than the given threshold. - // Trigger 'bufferedamountlow' now. - if (this->bufferedAmount <= this->bufferedAmountLowThreshold) - { - // Notify the Node DataConsumer. - auto bufferedAmountLowOffset = FBS::DataConsumer::CreateBufferedAmountLowNotification( - this->shared->GetChannelNotifier()->GetBufferBuilder(), this->bufferedAmount); - - this->shared->GetChannelNotifier()->Emit( - this->id, - FBS::Notification::Event::DATACONSUMER_BUFFERED_AMOUNT_LOW, - FBS::Notification::Body::DataConsumer_BufferedAmountLowNotification, - bufferedAmountLowOffset); - } - // Force the trigger of 'bufferedamountlow' once there is less or same - // buffered data than the given threshold. - else - { - this->forceTriggerBufferedAmountLow = true; - } - break; } @@ -295,23 +290,16 @@ namespace RTC } }); - static std::vector emptySubchannels; + static thread_local std::vector emptySubchannels; - if (Settings::configuration.useBuiltInSctpStack) - { - const uint16_t streamId = - this->type == DataConsumer::Type::SCTP ? this->sctpStreamParameters.streamId : 0; + const uint16_t streamId = + this->type == DataConsumer::Type::SCTP ? this->sctpStreamParameters.streamId : 0; - // NOTE: We are creating a copy of the data here, otherwise we cannot - // move the Message and pass its ownership to the SCTP stack. - RTC::SCTP::Message message(streamId, body->ppid(), std::vector(data, data + len)); + // NOTE: We are creating a copy of the data here, otherwise we cannot + // move the Message and pass its ownership to the SCTP stack. + RTC::SCTP::Message message(streamId, body->ppid(), std::vector(data, data + len)); - SendMessage(std::move(message), emptySubchannels, std::nullopt, cb); - } - else - { - SendMessage(data, len, body->ppid(), emptySubchannels, std::nullopt, cb); - } + SendMessage(std::move(message), emptySubchannels, std::nullopt, cb); break; } @@ -429,7 +417,7 @@ namespace RTC this->dataProducerPaused = true; - MS_DEBUG_DEV("DataProducer paused [dataConsumerId:%s]", this->id.c_str()); + MS_DEBUG_DEV("DataConsumer paused [dataConsumerId:%s]", this->id.c_str()); this->shared->GetChannelNotifier()->Emit( this->id, FBS::Notification::Event::DATACONSUMER_DATAPRODUCER_PAUSE); @@ -446,7 +434,7 @@ namespace RTC this->dataProducerPaused = false; - MS_DEBUG_DEV("DataProducer resumed [dataConsumerId:%s]", this->id.c_str()); + MS_DEBUG_DEV("DataConsumer resumed [dataConsumerId:%s]", this->id.c_str()); this->shared->GetChannelNotifier()->Emit( this->id, FBS::Notification::Event::DATACONSUMER_DATAPRODUCER_RESUME); @@ -470,34 +458,22 @@ namespace RTC MS_DEBUG_DEV("SctpAssociation closed [dataConsumerId:%s]", this->id.c_str()); } - void DataConsumer::SetSctpAssociationBufferedAmount(uint32_t bufferedAmount) + void DataConsumer::SctpBufferedAmountLow(uint32_t bufferedAmount) const { MS_TRACE(); - auto previousBufferedAmount = this->bufferedAmount; + // Notify the Node DataConsumer. + auto bufferedAmountLowOffset = FBS::DataConsumer::CreateBufferedAmountLowNotification( + this->shared->GetChannelNotifier()->GetBufferBuilder(), bufferedAmount); - this->bufferedAmount = bufferedAmount; - - if ( - (this->forceTriggerBufferedAmountLow || - previousBufferedAmount > this->bufferedAmountLowThreshold) && - this->bufferedAmount <= this->bufferedAmountLowThreshold) - { - this->forceTriggerBufferedAmountLow = false; - - // Notify the Node DataConsumer. - auto bufferedAmountLowOffset = FBS::DataConsumer::CreateBufferedAmountLowNotification( - this->shared->GetChannelNotifier()->GetBufferBuilder(), this->bufferedAmount); - - this->shared->GetChannelNotifier()->Emit( - this->id, - FBS::Notification::Event::DATACONSUMER_BUFFERED_AMOUNT_LOW, - FBS::Notification::Body::DataConsumer_BufferedAmountLowNotification, - bufferedAmountLowOffset); - } + this->shared->GetChannelNotifier()->Emit( + this->id, + FBS::Notification::Event::DATACONSUMER_BUFFERED_AMOUNT_LOW, + FBS::Notification::Body::DataConsumer_BufferedAmountLowNotification, + bufferedAmountLowOffset); } - void DataConsumer::SctpAssociationSendBufferFull() + void DataConsumer::SctpSendBufferFull() const { MS_TRACE(); @@ -513,7 +489,7 @@ namespace RTC this->dataProducerClosed = true; - MS_DEBUG_DEV("DataProducer closed [dataConsumerId:%s]", this->id.c_str()); + MS_DEBUG_DEV("DataConsumer closed [dataConsumerId:%s]", this->id.c_str()); this->shared->GetChannelNotifier()->Emit( this->id, FBS::Notification::Event::DATACONSUMER_DATAPRODUCER_CLOSE); @@ -521,96 +497,6 @@ namespace RTC this->listener->OnDataConsumerDataProducerClosed(this); } - // TODO: SCTP: Remove when we migrate to the new SCTP stack. - bool DataConsumer::SendMessage( - const uint8_t* msg, - size_t len, - uint32_t ppid, - std::vector& subchannels, - std::optional requiredSubchannel, - const onQueuedCallback* cb) - { - MS_TRACE(); - - if (!IsActive()) - { - if (cb) - { - (*cb)(false, false); - delete cb; - } - - return false; - } - - // If a required subchannel is given, verify that this data consumer is - // subscribed to it. - if ( - requiredSubchannel.has_value() && - this->subchannels.find(requiredSubchannel.value()) == this->subchannels.end()) - { - if (cb) - { - (*cb)(false, false); - delete cb; - } - - return false; - } - - // If subchannels are given, verify that this data consumer is subscribed - // to at least one of them. - if (!subchannels.empty()) - { - bool subchannelMatched{ false }; - - for (const auto subchannel : subchannels) - { - if (this->subchannels.find(subchannel) != this->subchannels.end()) - { - subchannelMatched = true; - - break; - } - } - - if (!subchannelMatched) - { - if (cb) - { - (*cb)(false, false); - delete cb; - } - - return false; - } - } - - if (len > this->maxMessageSize) - { - MS_WARN_TAG( - message, - "given message exceeds maxMessageSize value [maxMessageSize:%zu, len:%zu]", - len, - this->maxMessageSize); - - if (cb) - { - (*cb)(false, false); - delete cb; - } - - return false; - } - - this->messagesSent++; - this->bytesSent += len; - - this->listener->OnDataConsumerSendMessage(this, msg, len, ppid, cb); - - return true; - } - bool DataConsumer::SendMessage( RTC::SCTP::Message message, std::vector& subchannels, diff --git a/worker/src/RTC/DataProducer.cpp b/worker/src/RTC/DataProducer.cpp index 9cbf12f0e0..7967f9501b 100644 --- a/worker/src/RTC/DataProducer.cpp +++ b/worker/src/RTC/DataProducer.cpp @@ -229,21 +229,14 @@ namespace RTC requiredSubchannel = body->requiredSubchannel(); } - if (Settings::configuration.useBuiltInSctpStack) - { - const uint16_t streamId = - this->type == DataProducer::Type::SCTP ? this->sctpStreamParameters.streamId : 0; + const uint16_t streamId = + this->type == DataProducer::Type::SCTP ? this->sctpStreamParameters.streamId : 0; - // NOTE: We are creating a copy of the data here, otherwise we cannot - // move the Message and pass its ownership to the SCTP stack. - RTC::SCTP::Message message(streamId, body->ppid(), std::vector(data, data + len)); + // NOTE: We are creating a copy of the data here, otherwise we cannot + // move the Message and pass its ownership to the SCTP stack. + RTC::SCTP::Message message(streamId, body->ppid(), std::vector(data, data + len)); - ReceiveMessage(std::move(message), subchannels, requiredSubchannel); - } - else - { - ReceiveMessage(data, len, body->ppid(), subchannels, requiredSubchannel); - } + ReceiveMessage(std::move(message), subchannels, requiredSubchannel); // Increase receive transmission. this->listener->OnDataProducerReceiveData(this, len); @@ -258,29 +251,6 @@ namespace RTC } } - // TODO: SCTP: Remove when we migrate to the new SCTP stack. - void DataProducer::ReceiveMessage( - const uint8_t* msg, - size_t len, - uint32_t ppid, - std::vector& subchannels, - std::optional requiredSubchannel) - { - MS_TRACE(); - - this->messagesReceived++; - this->bytesReceived += len; - - // If paused stop here. - if (this->paused) - { - return; - } - - this->listener->OnDataProducerMessageReceived( - this, msg, len, ppid, subchannels, requiredSubchannel); - } - void DataProducer::ReceiveMessage( RTC::SCTP::Message message, std::vector& subchannels, diff --git a/worker/src/RTC/DirectTransport.cpp b/worker/src/RTC/DirectTransport.cpp index 95dc8156ef..4ade237113 100644 --- a/worker/src/RTC/DirectTransport.cpp +++ b/worker/src/RTC/DirectTransport.cpp @@ -218,34 +218,6 @@ namespace RTC notification); } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - void DirectTransport::SendMessage( - RTC::DataConsumer* dataConsumer, const uint8_t* msg, size_t len, uint32_t ppid, onQueuedCallback* cb) - { - MS_TRACE(); - - // Notify the Node DirectTransport. - auto data = this->shared->GetChannelNotifier()->GetBufferBuilder().CreateVector(msg, len); - - auto notification = FBS::DataConsumer::CreateMessageNotification( - this->shared->GetChannelNotifier()->GetBufferBuilder(), ppid, data); - - this->shared->GetChannelNotifier()->Emit( - dataConsumer->id, - FBS::Notification::Event::DATACONSUMER_MESSAGE, - FBS::Notification::Body::DataConsumer_MessageNotification, - notification); - - if (cb) - { - (*cb)(true, false); - delete cb; - } - - // Increase send transmission. - RTC::Transport::DataSent(len); - } - void DirectTransport::SendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, onQueuedCallback* cb) { diff --git a/worker/src/RTC/PipeConsumer.cpp b/worker/src/RTC/PipeConsumer.cpp index 0d1aff834e..b1d9f92b1f 100644 --- a/worker/src/RTC/PipeConsumer.cpp +++ b/worker/src/RTC/PipeConsumer.cpp @@ -4,8 +4,8 @@ #include "RTC/PipeConsumer.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" -#include "Utils.hpp" #include "RTC/RTP/Codecs/Tools.hpp" +#include "Utils.hpp" #ifdef MS_RTC_LOGGER_RTP #include "RTC/RtcLogger.hpp" #endif diff --git a/worker/src/RTC/PipeTransport.cpp b/worker/src/RTC/PipeTransport.cpp index f2c6b05148..31d058ab08 100644 --- a/worker/src/RTC/PipeTransport.cpp +++ b/worker/src/RTC/PipeTransport.cpp @@ -4,9 +4,9 @@ #include "RTC/PipeTransport.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" +#include "RTC/SCTP/packet/Packet.hpp" #include "Settings.hpp" #include "Utils.hpp" -#include "RTC/SCTP/packet/Packet.hpp" #include // std::memcpy() namespace RTC @@ -578,15 +578,6 @@ namespace RTC RTC::Transport::DataSent(len); } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - void PipeTransport::SendMessage( - RTC::DataConsumer* dataConsumer, const uint8_t* msg, size_t len, uint32_t ppid, onQueuedCallback* cb) - { - MS_TRACE(); - - SendSctpMessage(dataConsumer, msg, len, ppid, cb); - } - void PipeTransport::SendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, onQueuedCallback* cb) { @@ -651,12 +642,7 @@ namespace RTC OnRtpDataReceived(tuple, data, len, bufferLen); } // Check if it's SCTP. - else if (Settings::configuration.useBuiltInSctpStack && RTC::SCTP::Packet::IsSctp(data, len)) - { - OnSctpDataReceived(tuple, data, len); - } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else if (!Settings::configuration.useBuiltInSctpStack && RTC::SctpAssociation::IsSctp(data, len)) + else if (RTC::SCTP::Packet::IsSctp(data, len)) { OnSctpDataReceived(tuple, data, len); } diff --git a/worker/src/RTC/PlainTransport.cpp b/worker/src/RTC/PlainTransport.cpp index 5ebcb163bd..d35927eb7b 100644 --- a/worker/src/RTC/PlainTransport.cpp +++ b/worker/src/RTC/PlainTransport.cpp @@ -4,9 +4,9 @@ #include "RTC/PlainTransport.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" +#include "RTC/SCTP/packet/Packet.hpp" #include "Settings.hpp" #include "Utils.hpp" -#include "RTC/SCTP/packet/Packet.hpp" #include // std::memcpy() namespace RTC @@ -898,15 +898,6 @@ namespace RTC RTC::Transport::DataSent(len); } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - void PlainTransport::SendMessage( - RTC::DataConsumer* dataConsumer, const uint8_t* msg, size_t len, uint32_t ppid, onQueuedCallback* cb) - { - MS_TRACE(); - - SendSctpMessage(dataConsumer, msg, len, ppid, cb); - } - void PlainTransport::SendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, onQueuedCallback* cb) { @@ -973,12 +964,7 @@ namespace RTC OnRtpDataReceived(tuple, data, len, bufferLen); } // Check if it's SCTP. - else if (Settings::configuration.useBuiltInSctpStack && RTC::SCTP::Packet::IsSctp(data, len)) - { - OnSctpDataReceived(tuple, data, len); - } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else if (!Settings::configuration.useBuiltInSctpStack && RTC::SctpAssociation::IsSctp(data, len)) + else if (RTC::SCTP::Packet::IsSctp(data, len)) { OnSctpDataReceived(tuple, data, len); } diff --git a/worker/src/RTC/Producer.cpp b/worker/src/RTC/Producer.cpp index 23f3699bb1..b5f0f79363 100644 --- a/worker/src/RTC/Producer.cpp +++ b/worker/src/RTC/Producer.cpp @@ -4,11 +4,11 @@ #include "RTC/Producer.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" -#include "Utils.hpp" #include "RTC/Consts.hpp" #include "RTC/RTCP/Feedback.hpp" #include "RTC/RTCP/XrReceiverReferenceTime.hpp" #include "RTC/RTP/Codecs/Tools.hpp" +#include "Utils.hpp" #ifdef MS_RTC_LOGGER_RTP #include "RTC/RtcLogger.hpp" #endif diff --git a/worker/src/RTC/RTCP/FeedbackPsAfb.cpp b/worker/src/RTC/RTCP/FeedbackPsAfb.cpp index a74cf51d3d..667d2a6b3c 100644 --- a/worker/src/RTC/RTCP/FeedbackPsAfb.cpp +++ b/worker/src/RTC/RTCP/FeedbackPsAfb.cpp @@ -3,8 +3,8 @@ #include "RTC/RTCP/FeedbackPsAfb.hpp" #include "Logger.hpp" -#include "Utils.hpp" #include "RTC/RTCP/FeedbackPsRemb.hpp" +#include "Utils.hpp" #include namespace RTC diff --git a/worker/src/RTC/RTCP/FeedbackRtpTransport.cpp b/worker/src/RTC/RTCP/FeedbackRtpTransport.cpp index 80a80d409f..d81d7b6468 100644 --- a/worker/src/RTC/RTCP/FeedbackRtpTransport.cpp +++ b/worker/src/RTC/RTCP/FeedbackRtpTransport.cpp @@ -3,8 +3,8 @@ #include "RTC/RTCP/FeedbackRtpTransport.hpp" #include "Logger.hpp" -#include "Utils.hpp" #include "RTC/SeqManager.hpp" +#include "Utils.hpp" #include // std::ostringstream namespace RTC diff --git a/worker/src/RTC/RTCP/XR.cpp b/worker/src/RTC/RTCP/XR.cpp index 18bd8a6ac2..c6ef497dcb 100644 --- a/worker/src/RTC/RTCP/XR.cpp +++ b/worker/src/RTC/RTCP/XR.cpp @@ -2,9 +2,9 @@ // #define MS_LOG_DEV_LEVEL 3 #include "Logger.hpp" -#include "Utils.hpp" #include "RTC/RTCP/XrDelaySinceLastRr.hpp" #include "RTC/RTCP/XrReceiverReferenceTime.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/src/RTC/RTP/ProbationGenerator.cpp b/worker/src/RTC/RTP/ProbationGenerator.cpp index db2b93267b..7aaeb4ee90 100644 --- a/worker/src/RTC/RTP/ProbationGenerator.cpp +++ b/worker/src/RTC/RTP/ProbationGenerator.cpp @@ -3,8 +3,8 @@ #include "RTC/RTP/ProbationGenerator.hpp" #include "Logger.hpp" -#include "Utils.hpp" #include "RTC/RtpDictionaries.hpp" +#include "Utils.hpp" #include // std::memcpy(), std::memset() #include diff --git a/worker/src/RTC/RTP/RetransmissionBuffer.cpp b/worker/src/RTC/RTP/RetransmissionBuffer.cpp index d3b3003cb5..116220902d 100644 --- a/worker/src/RTC/RTP/RetransmissionBuffer.cpp +++ b/worker/src/RTC/RTP/RetransmissionBuffer.cpp @@ -3,8 +3,8 @@ #include "RTC/RTP/RetransmissionBuffer.hpp" #include "Logger.hpp" -#include "Utils.hpp" #include "RTC/SeqManager.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/src/RTC/RTP/RtpStreamRecv.cpp b/worker/src/RTC/RTP/RtpStreamRecv.cpp index 65199b1137..b3ffe7b9f0 100644 --- a/worker/src/RTC/RTP/RtpStreamRecv.cpp +++ b/worker/src/RTC/RTP/RtpStreamRecv.cpp @@ -3,8 +3,8 @@ #include "RTC/RTP/RtpStreamRecv.hpp" #include "Logger.hpp" -#include "Utils.hpp" #include "RTC/RTP/Codecs/Tools.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/src/RTC/RTP/RtpStreamSend.cpp b/worker/src/RTC/RTP/RtpStreamSend.cpp index c76f988fce..67e4d181f2 100644 --- a/worker/src/RTC/RTP/RtpStreamSend.cpp +++ b/worker/src/RTC/RTP/RtpStreamSend.cpp @@ -6,9 +6,9 @@ #include "DepLibUring.hpp" #endif #include "Logger.hpp" -#include "Utils.hpp" #include "RTC/Consts.hpp" #include "RTC/RtpDictionaries.hpp" +#include "Utils.hpp" #include namespace RTC diff --git a/worker/src/RTC/Router.cpp b/worker/src/RTC/Router.cpp index e91d542506..ca9b3ce207 100644 --- a/worker/src/RTC/Router.cpp +++ b/worker/src/RTC/Router.cpp @@ -392,7 +392,7 @@ namespace RTC auto transportId = body->transportId()->str(); // This may throw. - RTC::Transport* transport = GetTransportById(transportId); + RTC::Transport* transport = AssertAndGetTransportById(transportId); // Tell the Transport to close all its Producers and Consumers so it will // notify us about their closures. @@ -417,7 +417,7 @@ namespace RTC auto rtpObserverId = body->rtpObserverId()->str(); // This may throw. - RTC::RtpObserver* rtpObserver = GetRtpObserverById(rtpObserverId); + const RTC::RtpObserver* rtpObserver = AssertAndGetRtpObserverById(rtpObserverId); // Remove it from the map. this->mapRtpObservers.erase(rtpObserver->id); @@ -463,7 +463,7 @@ namespace RTC } } - RTC::Transport* Router::GetTransportById(const std::string& transportId) const + RTC::Transport* Router::AssertAndGetTransportById(const std::string& transportId) const { MS_TRACE(); @@ -477,7 +477,7 @@ namespace RTC return it->second; } - RTC::RtpObserver* Router::GetRtpObserverById(const std::string& rtpObserverId) const + RTC::RtpObserver* Router::AssertAndGetRtpObserverById(const std::string& rtpObserverId) const { MS_TRACE(); @@ -921,47 +921,6 @@ namespace RTC } } - // TODO: SCTP: Remove when we migrate to the new SCTP stack. - void Router::OnTransportDataProducerMessageReceived( - RTC::Transport* /*transport*/, - RTC::DataProducer* dataProducer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - std::vector& subchannels, - std::optional requiredSubchannel) - { - MS_TRACE(); - - auto& dataConsumers = this->mapDataProducerDataConsumers.at(dataProducer); - - if (!dataConsumers.empty()) - { -#ifdef MS_LIBURING_SUPPORTED - if (DepLibUring::IsEnabled()) - { - // Activate liburing usage. - // The effective sending could be synchronous, thus we would send those - // messages within a single system call. - DepLibUring::SetActive(); - } -#endif - - for (auto* dataConsumer : dataConsumers) - { - dataConsumer->SendMessage(msg, len, ppid, subchannels, requiredSubchannel); - } - -#ifdef MS_LIBURING_SUPPORTED - if (DepLibUring::IsEnabled()) - { - // Submit all prepared submission entries. - DepLibUring::Submit(); - } -#endif - } - } - void Router::OnTransportDataProducerMessageReceived( RTC::Transport* /*transport*/, RTC::DataProducer* dataProducer, diff --git a/worker/src/RTC/RtpDictionaries/RtpCodecMimeType.cpp b/worker/src/RTC/RtpDictionaries/RtpCodecMimeType.cpp index 5977436cb4..927cd71142 100644 --- a/worker/src/RTC/RtpDictionaries/RtpCodecMimeType.cpp +++ b/worker/src/RTC/RtpDictionaries/RtpCodecMimeType.cpp @@ -3,8 +3,8 @@ #include "Logger.hpp" #include "MediaSoupErrors.hpp" -#include "Utils.hpp" #include "RTC/RtpDictionaries.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/src/RTC/SCTP/association/Association.cpp b/worker/src/RTC/SCTP/association/Association.cpp index 603d87b494..7901c7adc6 100644 --- a/worker/src/RTC/SCTP/association/Association.cpp +++ b/worker/src/RTC/SCTP/association/Association.cpp @@ -3,7 +3,6 @@ #include "RTC/SCTP/association/Association.hpp" #include "Logger.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/errorCauses/CookieReceivedWhileShuttingDownErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/NoUserDataErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/OutOfResourceErrorCause.hpp" @@ -14,6 +13,7 @@ #include "RTC/SCTP/packet/parameters/StateCookieParameter.hpp" #include "RTC/SCTP/packet/parameters/SupportedExtensionsParameter.hpp" #include "RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp" +#include "Utils.hpp" #include // std::numeric_limits() #include // std::ostringstream #include @@ -37,7 +37,10 @@ namespace RTC /* Instance methods. */ Association::Association( - const SctpOptions& sctpOptions, AssociationListenerInterface* listener, SharedInterface* shared) + const SctpOptions& sctpOptions, + AssociationListenerInterface* listener, + SharedInterface* shared, + bool isDataChannel) : sctpOptions(sctpOptions), // Our `listener` member is a `AssociationListenerDeferrer` which takes // `listener` argument as constructor argument. @@ -74,7 +77,8 @@ namespace RTC .backoffAlgorithm = BackoffTimerHandleInterface::BackoffAlgorithm::EXPONENTIAL, .maxBackoffTimeoutMs = sctpOptions.timerMaxBackoffTimeoutMs, .maxRestarts = sctpOptions.maxRetransmissions })), - maxPacketLength(Utils::Byte::PadDownTo4Bytes(this->sctpOptions.mtu)) + maxPacketLength(Utils::Byte::PadDownTo4Bytes(this->sctpOptions.mtu)), + isDataChannel(isDataChannel) { MS_TRACE(); } @@ -108,7 +112,7 @@ namespace RTC this->tcb->Dump(indentation + 1); } - const auto metrics = GetMetrics(); + const auto metrics = MakeMetrics(); if (metrics.has_value()) { @@ -125,26 +129,13 @@ namespace RTC return FBS::SctpParameters::CreateSctpParameters( builder, - // Add port. - this->sctpOptions.sourcePort, - // Add OS. - // TODO: SCTP: We should put here current value which may be different after - // negotiation with peer and reconfig. - this->sctpOptions.announcedMaxOutboundStreams, - // Add MIS. - // TODO: SCTP: We should put here current value which may be different after - // negotiation with peer and reconfig. - this->sctpOptions.announcedMaxInboundStreams, - // Add maxMessageSize. - this->sctpOptions.maxSendMessageSize, - // Add sendBufferSize. - this->sctpOptions.maxSendBufferSize, - // Add sctpBufferedAmountLowThreshold. - this->sctpOptions.totalBufferedAmountLowThreshold, - // Add isDataChannel. - // TODO: SCTP: Have a member for this. - // TODO: SCTP: So remove this hardcoded `true`. - /*isDataChannel*/ true); + /*port*/ this->sctpOptions.sourcePort, + /*maxSendMessageSize*/ this->sctpOptions.maxSendMessageSize, + /*maxReceiveMessageSize*/ this->sctpOptions.maxReceiveMessageSize, + /*sctpSendBufferSize*/ this->sctpOptions.maxSendBufferSize, + /*sctpPerStreamSendQueueLimit*/ this->sctpOptions.perStreamSendQueueLimit, + /*sctpMaxReceiverWindowBufferSize*/ this->sctpOptions.maxReceiverWindowBufferSize, + /*isDataChannel*/ this->isDataChannel); } Types::AssociationState Association::GetAssociationState() const @@ -334,10 +325,11 @@ namespace RTC } InternalClose(Types::ErrorKind::SUCCESS, ""); + AssertIsConsistent(); } - std::optional Association::GetMetrics() const + std::optional Association::MakeMetrics() const { if (!this->tcb) { @@ -394,6 +386,13 @@ namespace RTC this->sctpOptions.maxSendMessageSize = maxMessageSize; } + size_t Association::GetTotalBufferedAmount() const + { + MS_TRACE(); + + return this->sendQueue.GetTotalBufferedAmount(); + } + size_t Association::GetStreamBufferedAmount(uint16_t streamId) const { MS_TRACE(); @@ -408,7 +407,7 @@ namespace RTC return this->sendQueue.GetStreamBufferedAmountLowThreshold(streamId); } - void Association::SetBufferedAmountLowThreshold(uint16_t streamId, size_t bytes) + void Association::SetStreamBufferedAmountLowThreshold(uint16_t streamId, size_t bytes) { MS_TRACE(); @@ -442,6 +441,7 @@ namespace RTC this->tcb->GetStreamResetHandler().ResetStreams(outboundStreamIds); MaySendResetStreamsRequest(); + AssertIsConsistent(); return Types::ResetStreamsStatus::PERFORMED; @@ -522,12 +522,12 @@ namespace RTC // For debugging purposes. #if MS_LOG_DEV_LEVEL == 3 - MS_DUMP("<<< received SCTP packet:"); - const auto* packet = RTC::SCTP::Packet::Parse(data, len); if (packet) { + MS_DUMP("<<< received SCTP packet:"); + packet->Dump(); delete packet; @@ -591,6 +591,42 @@ namespace RTC AssertIsConsistent(); } + uint16_t Association::GetNegotiatedMaxOutboundStreams() const + { + MS_TRACE(); + + if (this->tcb) + { + return this->tcb->GetNegotiatedCapabilities().negotiatedMaxOutboundStreams; + } + else + { + MS_WARN_TAG( + sctp, + "calling Association::GetNegotiatedMaxOutboundStreams() before TCB is created returns 0"); + + return 0; + } + } + + uint16_t Association::GetNegotiatedMaxInboundStreams() const + { + MS_TRACE(); + + if (this->tcb) + { + return this->tcb->GetNegotiatedCapabilities().negotiatedMaxInboundStreams; + } + else + { + MS_WARN_TAG( + sctp, + "calling Association::GetNegotiatedMaxInboundStreams() before TCB is created returns 0"); + + return 0; + } + } + void Association::InternalClose(Types::ErrorKind errorKind, const std::string_view& message) { MS_TRACE(); @@ -922,6 +958,18 @@ namespace RTC while (std::optional message = this->tcb->GetReassemblyQueue().GetNextMessage()) { this->privateMetrics.rxMessagesCount++; + + if (message->GetPayloadLength() > this->sctpOptions.maxReceiveMessageSize) + { + MS_WARN_TAG( + sctp, + "dropping too large received message [messageByteLength:%zu, maxReceiveMessageSize:%zu]", + message->GetPayloadLength(), + this->sctpOptions.maxReceiveMessageSize); + + break; + } + this->associationListenerDeferrer.OnAssociationMessageReceived(*std::move(message)); } } @@ -1584,6 +1632,7 @@ namespace RTC this->tcb->SendBufferedPackets(nowMs); this->t1CookieTimer->Start(); + this->associationListenerDeferrer.OnAssociationConnecting(); } @@ -1797,6 +1846,7 @@ namespace RTC const uint64_t nowMs = this->shared->GetTimeMs(); this->tcb->SendBufferedPackets(nowMs); + this->associationListenerDeferrer.OnAssociationConnected(); } @@ -2446,6 +2496,7 @@ namespace RTC this->packetSender.SendPacket(packet.get()); InternalClose(Types::ErrorKind::TOO_MANY_RETRIES, "no SHUTDOWN_ACK chunk received"); + AssertIsConsistent(); return; @@ -2567,9 +2618,18 @@ namespace RTC { MS_TRACE(); - MS_ASSERT( - !(this->tcb && this->tcb->GetReassemblyQueue().HasMessages()), - "this->tcb && this->tcb->GetReassemblyQueue().HasMessages()"); + // NOTE: This assertion is present in dcsctp but we are removing it because + // it's dangerous. Depending on where `AssertIsConsistent()` is called from, + // it may legitimately happen that tere are SCTP full messages stored in + // the reassembly queue. `ReassemblyQueue::HasMessages()` can legitimately + // return `true` during stream deferred reset processing, which is a valid + // state where the reassembly queue intentionally retains messages while + // waiting for the TSN marked by the peer as the "Sender's Last Assigned + // TSN". There is no point in the code where we can guarantee that this + // state is not active. + // MS_ASSERT( + // !(this->tcb && this->tcb->GetReassemblyQueue().HasMessages()), + // "this->tcb && this->tcb->GetReassemblyQueue().HasMessages()"); switch (this->state) { @@ -2720,11 +2780,23 @@ namespace RTC } } +#if MS_LOG_DEV_LEVEL == 3 + void Association::OnPacketSenderPacketSent( + PacketSender* /*packetSender*/, const Packet* packet, bool sent) +#else void Association::OnPacketSenderPacketSent( PacketSender* /*packetSender*/, const Packet* /*packet*/, bool sent) +#endif { MS_TRACE(); +// For debugging purposes. +#if MS_LOG_DEV_LEVEL == 3 + MS_DUMP(">>> SCTP packet sent [sent:%s]", sent ? "yes" : "no"); + + packet->Dump(); +#endif + if (sent) { this->privateMetrics.txPacketsCount++; diff --git a/worker/src/RTC/SCTP/association/HeartbeatHandler.cpp b/worker/src/RTC/SCTP/association/HeartbeatHandler.cpp index d47513ef64..245580dae8 100644 --- a/worker/src/RTC/SCTP/association/HeartbeatHandler.cpp +++ b/worker/src/RTC/SCTP/association/HeartbeatHandler.cpp @@ -3,9 +3,9 @@ #include "RTC/SCTP/association/HeartbeatHandler.hpp" #include "Logger.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/parameters/HeartbeatInfoParameter.hpp" #include "RTC/SCTP/public/SctpTypes.hpp" +#include "Utils.hpp" #include namespace RTC diff --git a/worker/src/RTC/SCTP/association/PacketSender.cpp b/worker/src/RTC/SCTP/association/PacketSender.cpp index d1c82df339..68d7a5e358 100644 --- a/worker/src/RTC/SCTP/association/PacketSender.cpp +++ b/worker/src/RTC/SCTP/association/PacketSender.cpp @@ -33,13 +33,6 @@ namespace RTC packet->WriteCRC32cChecksum(); } -// For debugging purposes. -#if MS_LOG_DEV_LEVEL == 3 - MS_DUMP(">>> sending SCTP packet:"); - - packet->Dump(); -#endif - MS_ASSERT(!packet->NeedsConsolidation(), "cannot send a SCTP packet that needs consolidation"); const bool sent = diff --git a/worker/src/RTC/SCTP/association/StreamResetHandler.cpp b/worker/src/RTC/SCTP/association/StreamResetHandler.cpp index 30ffcfccae..4d8eb62398 100644 --- a/worker/src/RTC/SCTP/association/StreamResetHandler.cpp +++ b/worker/src/RTC/SCTP/association/StreamResetHandler.cpp @@ -204,7 +204,7 @@ namespace RTC // `reqSeqNbr` will be used. MS_ASSERT(this->currentRequest.has_value(), "currentRequest optional must have value"); - if (this->currentRequest->HasBeenSent()) + if (!this->currentRequest->HasBeenSent()) { this->currentRequest->PrepareToSend(this->nextOutgoingReqSeqNbr); this->nextOutgoingReqSeqNbr = uint32_t{ this->nextOutgoingReqSeqNbr + 1 }; diff --git a/worker/src/RTC/SCTP/packet/Chunk.cpp b/worker/src/RTC/SCTP/packet/Chunk.cpp index ff82b5e932..d4f90288fa 100644 --- a/worker/src/RTC/SCTP/packet/Chunk.cpp +++ b/worker/src/RTC/SCTP/packet/Chunk.cpp @@ -4,7 +4,6 @@ #include "RTC/SCTP/packet/Chunk.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/errorCauses/CookieReceivedWhileShuttingDownErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/InvalidMandatoryParameterErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/InvalidStreamIdentifierErrorCause.hpp" @@ -36,6 +35,7 @@ #include "RTC/SCTP/packet/parameters/UnknownParameter.hpp" #include "RTC/SCTP/packet/parameters/UnrecognizedParameterParameter.hpp" #include "RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/src/RTC/SCTP/packet/Packet.cpp b/worker/src/RTC/SCTP/packet/Packet.cpp index 2244691554..4c48dda05d 100644 --- a/worker/src/RTC/SCTP/packet/Packet.cpp +++ b/worker/src/RTC/SCTP/packet/Packet.cpp @@ -4,7 +4,6 @@ #include "RTC/SCTP/packet/Packet.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/chunks/AbortAssociationChunk.hpp" #include "RTC/SCTP/packet/chunks/CookieAckChunk.hpp" #include "RTC/SCTP/packet/chunks/CookieEchoChunk.hpp" @@ -23,6 +22,7 @@ #include "RTC/SCTP/packet/chunks/ShutdownChunk.hpp" #include "RTC/SCTP/packet/chunks/ShutdownCompleteChunk.hpp" #include "RTC/SCTP/packet/chunks/UnknownChunk.hpp" +#include "Utils.hpp" namespace RTC { diff --git a/worker/src/RTC/SCTP/public/SctpOptions.cpp b/worker/src/RTC/SCTP/public/SctpOptions.cpp index 199944efe7..1a7bacaf9f 100644 --- a/worker/src/RTC/SCTP/public/SctpOptions.cpp +++ b/worker/src/RTC/SCTP/public/SctpOptions.cpp @@ -27,6 +27,7 @@ namespace RTC MS_DUMP_CLEAN(indentation, " max send message size: %zu", this->maxSendMessageSize); MS_DUMP_CLEAN(indentation, " max send buffer size: %zu", this->maxSendBufferSize); MS_DUMP_CLEAN(indentation, " per stream send queue limit: %zu", this->perStreamSendQueueLimit); + MS_DUMP_CLEAN(indentation, " max receive message size: %zu", this->maxReceiveMessageSize); MS_DUMP_CLEAN(indentation, " max receiver window size: %zu", this->maxReceiverWindowBufferSize); MS_DUMP_CLEAN( indentation, diff --git a/worker/src/RTC/SCTP/rx/ReassemblyQueue.cpp b/worker/src/RTC/SCTP/rx/ReassemblyQueue.cpp index be019d631a..7a86536fd9 100644 --- a/worker/src/RTC/SCTP/rx/ReassemblyQueue.cpp +++ b/worker/src/RTC/SCTP/rx/ReassemblyQueue.cpp @@ -85,7 +85,7 @@ namespace RTC AddData(tsn, std::move(*sharedData)); }); - // TODO: Once we upgrade to C++23, replace the above with: + // TODO: SCTP: Once we upgrade to C++23, replace the above with: // this->deferredResetStreams->deferredActions.emplace_back( // [this, tsn, data = std::move(data)]() mutable // { diff --git a/worker/src/RTC/SCTP/tx/OutstandingData.cpp b/worker/src/RTC/SCTP/tx/OutstandingData.cpp index dcd1258653..20ccc21342 100644 --- a/worker/src/RTC/SCTP/tx/OutstandingData.cpp +++ b/worker/src/RTC/SCTP/tx/OutstandingData.cpp @@ -4,8 +4,8 @@ #include "RTC/SCTP/tx/OutstandingData.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/chunks/AnyForwardTsnChunk.hpp" +#include "Utils.hpp" #include namespace RTC diff --git a/worker/src/RTC/SCTP/tx/RetransmissionQueue.cpp b/worker/src/RTC/SCTP/tx/RetransmissionQueue.cpp index 9c4edbf368..b2019726b3 100644 --- a/worker/src/RTC/SCTP/tx/RetransmissionQueue.cpp +++ b/worker/src/RTC/SCTP/tx/RetransmissionQueue.cpp @@ -3,10 +3,10 @@ #include "RTC/SCTP/tx/RetransmissionQueue.hpp" #include "Logger.hpp" -#include "Utils.hpp" #include "RTC/SCTP/packet/chunks/DataChunk.hpp" #include "RTC/SCTP/packet/chunks/IDataChunk.hpp" #include "RTC/SCTP/public/SctpTypes.hpp" +#include "Utils.hpp" #include // std::min() #include // std::accumulate() #include diff --git a/worker/src/RTC/SCTP/tx/RoundRobinSendQueue.cpp b/worker/src/RTC/SCTP/tx/RoundRobinSendQueue.cpp index b15631abd2..71b28c8384 100644 --- a/worker/src/RTC/SCTP/tx/RoundRobinSendQueue.cpp +++ b/worker/src/RTC/SCTP/tx/RoundRobinSendQueue.cpp @@ -724,7 +724,7 @@ namespace RTC { MS_DEBUG_DEV( "triggering OnAssociationLifecycleMessageExpired(%" PRIu64 "), /*maybeDelivered*/ false)", - item.attributes.lifecycleId); + item.attributes.lifecycleId.value()); this->parent.associationListener.OnAssociationLifecycleMessageExpired( item.attributes.lifecycleId.value(), /*maybeDelivered*/ false); diff --git a/worker/src/RTC/SCTP/tx/StreamScheduler.cpp b/worker/src/RTC/SCTP/tx/StreamScheduler.cpp index 9449846bc8..6fc4652fd9 100644 --- a/worker/src/RTC/SCTP/tx/StreamScheduler.cpp +++ b/worker/src/RTC/SCTP/tx/StreamScheduler.cpp @@ -36,14 +36,15 @@ namespace RTC this->currentStream = *it; - MS_DEBUG_DEV("rescheduling to stream %" PRIu16, this->currentStream->GetStreamId()); + MS_DEBUG_DEV("rescheduling to streamId %" PRIu16, this->currentStream->GetStreamId()); this->activeStreams.erase(it); this->currentStream->ForceMarkInactive(); } else { - MS_DEBUG_DEV("producing from previous stream %" PRIu16, this->currentStream->GetStreamId()); + MS_DEBUG_DEV( + "producing from previous streamId %" PRIu16, this->currentStream->GetStreamId()); MS_ASSERT( std::ranges::any_of( @@ -169,7 +170,8 @@ namespace RTC MS_ASSERT(nextFinishTime > 0, "nextFinishTime must be higher than 0"); - MS_DEBUG_DEV("making stream %" PRIu16 " active, expiring at %f", GetStreamId(), nextFinishTime); + MS_DEBUG_DEV( + "making streamId %" PRIu16 " active, expiring at %f", GetStreamId(), nextFinishTime); MS_ASSERT(this->nextFinishTime == 0, "this->nextFinishTime must be 0"); @@ -191,7 +193,7 @@ namespace RTC { MS_TRACE(); - MS_DEBUG_DEV("making stream %" PRIu16 " inactive", GetStreamId()); + MS_DEBUG_DEV("making streamId %" PRIu16 " inactive", GetStreamId()); MS_ASSERT(this->nextFinishTime != 0, "this->nextFinishTime must be different than 0"); diff --git a/worker/src/RTC/SctpAssociation.cpp b/worker/src/RTC/SctpAssociation.cpp deleted file mode 100644 index a9ace561ac..0000000000 --- a/worker/src/RTC/SctpAssociation.cpp +++ /dev/null @@ -1,1175 +0,0 @@ -#define MS_CLASS "RTC::SctpAssociation" -// #define MS_LOG_DEV_LEVEL 3 - -#include "RTC/SctpAssociation.hpp" -#include "DepUsrSCTP.hpp" -#include "Logger.hpp" -#include "MediaSoupErrors.hpp" -#include // std::snprintf() -#include // std::malloc(), std::free() -#include // std::memset(), std::memcpy() -#include - -// Free send buffer threshold (in bytes) upon which send_cb will be executed. -static const uint32_t SendBufferThreshold{ 256u }; - -/* SCTP events to which we are subscribing. */ - -// clang-format off -const uint16_t EventTypes[] = -{ - SCTP_ADAPTATION_INDICATION, - SCTP_ASSOC_CHANGE, - SCTP_ASSOC_RESET_EVENT, - SCTP_REMOTE_ERROR, - SCTP_SHUTDOWN_EVENT, - SCTP_SEND_FAILED_EVENT, - SCTP_STREAM_RESET_EVENT, - SCTP_STREAM_CHANGE_EVENT -}; -// clang-format on - -/* Static methods for usrsctp callbacks. */ - -inline static int onRecvSctpData( - struct socket* /*sock*/, - union sctp_sockstore /*addr*/, - void* data, - size_t len, - struct sctp_rcvinfo rcv, - int flags, - void* ulpInfo) -{ - auto* sctpAssociation = DepUsrSCTP::RetrieveSctpAssociation(reinterpret_cast(ulpInfo)); - - if (!sctpAssociation) - { - MS_WARN_TAG(sctp, "no SctpAssociation found"); - - std::free(data); - - return 0; - } - - if (flags & MSG_NOTIFICATION) - { - sctpAssociation->OnUsrSctpReceiveSctpNotification( - static_cast(data), len); - } - else - { - const uint16_t streamId = rcv.rcv_sid; - const uint32_t ppid = ntohl(rcv.rcv_ppid); - const uint16_t ssn = rcv.rcv_ssn; - - MS_DEBUG_TAG( - sctp, - "data chunk received [length:%zu, streamId:%" PRIu16 ", SSN:%" PRIu16 ", TSN:%" PRIu32 - ", PPID:%" PRIu32 ", context:%" PRIu32 ", flags:%d]", - len, - rcv.rcv_sid, - rcv.rcv_ssn, - rcv.rcv_tsn, - ntohl(rcv.rcv_ppid), - rcv.rcv_context, - flags); - - sctpAssociation->OnUsrSctpReceiveSctpData( - streamId, ssn, ppid, flags, static_cast(data), len); - } - - std::free(data); - - return 1; -} - -inline static int onSendSctpData(struct socket* /*sock*/, uint32_t freeBuffer, void* ulpInfo) -{ - auto* sctpAssociation = DepUsrSCTP::RetrieveSctpAssociation(reinterpret_cast(ulpInfo)); - - if (!sctpAssociation) - { - MS_WARN_TAG(sctp, "no SctpAssociation found"); - - return 0; - } - - sctpAssociation->OnUsrSctpSentData(freeBuffer); - - return 1; -} - -namespace RTC -{ - /* Static. */ - - static constexpr size_t SctpMtu{ 1200 }; - static constexpr uint16_t MaxSctpStreams{ 65535 }; - - /* Instance methods. */ - - SctpAssociation::SctpAssociation( - Listener* listener, - uint16_t os, - uint16_t mis, - size_t maxSctpMessageSize, - size_t sctpSendBufferSize, - bool isDataChannel) - : id(DepUsrSCTP::GetNextSctpAssociationId()), - listener(listener), - os(os), - mis(mis), - maxSctpMessageSize(maxSctpMessageSize), - sctpSendBufferSize(std::max(sctpSendBufferSize, maxSctpMessageSize)), - isDataChannel(isDataChannel) - { - MS_TRACE(); - - // Register ourselves in usrsctp. - // NOTE: This must be done before calling usrsctp_bind(). - usrsctp_register_address(reinterpret_cast(this->id)); - - int ret; - - // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) - this->socket = usrsctp_socket( - AF_CONN, - SOCK_STREAM, - IPPROTO_SCTP, - onRecvSctpData, - onSendSctpData, - SendBufferThreshold, - reinterpret_cast(this->id)); - - if (!this->socket) - { - usrsctp_deregister_address(reinterpret_cast(this->id)); - - MS_THROW_ERROR("usrsctp_socket() failed: %s", std::strerror(errno)); - } - - usrsctp_set_ulpinfo(this->socket, reinterpret_cast(this->id)); - - // Make the socket non-blocking. - ret = usrsctp_set_non_blocking(this->socket, 1); - - if (ret < 0) - { - usrsctp_deregister_address(reinterpret_cast(this->id)); - - MS_THROW_ERROR("usrsctp_set_non_blocking() failed: %s", std::strerror(errno)); - } - - // Set SO_LINGER. - // This ensures that the usrsctp close call deletes the association. This - // prevents usrsctp from calling the global send callback with references to - // this class as the address. - struct linger lingerOpt{}; // NOLINT(cppcoreguidelines-pro-type-member-init) - - lingerOpt.l_onoff = 1; - lingerOpt.l_linger = 0; - - ret = usrsctp_setsockopt(this->socket, SOL_SOCKET, SO_LINGER, &lingerOpt, sizeof(lingerOpt)); - - if (ret < 0) - { - usrsctp_deregister_address(reinterpret_cast(this->id)); - - MS_THROW_ERROR("usrsctp_setsockopt(SO_LINGER) failed: %s", std::strerror(errno)); - } - - // Set SCTP_ENABLE_STREAM_RESET. - struct sctp_assoc_value av{}; // NOLINT(cppcoreguidelines-pro-type-member-init) - - av.assoc_value = - SCTP_ENABLE_RESET_STREAM_REQ | SCTP_ENABLE_RESET_ASSOC_REQ | SCTP_ENABLE_CHANGE_ASSOC_REQ; - - ret = usrsctp_setsockopt(this->socket, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, &av, sizeof(av)); - - if (ret < 0) - { - usrsctp_deregister_address(reinterpret_cast(this->id)); - - MS_THROW_ERROR("usrsctp_setsockopt(SCTP_ENABLE_STREAM_RESET) failed: %s", std::strerror(errno)); - } - - // Set SCTP_NODELAY. - const uint32_t noDelay = 1; - - ret = usrsctp_setsockopt(this->socket, IPPROTO_SCTP, SCTP_NODELAY, &noDelay, sizeof(noDelay)); - - if (ret < 0) - { - usrsctp_deregister_address(reinterpret_cast(this->id)); - - MS_THROW_ERROR("usrsctp_setsockopt(SCTP_NODELAY) failed: %s", std::strerror(errno)); - } - - // Enable events. - struct sctp_event event{}; // NOLINT(cppcoreguidelines-pro-type-member-init) - - std::memset(&event, 0, sizeof(event)); - event.se_on = 1; - - for (size_t i{ 0 }; i < sizeof(EventTypes) / sizeof(uint16_t); ++i) - { - event.se_type = EventTypes[i]; - - ret = usrsctp_setsockopt(this->socket, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(event)); - - if (ret < 0) - { - usrsctp_deregister_address(reinterpret_cast(this->id)); - - MS_THROW_ERROR("usrsctp_setsockopt(SCTP_EVENT) failed: %s", std::strerror(errno)); - } - } - - // Init message. - struct sctp_initmsg initmsg{}; // NOLINT(cppcoreguidelines-pro-type-member-init) - - std::memset(&initmsg, 0, sizeof(initmsg)); - initmsg.sinit_num_ostreams = this->os; - initmsg.sinit_max_instreams = this->mis; - - ret = usrsctp_setsockopt(this->socket, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg)); - - if (ret < 0) - { - usrsctp_deregister_address(reinterpret_cast(this->id)); - - MS_THROW_ERROR("usrsctp_setsockopt(SCTP_INITMSG) failed: %s", std::strerror(errno)); - } - - // Server side. - struct sockaddr_conn sconn{}; // NOLINT(cppcoreguidelines-pro-type-member-init) - - std::memset(&sconn, 0, sizeof(sconn)); - sconn.sconn_family = AF_CONN; - sconn.sconn_port = htons(5000); - sconn.sconn_addr = reinterpret_cast(this->id); -#ifdef HAVE_SCONN_LEN - sconn.sconn_len = sizeof(sconn); -#endif - - ret = usrsctp_bind(this->socket, reinterpret_cast(&sconn), sizeof(sconn)); - - if (ret < 0) - { - usrsctp_deregister_address(reinterpret_cast(this->id)); - - MS_THROW_ERROR("usrsctp_bind() failed: %s", std::strerror(errno)); - } - - auto bufferSize = static_cast(sctpSendBufferSize); - - if (usrsctp_setsockopt(this->socket, SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(int)) < 0) - { - usrsctp_deregister_address(reinterpret_cast(this->id)); - - MS_THROW_ERROR("usrsctp_setsockopt(SO_SNDBUF) failed: %s", std::strerror(errno)); - } - - // Register the SctpAssociation into the global map. - DepUsrSCTP::RegisterSctpAssociation(this); - } - - SctpAssociation::~SctpAssociation() - { - MS_TRACE(); - - usrsctp_set_ulpinfo(this->socket, nullptr); - usrsctp_close(this->socket); - - // Deregister ourselves from usrsctp. - usrsctp_deregister_address(reinterpret_cast(this->id)); - - // Register the SctpAssociation from the global map. - DepUsrSCTP::DeregisterSctpAssociation(this); - - delete[] this->messageBuffer; - } - - void SctpAssociation::TransportConnected() - { - MS_TRACE(); - - this->transportConnected = true; - - MayConnect(); - } - - void SctpAssociation::TransportDisconnected() - { - MS_TRACE(); - - this->transportConnected = false; - } - - flatbuffers::Offset SctpAssociation::FillBuffer( - flatbuffers::FlatBufferBuilder& builder) const - { - MS_TRACE(); - - return FBS::SctpParameters::CreateSctpParameters( - builder, - // Add port (always 5000). - 5000, - // Add OS. - this->os, - // Add MIS. - this->mis, - // Add maxMessageSize. - this->maxSctpMessageSize, - // Add sendBufferSize. - this->sctpSendBufferSize, - // Add sctpBufferedAmountLowThreshold. - this->sctpBufferedAmount, - // Add isDataChannel. - this->isDataChannel); - } - - void SctpAssociation::ProcessSctpData(const uint8_t* data, size_t len) - { - MS_TRACE(); - - this->sctpDataReceived = true; - - MayConnect(); - -#if MS_LOG_DEV_LEVEL == 3 - // NOTE: Only uncomment this during local debugging if needed. - // MS_DUMP_DATA(data, len); -#endif - - usrsctp_conninput(reinterpret_cast(this->id), data, len, 0); - } - - void SctpAssociation::SendSctpMessage( - RTC::DataConsumer* dataConsumer, const uint8_t* msg, size_t len, uint32_t ppid, onQueuedCallback* cb) - { - MS_TRACE(); - - // This must be controlled by the DataConsumer. - MS_ASSERT( - len <= this->maxSctpMessageSize, - "given message exceeds max allowed message size [message size:%zu, max message size:%zu]", - len, - this->maxSctpMessageSize); - - const auto& parameters = dataConsumer->GetSctpStreamParameters(); - - // Fill sctp_sendv_spa. - struct sctp_sendv_spa spa{}; // NOLINT(cppcoreguidelines-pro-type-member-init) - - std::memset(&spa, 0, sizeof(spa)); - spa.sendv_flags = SCTP_SEND_SNDINFO_VALID; - spa.sendv_sndinfo.snd_sid = parameters.streamId; - spa.sendv_sndinfo.snd_ppid = htonl(ppid); - spa.sendv_sndinfo.snd_flags = SCTP_EOR; - - // If ordered it must be reliable. - if (parameters.ordered) - { - spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_NONE; - spa.sendv_prinfo.pr_value = 0; - } - // Configure reliability: https://tools.ietf.org/html/rfc3758 - else - { - spa.sendv_flags |= SCTP_SEND_PRINFO_VALID; - spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED; - - if (parameters.maxPacketLifeTime != 0) - { - spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL; - spa.sendv_prinfo.pr_value = parameters.maxPacketLifeTime; - } - else if (parameters.maxRetransmits != 0) - { - spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX; - spa.sendv_prinfo.pr_value = parameters.maxRetransmits; - } - } - - this->sctpBufferedAmount += len; - - // Notify the listener about the buffered amount increase regardless - // usrsctp_sendv result. - // In case of failure the correct value will be later provided by usrsctp - // via onSendSctpData. - this->listener->OnSctpAssociationBufferedAmount(this, this->sctpBufferedAmount); - - const ssize_t ret = usrsctp_sendv( - this->socket, msg, len, nullptr, 0, &spa, static_cast(sizeof(spa)), SCTP_SENDV_SPA, 0); - - if (ret < 0) - { - const bool sctpSendBufferFull = errno == EWOULDBLOCK || errno == EAGAIN; - - // SCTP send buffer being full is legit, not an error. - if (sctpSendBufferFull) - { - MS_WARN_DEV( - "error sending SCTP message [sid:%" PRIu16 ", ppid:%" PRIu32 ", message size:%zu]: %s", - parameters.streamId, - ppid, - len, - std::strerror(errno)); - } - else - { - MS_WARN_TAG( - sctp, - "error sending SCTP message [sid:%" PRIu16 ", ppid:%" PRIu32 ", message size:%zu]: %s", - parameters.streamId, - ppid, - len, - std::strerror(errno)); - } - - if (cb) - { - (*cb)(false, sctpSendBufferFull); - delete cb; - } - - if (sctpSendBufferFull) - { - dataConsumer->SctpAssociationSendBufferFull(); - } - } - else if (cb) - { - (*cb)(true, false); - delete cb; - } - } - - void SctpAssociation::HandleDataProducer(RTC::DataProducer* /*dataProducer*/) - { - MS_TRACE(); - - this->firstStreamCreated = true; - - MayConnect(); - } - - void SctpAssociation::HandleDataConsumer(RTC::DataConsumer* dataConsumer) - { - MS_TRACE(); - - this->firstStreamCreated = true; - - MayConnect(); - - auto streamId = dataConsumer->GetSctpStreamParameters().streamId; - - // We need more OS. - if (streamId > this->os - 1) - { - AddOutgoingStreams(/*force*/ false); - } - } - - void SctpAssociation::DataProducerClosed(RTC::DataProducer* dataProducer) - { - MS_TRACE(); - - auto streamId = dataProducer->GetSctpStreamParameters().streamId; - - // Send SCTP_RESET_STREAMS to the remote. - // https://tools.ietf.org/html/rfc8831#section-6.7 - if (this->isDataChannel) - { - ResetSctpStream(streamId, StreamDirection::OUTGOING); - } - else - { - ResetSctpStream(streamId, StreamDirection::INCOMING); - } - } - - void SctpAssociation::DataConsumerClosed(RTC::DataConsumer* dataConsumer) - { - MS_TRACE(); - - auto streamId = dataConsumer->GetSctpStreamParameters().streamId; - - // Send SCTP_RESET_STREAMS to the remote. - ResetSctpStream(streamId, StreamDirection::OUTGOING); - } - - void SctpAssociation::MayConnect() - { - MS_TRACE(); - - // Just run the SCTP stack if our state is 'new'. - // Notice that once MayConnect() is called (and the code below is executed), - // SCTP state will no longer be "NEW". - if (this->state != SctpState::NEW) - { - MS_DEBUG_DEV("SCTP state is not NEW, ignoring"); - - return; - } - // If the transport is not connected, don't do anything. - else if (!this->transportConnected) - { - MS_DEBUG_DEV("transport is not connected, ignoring"); - - return; - } - // If there are no SCTP streams yet and no SCTP data has been yet received - // from the remote peer, don't do anything. - // This is because the peer may never create a DataChannel so we shouldn't - // try to connect SCTP (SCTP INIT chunk, etc) since it will timeout and - // trigger "SCTP failed". - else if (!this->firstStreamCreated && !this->sctpDataReceived) - { - MS_DEBUG_DEV( - "no SCTP stream has been created yet and no SCTP data has been received yet, ignoring"); - - return; - } - - MS_DEBUG_TAG(sctp, "connecting SCTP"); - - try - { - int ret; - struct sockaddr_conn rconn{}; // NOLINT(cppcoreguidelines-pro-type-member-init) - - std::memset(&rconn, 0, sizeof(rconn)); - rconn.sconn_family = AF_CONN; - rconn.sconn_port = htons(5000); - rconn.sconn_addr = reinterpret_cast(this->id); -#ifdef HAVE_SCONN_LEN - rconn.sconn_len = sizeof(rconn); -#endif - - ret = usrsctp_connect(this->socket, reinterpret_cast(&rconn), sizeof(rconn)); - - if (ret < 0 && errno != EINPROGRESS) - { - MS_THROW_ERROR("usrsctp_connect() failed: %s", std::strerror(errno)); - } - - // Disable MTU discovery. - sctp_paddrparams peerAddrParams{}; // NOLINT(cppcoreguidelines-pro-type-member-init) - - std::memset(&peerAddrParams, 0, sizeof(peerAddrParams)); - std::memcpy(&peerAddrParams.spp_address, &rconn, sizeof(rconn)); - peerAddrParams.spp_flags = SPP_PMTUD_DISABLE; - - // The MTU value provided specifies the space available for chunks in the - // packet, so let's subtract the SCTP header size. - peerAddrParams.spp_pathmtu = SctpMtu - sizeof(struct sctp_common_header); - - ret = usrsctp_setsockopt( - this->socket, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &peerAddrParams, sizeof(peerAddrParams)); - - if (ret < 0) - { - MS_THROW_ERROR("usrsctp_setsockopt(SCTP_PEER_ADDR_PARAMS) failed: %s", std::strerror(errno)); - } - - // Announce connecting state. - MS_DEBUG_DEV("SCTP state switched to CONNECTING (in MayConnect())"); - - this->state = SctpState::CONNECTING; - this->listener->OnSctpAssociationConnecting(this); - } - catch (const MediaSoupError& /*error*/) - { - MS_DEBUG_DEV("SCTP state switched to FAILED (in MayConnect())"); - - this->state = SctpState::FAILED; - this->listener->OnSctpAssociationFailed(this); - } - } - - void SctpAssociation::ResetSctpStream(uint16_t streamId, StreamDirection direction) const - { - MS_TRACE(); - - // Do nothing if an outgoing stream that could not be allocated by us. - if (direction == StreamDirection::OUTGOING && streamId > this->os - 1) - { - return; - } - - int ret; - struct sctp_assoc_value av{}; // NOLINT(cppcoreguidelines-pro-type-member-init) - socklen_t len = sizeof(av); - - ret = usrsctp_getsockopt(this->socket, IPPROTO_SCTP, SCTP_RECONFIG_SUPPORTED, &av, &len); - - if (ret == 0) - { - if (av.assoc_value != 1) - { - MS_DEBUG_TAG(sctp, "stream reconfiguration not negotiated"); - - return; - } - } - else - { - MS_WARN_TAG( - sctp, - "could not retrieve whether stream reconfiguration has been negotiated: %s\n", - std::strerror(errno)); - - return; - } - - // As per spec: https://tools.ietf.org/html/rfc6525#section-4.1 - len = sizeof(sctp_assoc_t) + ((2 + 1) * sizeof(uint16_t)); - - auto* srs = static_cast(std::malloc(len)); - - switch (direction) - { - case StreamDirection::INCOMING: - srs->srs_flags = SCTP_STREAM_RESET_INCOMING; - break; - - case StreamDirection::OUTGOING: - srs->srs_flags = SCTP_STREAM_RESET_OUTGOING; - break; - } - - srs->srs_number_streams = 1; - srs->srs_stream_list[0] = streamId; // No need for htonl(). - - ret = usrsctp_setsockopt(this->socket, IPPROTO_SCTP, SCTP_RESET_STREAMS, srs, len); - - if (ret == 0) - { - MS_DEBUG_TAG(sctp, "SCTP_RESET_STREAMS sent [streamId:%" PRIu16 "]", streamId); - } - else - { - MS_WARN_TAG(sctp, "usrsctp_setsockopt(SCTP_RESET_STREAMS) failed: %s", std::strerror(errno)); - } - - std::free(srs); - } - - void SctpAssociation::AddOutgoingStreams(bool force) - { - MS_TRACE(); - - uint16_t additionalOs{ 0 }; - - if (MaxSctpStreams - this->os >= 32) - { - additionalOs = 32; - } - else - { - additionalOs = MaxSctpStreams - this->os; - } - - if (additionalOs == 0) - { - MS_WARN_TAG(sctp, "cannot add more outgoing streams [OS:%" PRIu16 "]", this->os); - - return; - } - - auto nextDesiredOs = this->os + additionalOs; - - // Already in progress, ignore (unless forced). - if (!force && nextDesiredOs == this->desiredOs) - { - return; - } - - // Update desired value. - this->desiredOs = nextDesiredOs; - - // If not connected, defer it. - if (this->state != SctpState::CONNECTED) - { - MS_DEBUG_TAG(sctp, "SCTP not connected, deferring OS increase"); - - return; - } - - struct sctp_add_streams sas{}; // NOLINT(cppcoreguidelines-pro-type-member-init) - - std::memset(&sas, 0, sizeof(sas)); - sas.sas_instrms = 0; - sas.sas_outstrms = additionalOs; - - MS_DEBUG_TAG(sctp, "adding %" PRIu16 " outgoing streams", additionalOs); - - const int ret = usrsctp_setsockopt( - this->socket, IPPROTO_SCTP, SCTP_ADD_STREAMS, &sas, static_cast(sizeof(sas))); - - if (ret < 0) - { - MS_WARN_TAG(sctp, "usrsctp_setsockopt(SCTP_ADD_STREAMS) failed: %s", std::strerror(errno)); - } - } - - void SctpAssociation::OnUsrSctpSendSctpData(void* buffer, size_t len) - { - MS_TRACE(); - - const uint8_t* data = static_cast(buffer); - -#if MS_LOG_DEV_LEVEL == 3 - // NOTE: Only uncomment this during local debugging if needed. - // MS_DUMP_DATA(data, len); -#endif - - this->listener->OnSctpAssociationSendData(this, data, len); - } - - void SctpAssociation::OnUsrSctpReceiveSctpData( - uint16_t streamId, uint16_t ssn, uint32_t ppid, int flags, const uint8_t* data, size_t len) - { - // Ignore WebRTC DataChannel Control DATA chunks. - if (ppid == 50) - { - MS_WARN_TAG(sctp, "ignoring SCTP data with ppid:50 (WebRTC DataChannel Control)"); - - return; - } - - if (this->messageBufferLen != 0 && ssn != this->lastSsnReceived) - { - MS_WARN_TAG( - sctp, - "message chunk received with different SSN while buffer not empty, buffer discarded [ssn:%" PRIu16 - ", last ssn received:%" PRIu16 "]", - ssn, - this->lastSsnReceived); - - this->messageBufferLen = 0; - } - - // Update last SSN received. - this->lastSsnReceived = ssn; - - auto eor = static_cast(flags & MSG_EOR); - - if (this->messageBufferLen + len > this->maxSctpMessageSize) - { - MS_WARN_TAG( - sctp, - "ongoing received message exceeds max allowed message size [message size:%zu, max message size:%zu, eor:%u]", - this->messageBufferLen + len, - this->maxSctpMessageSize, - eor ? 1 : 0); - - this->lastSsnReceived = 0; - - return; - } - - // If end of message and there is no buffered data, notify it directly. - if (eor && this->messageBufferLen == 0) - { - MS_DEBUG_DEV("directly notifying listener [eor:1, buffer len:0]"); - - this->listener->OnSctpAssociationMessageReceived(this, streamId, data, len, ppid); - } - // If end of message and there is buffered data, append data and notify buffer. - else if (eor && this->messageBufferLen != 0) - { - std::memcpy(this->messageBuffer + this->messageBufferLen, data, len); - this->messageBufferLen += len; - - MS_DEBUG_DEV("notifying listener [eor:1, buffer len:%zu]", this->messageBufferLen); - - this->listener->OnSctpAssociationMessageReceived( - this, streamId, this->messageBuffer, this->messageBufferLen, ppid); - - this->messageBufferLen = 0; - } - // If non end of message, append data to the buffer. - else if (!eor) - { - // Allocate the buffer if not already done. - if (!this->messageBuffer) - { - this->messageBuffer = new uint8_t[this->maxSctpMessageSize]; - } - - std::memcpy(this->messageBuffer + this->messageBufferLen, data, len); - this->messageBufferLen += len; - - MS_DEBUG_DEV("data buffered [eor:0, buffer len:%zu]", this->messageBufferLen); - } - } - - void SctpAssociation::OnUsrSctpReceiveSctpNotification(union sctp_notification* notification, size_t len) - { - if (notification->sn_header.sn_length != (uint32_t)len) - { - return; - } - - switch (notification->sn_header.sn_type) - { - case SCTP_ADAPTATION_INDICATION: - { - MS_DEBUG_TAG( - sctp, - "SCTP adaptation indication [%x]", - notification->sn_adaptation_event.sai_adaptation_ind); - - break; - } - - case SCTP_ASSOC_CHANGE: - { - switch (notification->sn_assoc_change.sac_state) - { - case SCTP_COMM_UP: - { - MS_DEBUG_TAG( - sctp, - "SCTP association connected, streams [out:%" PRIu16 ", in:%" PRIu16 "]", - notification->sn_assoc_change.sac_outbound_streams, - notification->sn_assoc_change.sac_inbound_streams); - - // Update our OS. - this->os = notification->sn_assoc_change.sac_outbound_streams; - - // Increase if requested before connected. - if (this->desiredOs > this->os) - { - AddOutgoingStreams(/*force*/ true); - } - - if (this->state != SctpState::CONNECTED) - { - MS_DEBUG_DEV("SCTP state switched to CONNECTED (in SCTP_ASSOC_CHANGE)"); - - this->state = SctpState::CONNECTED; - this->listener->OnSctpAssociationConnected(this); - } - - break; - } - - case SCTP_COMM_LOST: - { - if (notification->sn_header.sn_length > 0) - { - static const size_t BufferSize{ 1024 }; - static thread_local char buffer[BufferSize]; - - const uint32_t len = - notification->sn_assoc_change.sac_length - sizeof(struct sctp_assoc_change); - - for (uint32_t i{ 0 }; i < len; ++i) - { - std::snprintf( - buffer, BufferSize, " 0x%02x", notification->sn_assoc_change.sac_info[i]); - } - - MS_DEBUG_TAG(sctp, "SCTP communication lost [info:%s]", buffer); - } - else - { - MS_DEBUG_TAG(sctp, "SCTP communication lost"); - } - - if (this->state != SctpState::CLOSED) - { - MS_DEBUG_DEV("SCTP state switched to CLOSED (in SCTP_COMM_LOST)"); - - this->state = SctpState::CLOSED; - this->listener->OnSctpAssociationClosed(this); - } - - break; - } - - case SCTP_RESTART: - { - MS_DEBUG_TAG( - sctp, - "SCTP remote association restarted, streams [out:%" PRIu16 ", int:%" PRIu16 "]", - notification->sn_assoc_change.sac_outbound_streams, - notification->sn_assoc_change.sac_inbound_streams); - - // Update our OS. - this->os = notification->sn_assoc_change.sac_outbound_streams; - - // Increase if requested before connected. - if (this->desiredOs > this->os) - { - AddOutgoingStreams(/*force*/ true); - } - - if (this->state != SctpState::CONNECTED) - { - MS_DEBUG_DEV("SCTP state switched to CONNECTED (in SCTP_RESTART)"); - - this->state = SctpState::CONNECTED; - this->listener->OnSctpAssociationConnected(this); - } - - break; - } - - case SCTP_SHUTDOWN_COMP: - { - MS_DEBUG_TAG(sctp, "SCTP association gracefully closed"); - - if (this->state != SctpState::CLOSED) - { - MS_DEBUG_DEV("SCTP state switched to CLOSED (in SCTP_SHUTDOWN_COMP)"); - - this->state = SctpState::CLOSED; - this->listener->OnSctpAssociationClosed(this); - } - - break; - } - - case SCTP_CANT_STR_ASSOC: - { - if (notification->sn_header.sn_length > 0) - { - static const size_t BufferSize{ 1024 }; - static thread_local char buffer[BufferSize]; - - const uint32_t len = - notification->sn_assoc_change.sac_length - sizeof(struct sctp_assoc_change); - - for (uint32_t i{ 0 }; i < len; ++i) - { - std::snprintf( - buffer, BufferSize, " 0x%02x", notification->sn_assoc_change.sac_info[i]); - } - - MS_WARN_TAG(sctp, "SCTP setup failed: %s", buffer); - } - - if (this->state != SctpState::FAILED) - { - MS_DEBUG_DEV("SCTP state switched to FAILED (in SCTP_CANT_STR_ASSOC)"); - - this->state = SctpState::FAILED; - this->listener->OnSctpAssociationFailed(this); - } - - break; - } - - default:; - } - - break; - } - - // https://tools.ietf.org/html/rfc6525#section-6.1.2. - case SCTP_ASSOC_RESET_EVENT: - { - MS_DEBUG_TAG(sctp, "SCTP association reset event received"); - - break; - } - - // An Operation Error is not considered fatal in and of itself, but may be - // used with an ABORT chunk to report a fatal condition. - case SCTP_REMOTE_ERROR: - { - static const size_t BufferSize{ 1024 }; - static thread_local char buffer[BufferSize]; - - const uint32_t len = - notification->sn_remote_error.sre_length - sizeof(struct sctp_remote_error); - - for (uint32_t i{ 0 }; i < len; i++) - { - std::snprintf(buffer, BufferSize, "0x%02x", notification->sn_remote_error.sre_data[i]); - } - - MS_WARN_TAG( - sctp, - "remote SCTP association error [type:0x%04x, data:%s]", - notification->sn_remote_error.sre_error, - buffer); - - break; - } - - // When a peer sends a SHUTDOWN, SCTP delivers this notification to - // inform the application that it should cease sending data. - case SCTP_SHUTDOWN_EVENT: - { - MS_DEBUG_TAG(sctp, "remote SCTP association shutdown"); - - if (this->state != SctpState::CLOSED) - { - MS_DEBUG_DEV("SCTP state switched to CLOSED (in SCTP_SHUTDOWN_EVENT)"); - - this->state = SctpState::CLOSED; - this->listener->OnSctpAssociationClosed(this); - } - - break; - } - - case SCTP_SEND_FAILED_EVENT: - { - static const size_t BufferSize{ 1024 }; - static thread_local char buffer[BufferSize]; - - const uint32_t len = - notification->sn_send_failed_event.ssfe_length - sizeof(struct sctp_send_failed_event); - - for (uint32_t i{ 0 }; i < len; ++i) - { - std::snprintf(buffer, BufferSize, "0x%02x", notification->sn_send_failed_event.ssfe_data[i]); - } - - MS_WARN_TAG( - sctp, - "SCTP message sent failure [streamId:%" PRIu16 ", ppid:%" PRIu32 - ", sent:%s, error:0x%08x, info:%s]", - notification->sn_send_failed_event.ssfe_info.snd_sid, - ntohl(notification->sn_send_failed_event.ssfe_info.snd_ppid), - (notification->sn_send_failed_event.ssfe_flags & SCTP_DATA_SENT) ? "yes" : "no", - notification->sn_send_failed_event.ssfe_error, - buffer); - - break; - } - - case SCTP_STREAM_RESET_EVENT: - { - bool incoming{ false }; - bool outgoing{ false }; - const uint16_t numStreams = - (notification->sn_strreset_event.strreset_length - sizeof(struct sctp_stream_reset_event)) / - sizeof(uint16_t); - - if (notification->sn_strreset_event.strreset_flags & SCTP_STREAM_RESET_INCOMING_SSN) - { - incoming = true; - } - - if (notification->sn_strreset_event.strreset_flags & SCTP_STREAM_RESET_OUTGOING_SSN) - { - outgoing = true; - } - - if (MS_HAS_DEBUG_TAG(sctp)) - { - std::string streamIds; - - for (uint16_t i{ 0 }; i < numStreams; ++i) - { - auto streamId = notification->sn_strreset_event.strreset_stream_list[i]; - - // Don't log more than 5 stream ids. - if (i > 4) - { - streamIds.append("..."); - - break; - } - - if (i > 0) - { - streamIds.append(","); - } - - streamIds.append(std::to_string(streamId)); - } - - MS_DEBUG_TAG( - sctp, - "SCTP stream reset event [flags:%x, i|o:%s|%s, num streams:%" PRIu16 ", stream ids:%s]", - notification->sn_strreset_event.strreset_flags, - incoming ? "true" : "false", - outgoing ? "true" : "false", - numStreams, - streamIds.c_str()); - } - - // Special case for WebRTC DataChannels in which we must also reset our - // outgoing SCTP stream. - if (incoming && !outgoing && this->isDataChannel) - { - for (uint16_t i{ 0 }; i < numStreams; ++i) - { - auto streamId = notification->sn_strreset_event.strreset_stream_list[i]; - - ResetSctpStream(streamId, StreamDirection::OUTGOING); - } - } - - break; - } - - case SCTP_STREAM_CHANGE_EVENT: - { - if (notification->sn_strchange_event.strchange_flags == 0) - { - MS_DEBUG_TAG( - sctp, - "SCTP stream changed, streams [out:%" PRIu16 ", in:%" PRIu16 ", flags:%x]", - notification->sn_strchange_event.strchange_outstrms, - notification->sn_strchange_event.strchange_instrms, - notification->sn_strchange_event.strchange_flags); - } - else if (notification->sn_strchange_event.strchange_flags & SCTP_STREAM_RESET_DENIED) - { - MS_WARN_TAG( - sctp, - "SCTP stream change denied, streams [out:%" PRIu16 ", in:%" PRIu16 ", flags:%x]", - notification->sn_strchange_event.strchange_outstrms, - notification->sn_strchange_event.strchange_instrms, - notification->sn_strchange_event.strchange_flags); - - break; - } - else if (notification->sn_strchange_event.strchange_flags & SCTP_STREAM_RESET_FAILED) - { - MS_WARN_TAG( - sctp, - "SCTP stream change failed, streams [out:%" PRIu16 ", in:%" PRIu16 ", flags:%x]", - notification->sn_strchange_event.strchange_outstrms, - notification->sn_strchange_event.strchange_instrms, - notification->sn_strchange_event.strchange_flags); - - break; - } - - // Update OS. - this->os = notification->sn_strchange_event.strchange_outstrms; - - break; - } - - default: - { - MS_WARN_TAG( - sctp, "unhandled SCTP event received [type:%" PRIu16 "]", notification->sn_header.sn_type); - } - } - } - - void SctpAssociation::OnUsrSctpSentData(uint32_t freeBuffer) - { - auto previousSctpBufferedAmount = this->sctpBufferedAmount; - - this->sctpBufferedAmount = this->sctpSendBufferSize - freeBuffer; - - if (this->sctpBufferedAmount != previousSctpBufferedAmount) - { - this->listener->OnSctpAssociationBufferedAmount(this, this->sctpBufferedAmount); - } - } -} // namespace RTC diff --git a/worker/src/RTC/SimpleConsumer.cpp b/worker/src/RTC/SimpleConsumer.cpp index e789e93dcc..a442606f8f 100644 --- a/worker/src/RTC/SimpleConsumer.cpp +++ b/worker/src/RTC/SimpleConsumer.cpp @@ -4,9 +4,9 @@ #include "Logger.hpp" #include "MediaSoupErrors.hpp" -#include "Utils.hpp" #include "RTC/RTP/Codecs/Tools.hpp" #include "RTC/SimpleConsumer.hpp" +#include "Utils.hpp" #ifdef MS_RTC_LOGGER_RTP #include "RTC/RtcLogger.hpp" #endif diff --git a/worker/src/RTC/SimulcastConsumer.cpp b/worker/src/RTC/SimulcastConsumer.cpp index 000a1b1c8e..12f6a3cb85 100644 --- a/worker/src/RTC/SimulcastConsumer.cpp +++ b/worker/src/RTC/SimulcastConsumer.cpp @@ -4,8 +4,8 @@ #include "RTC/SimulcastConsumer.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" -#include "Utils.hpp" #include "RTC/RTP/Codecs/Tools.hpp" +#include "Utils.hpp" #ifdef MS_RTC_LOGGER_RTP #include "RTC/RtcLogger.hpp" #endif diff --git a/worker/src/RTC/SvcConsumer.cpp b/worker/src/RTC/SvcConsumer.cpp index c2d62f290d..9767ed84cf 100644 --- a/worker/src/RTC/SvcConsumer.cpp +++ b/worker/src/RTC/SvcConsumer.cpp @@ -4,8 +4,8 @@ #include "RTC/SvcConsumer.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" -#include "Utils.hpp" #include "RTC/RTP/Codecs/Tools.hpp" +#include "Utils.hpp" #ifdef MS_RTC_LOGGER_RTP #include "RTC/RtcLogger.hpp" #endif diff --git a/worker/src/RTC/Transport.cpp b/worker/src/RTC/Transport.cpp index 2cd1c21a0f..7f901b2f43 100644 --- a/worker/src/RTC/Transport.cpp +++ b/worker/src/RTC/Transport.cpp @@ -4,11 +4,11 @@ #include "RTC/Transport.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" -#include "Settings.hpp" #include "Utils.hpp" #ifdef MS_LIBURING_SUPPORTED #include "DepLibUring.hpp" #endif +#include "FBS/sctpAssociation.h" #include "FBS/transport.h" #include "RTC/BweType.hpp" #include "RTC/Consts.hpp" @@ -29,14 +29,12 @@ #include "RTC/RtcLogger.hpp" #endif #include // webrtc::RtpPacketSendInfo -#include // std::ostream_iterator -#include // std::multimap +#include +#include // std::ostream_iterator +#include // std::multimap namespace RTC { - static const size_t DefaultSctpSendBufferSize{ 262144 }; // 2^18 bytes. - static const size_t MaxSctpSendBufferSize{ 268435456 }; // 2^28 bytes. - /* Instance methods. */ Transport::Transport( @@ -55,14 +53,18 @@ namespace RTC { MS_TRACE(); + this->maxSendMessageSize = options->maxSendMessageSize(); + this->maxReceiveMessageSize = options->maxReceiveMessageSize(); + if (options->direct()) { this->direct = true; - - if (auto maxMessageSize = options->maxMessageSize(); maxMessageSize.has_value()) - { - this->maxMessageSize = maxMessageSize.value(); - } + } + else + { + this->sctpSendBufferSize = options->sctpSendBufferSize(); + this->sctpPerStreamSendQueueLimit = options->sctpPerStreamSendQueueLimit(); + this->sctpMaxReceiverWindowBufferSize = options->sctpMaxReceiverWindowBufferSize(); } if ( @@ -79,65 +81,17 @@ namespace RTC MS_THROW_TYPE_ERROR("cannot enable SCTP in a direct Transport"); } - // numSctpStreams is mandatory. - if (!flatbuffers::IsFieldPresent(options, FBS::Transport::Options::VT_NUMSCTPSTREAMS)) - { - MS_THROW_TYPE_ERROR("numSctpStreams missing"); - } - - // maxSctpMessageSize is mandatory. - if (!flatbuffers::IsFieldPresent(options, FBS::Transport::Options::VT_MAXSCTPMESSAGESIZE)) - { - MS_THROW_TYPE_ERROR("maxSctpMessageSize missing"); - } - - this->maxMessageSize = options->maxSctpMessageSize(); - - size_t sctpSendBufferSize; + const RTC::SCTP::SctpOptions sctpOptions = { + .mtu = RTC::Consts::MaxSafeMtuSizeForSctp, + .maxSendMessageSize = this->maxSendMessageSize, + .maxSendBufferSize = this->sctpSendBufferSize, + .perStreamSendQueueLimit = this->sctpPerStreamSendQueueLimit, + .maxReceiveMessageSize = this->maxReceiveMessageSize, + .maxReceiverWindowBufferSize = this->sctpMaxReceiverWindowBufferSize + }; - // sctpSendBufferSize is optional. - if (flatbuffers::IsFieldPresent(options, FBS::Transport::Options::VT_SCTPSENDBUFFERSIZE)) - { - if (options->sctpSendBufferSize() > MaxSctpSendBufferSize) - { - MS_THROW_TYPE_ERROR("wrong sctpSendBufferSize (maximum value exceeded)"); - } - - sctpSendBufferSize = options->sctpSendBufferSize(); - } - else - { - sctpSendBufferSize = DefaultSctpSendBufferSize; - } - - if (Settings::configuration.useBuiltInSctpStack) - { - // TODO: SCTP: Many interesting options missing. - // NOTE: When using the built-in SCTP stack, `numSctpStreams` given to the - // transport is ignored. - const RTC::SCTP::SctpOptions sctpOptions = { - // TODO: SCTP: Sure? - .maxSendMessageSize = this->maxMessageSize, - .maxSendBufferSize = sctpSendBufferSize, - // TODO: SCTP: We may need a separate option for this. - .perStreamSendQueueLimit = sctpSendBufferSize - }; - - this->sctpAssociation = - std::make_unique(sctpOptions, this, this->shared); - } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else - { - // This may throw. - this->oldSctpAssociation = new RTC::SctpAssociation( - this, - options->numSctpStreams()->os(), - options->numSctpStreams()->mis(), - this->maxMessageSize, - sctpSendBufferSize, - options->isDataChannel()); - } + this->sctpAssociation = std::make_unique( + sctpOptions, this, this->shared, options->isDataChannel()); } // Create the RTCP timer. @@ -187,25 +141,15 @@ namespace RTC delete dataConsumer; } this->mapDataConsumers.clear(); + this->mapSctpStreamIdDataConsumers.clear(); - if (Settings::configuration.useBuiltInSctpStack) - { - // NOTE: When using the built-in SCTP stack we don't do anything here since - // the `SetDestroying()` method has already been called by the Transport - // subclass and it closed the SCTP Association. - // - // NOTE: We cannot do it here in the destructor because here we are no longer - // the Transport subclass but Transport parent (this is how the destruction - // chain works in C++). - } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else - { - // Delete SCTP association. - // TODO: SCTP: Remove once we only use built-in SCTP stack. - delete this->oldSctpAssociation; - this->oldSctpAssociation = nullptr; - } + // NOTE: We don't close `this->sctpAssociation` here since the + // `SetDestroying()` method has already been called by the Transport + // subclass and it closed the SCTP Association. + // + // NOTE: We cannot do it here in the destructor because here we are no longer + // the Transport subclass but Transport parent (this is how the destruction + // chain works in C++). // Delete the RTCP timer. delete this->rtcpTimer; @@ -271,6 +215,7 @@ namespace RTC delete dataConsumer; } this->mapDataConsumers.clear(); + this->mapSctpStreamIdDataConsumers.clear(); } void Transport::ListenServerClosed() @@ -378,7 +323,7 @@ namespace RTC // Add sctpListener. flatbuffers::Offset sctpListener; - if (Settings::configuration.useBuiltInSctpStack && this->sctpAssociation) + if (this->sctpAssociation) { // Add sctpParameters. sctpParameters = this->sctpAssociation->FillBuffer(builder); @@ -414,47 +359,6 @@ namespace RTC sctpListener = this->sctpListener.FillBuffer(builder); } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else if (!Settings::configuration.useBuiltInSctpStack && this->oldSctpAssociation) - { - // Add sctpParameters. - sctpParameters = this->oldSctpAssociation->FillBuffer(builder); - - switch (this->oldSctpAssociation->GetState()) - { - case RTC::SctpAssociation::SctpState::NEW: - { - sctpState = FBS::SctpAssociation::SctpState::NEW; - break; - } - - case RTC::SctpAssociation::SctpState::CONNECTING: - { - sctpState = FBS::SctpAssociation::SctpState::CONNECTING; - break; - } - - case RTC::SctpAssociation::SctpState::CONNECTED: - { - sctpState = FBS::SctpAssociation::SctpState::CONNECTED; - break; - } - - case RTC::SctpAssociation::SctpState::FAILED: - { - sctpState = FBS::SctpAssociation::SctpState::FAILED; - break; - } - - case RTC::SctpAssociation::SctpState::CLOSED: - { - sctpState = FBS::SctpAssociation::SctpState::CLOSED; - break; - } - } - - sctpListener = this->sctpListener.FillBuffer(builder); - } // Add traceEventTypes. std::vector traceEventTypes; @@ -480,11 +384,11 @@ namespace RTC &dataConsumerIds, recvRtpHeaderExtensions, rtpListenerOffset, - this->maxMessageSize, + this->maxSendMessageSize, + this->maxReceiveMessageSize, sctpParameters, - (this->sctpAssociation || this->oldSctpAssociation) - ? flatbuffers::Optional(sctpState) - : flatbuffers::nullopt, + this->sctpAssociation ? flatbuffers::Optional(sctpState) + : flatbuffers::nullopt, sctpListener, &traceEventTypes); } @@ -500,7 +404,7 @@ namespace RTC FBS::SctpAssociation::SctpState sctpState{ FBS::SctpAssociation::SctpState::NEW }; // Add sctpState. - if (Settings::configuration.useBuiltInSctpStack && this->sctpAssociation) + if (this->sctpAssociation) { // NOTE: There is never permanent FAILED state. switch (this->sctpAssociation->GetAssociationState()) @@ -531,42 +435,6 @@ namespace RTC } } } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else if (!Settings::configuration.useBuiltInSctpStack && this->oldSctpAssociation) - { - switch (this->oldSctpAssociation->GetState()) - { - case RTC::SctpAssociation::SctpState::NEW: - { - sctpState = FBS::SctpAssociation::SctpState::NEW; - break; - } - - case RTC::SctpAssociation::SctpState::CONNECTING: - { - sctpState = FBS::SctpAssociation::SctpState::CONNECTING; - break; - } - - case RTC::SctpAssociation::SctpState::CONNECTED: - { - sctpState = FBS::SctpAssociation::SctpState::CONNECTED; - break; - } - - case RTC::SctpAssociation::SctpState::FAILED: - { - sctpState = FBS::SctpAssociation::SctpState::FAILED; - break; - } - - case RTC::SctpAssociation::SctpState::CLOSED: - { - sctpState = FBS::SctpAssociation::SctpState::CLOSED; - break; - } - } - } return FBS::Transport::CreateStatsDirect( builder, @@ -575,9 +443,8 @@ namespace RTC // timestamp. nowMs, // sctpState. - (this->sctpAssociation || this->oldSctpAssociation) - ? flatbuffers::Optional(sctpState) - : flatbuffers::nullopt, + this->sctpAssociation ? flatbuffers::Optional(sctpState) + : flatbuffers::nullopt, // bytesReceived. this->recvTransmission.GetBytes(), // recvBitrate. @@ -1160,10 +1027,7 @@ namespace RTC case Channel::ChannelRequest::Method::TRANSPORT_PRODUCE_DATA: { // Early check. The Transport must support SCTP or be direct. - if ( - ((Settings::configuration.useBuiltInSctpStack && !this->sctpAssociation) || - (!Settings::configuration.useBuiltInSctpStack && !this->oldSctpAssociation)) && - !this->direct) + if (!this->sctpAssociation && !this->direct) { MS_THROW_ERROR("SCTP not enabled and not a direct Transport"); } @@ -1176,17 +1040,15 @@ namespace RTC CheckNoDataProducer(dataProducerId); // This may throw. - auto* dataProducer = - new RTC::DataProducer(this->shared, dataProducerId, this->maxMessageSize, this, body); + auto* dataProducer = new RTC::DataProducer( + this->shared, dataProducerId, this->maxReceiveMessageSize, this, body); // Verify the type of the DataProducer. switch (dataProducer->GetType()) { case RTC::DataProducer::Type::SCTP: { - if ( - (Settings::configuration.useBuiltInSctpStack && !this->sctpAssociation) || - (!Settings::configuration.useBuiltInSctpStack && !this->oldSctpAssociation)) + if (!this->sctpAssociation) { delete dataProducer; @@ -1259,15 +1121,7 @@ namespace RTC if (dataProducer->GetType() == RTC::DataProducer::Type::SCTP) { // Tell to the SCTP association. - if (Settings::configuration.useBuiltInSctpStack) - { - this->sctpAssociation->MayConnect(); - } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else - { - this->oldSctpAssociation->HandleDataProducer(dataProducer); - } + this->sctpAssociation->MayConnect(); } break; @@ -1276,10 +1130,7 @@ namespace RTC case Channel::ChannelRequest::Method::TRANSPORT_CONSUME_DATA: { // Early check. The Transport must support SCTP or be direct. - if ( - ((Settings::configuration.useBuiltInSctpStack && !this->sctpAssociation) || - (!Settings::configuration.useBuiltInSctpStack && !this->oldSctpAssociation)) && - !this->direct) + if (!this->sctpAssociation && !this->direct) { MS_THROW_ERROR("SCTP not enabled and not a direct Transport"); } @@ -1294,16 +1145,14 @@ namespace RTC // This may throw. auto* dataConsumer = new RTC::DataConsumer( - this->shared, dataConsumerId, dataProducerId, this, body, this->maxMessageSize); + this->shared, dataConsumerId, dataProducerId, this, body, this->maxSendMessageSize); // Verify the type of the DataConsumer. switch (dataConsumer->GetType()) { case RTC::DataConsumer::Type::SCTP: { - if ( - (Settings::configuration.useBuiltInSctpStack && !this->sctpAssociation) || - (!Settings::configuration.useBuiltInSctpStack && !this->oldSctpAssociation)) + if (!this->sctpAssociation) { delete dataConsumer; @@ -1312,6 +1161,18 @@ namespace RTC ; } + try + { + // This may throw. + CheckNoSctpDataConsumer(dataConsumer->GetSctpStreamParameters().streamId); + } + catch (const MediaSoupError& error) + { + delete dataConsumer; + + throw; + } + break; } @@ -1346,6 +1207,12 @@ namespace RTC // Insert into the maps. this->mapDataConsumers[dataConsumerId] = dataConsumer; + if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) + { + this->mapSctpStreamIdDataConsumers[dataConsumer->GetSctpStreamParameters().streamId] = + dataConsumer; + } + MS_DEBUG_DEV( "DataConsumer created [dataConsumerId:%s, dataProducerId:%s]", dataConsumerId.c_str(), @@ -1362,29 +1229,14 @@ namespace RTC if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) { - if (Settings::configuration.useBuiltInSctpStack) + if (this->sctpAssociation->GetAssociationState() == RTC::SCTP::Types::AssociationState::CONNECTED) { - if (this->sctpAssociation->GetAssociationState() == RTC::SCTP::Types::AssociationState::CONNECTED) - { - // Tell to the DataConsumer. - dataConsumer->SctpAssociationConnected(); - } - - // Tell to the SCTP association. - this->sctpAssociation->MayConnect(); + // Tell to the DataConsumer. + dataConsumer->SctpAssociationConnected(); } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else - { - if (this->oldSctpAssociation->GetState() == RTC::SctpAssociation::SctpState::CONNECTED) - { - // Tell to the DataConsumer. - dataConsumer->SctpAssociationConnected(); - } - // Tell to the SCTP association. - this->oldSctpAssociation->HandleDataConsumer(dataConsumer); - } + // Tell to the SCTP association. + this->sctpAssociation->MayConnect(); } break; @@ -1429,7 +1281,7 @@ namespace RTC const auto* body = request->data->body_as(); // This may throw. - RTC::Producer* producer = GetProducerById(body->producerId()->str()); + RTC::Producer* producer = AssertAndGetProducerById(body->producerId()->str()); // Remove it from the RtpListener. this->rtpListener.RemoveProducer(producer); @@ -1468,7 +1320,7 @@ namespace RTC const auto* body = request->data->body_as(); // This may throw. - RTC::Consumer* consumer = GetConsumerById(body->consumerId()->str()); + RTC::Consumer* consumer = AssertAndGetConsumerById(body->consumerId()->str()); // Remove it from the maps. this->mapConsumers.erase(consumer->id); @@ -1511,10 +1363,7 @@ namespace RTC case Channel::ChannelRequest::Method::TRANSPORT_CLOSE_DATAPRODUCER: { - if ( - ((Settings::configuration.useBuiltInSctpStack && !this->sctpAssociation) || - (!Settings::configuration.useBuiltInSctpStack && !this->oldSctpAssociation)) && - !this->direct) + if (!this->sctpAssociation && !this->direct) { MS_THROW_ERROR("cannot close DataProducer, SCTP not enabled and not a direct Transport"); } @@ -1522,7 +1371,7 @@ namespace RTC const auto* body = request->data->body_as(); // This may throw. - RTC::DataProducer* dataProducer = GetDataProducerById(body->dataProducerId()->str()); + RTC::DataProducer* dataProducer = AssertAndGetDataProducerById(body->dataProducerId()->str()); if (dataProducer->GetType() == RTC::DataProducer::Type::SCTP) { @@ -1533,25 +1382,24 @@ namespace RTC // Remove it from the map. this->mapDataProducers.erase(dataProducer->id); + // https://datatracker.ietf.org/doc/html/rfc8831#section-6.7 + // + // "Closing of a data channel MUST be signaled by resetting the corresponding + // outgoing streams [RFC6525]. This means that if one side decides to close + // the data channel, it resets the corresponding outgoing stream. When the + // peer sees that an incoming stream was reset, it also resets its + // corresponding outgoing stream." + if (this->sctpAssociation && this->sctpAssociation->IsDataChannel()) + { + this->sctpAssociation->ResetStreams( + std::array{ dataProducer->GetSctpStreamParameters().streamId }); + } + // Notify the listener. this->listener->OnTransportDataProducerClosed(this, dataProducer); MS_DEBUG_DEV("DataProducer closed [dataProducerId:%s]", dataProducer->id.c_str()); - if (dataProducer->GetType() == RTC::DataProducer::Type::SCTP) - { - if (Settings::configuration.useBuiltInSctpStack) - { - // TODO: SCTP - } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else - { - // Tell the SctpAssociation so it can reset the SCTP stream. - this->oldSctpAssociation->DataProducerClosed(dataProducer); - } - } - // Delete it. delete dataProducer; @@ -1562,10 +1410,7 @@ namespace RTC case Channel::ChannelRequest::Method::TRANSPORT_CLOSE_DATACONSUMER: { - if ( - ((Settings::configuration.useBuiltInSctpStack && !this->sctpAssociation) || - (!Settings::configuration.useBuiltInSctpStack && !this->oldSctpAssociation)) && - !this->direct) + if (!this->sctpAssociation && !this->direct) { MS_THROW_ERROR("cannot close DataConsumer, SCTP not enabled and not a direct Transport"); } @@ -1573,30 +1418,27 @@ namespace RTC const auto* body = request->data->body_as(); // This may throw. - RTC::DataConsumer* dataConsumer = GetDataConsumerById(body->dataConsumerId()->str()); + RTC::DataConsumer* dataConsumer = AssertAndGetDataConsumerById(body->dataConsumerId()->str()); // Remove it from the maps. this->mapDataConsumers.erase(dataConsumer->id); + if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) + { + this->mapSctpStreamIdDataConsumers.erase(dataConsumer->GetSctpStreamParameters().streamId); + } + + if (this->sctpAssociation) + { + this->sctpAssociation->ResetStreams( + std::array{ dataConsumer->GetSctpStreamParameters().streamId }); + } + // Notify the listener. this->listener->OnTransportDataConsumerClosed(this, dataConsumer); MS_DEBUG_DEV("DataConsumer closed [dataConsumerId:%s]", dataConsumer->id.c_str()); - if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) - { - if (Settings::configuration.useBuiltInSctpStack) - { - // TODO: SCTP - } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else - { - // Tell the SctpAssociation so it can reset the SCTP stream. - this->oldSctpAssociation->DataConsumerClosed(dataConsumer); - } - } - // Delete it. delete dataConsumer; @@ -1639,16 +1481,13 @@ namespace RTC { MS_TRACE(); - if (Settings::configuration.useBuiltInSctpStack) + if (this->sctpAssociation) { - if (this->sctpAssociation) - { - // NOTE: We don't invoke `Shutdown()` but `Close()` in the SCTP Association - // because at this point we are closing everything and we won't have any - // chance to complete the SCTP SHUTDOWN + SHUTDOWN_ACK + SHUTDOWN_COMPLETE - // dance, so we invoke `Close()` which just sends a SCTP ABORT. - this->sctpAssociation->Close(); - } + // NOTE: We don't invoke `Shutdown()` but `Close()` in the SCTP Association + // because at this point we are closing everything and we won't have any + // chance to complete the SCTP SHUTDOWN + SHUTDOWN_ACK + SHUTDOWN_COMPLETE + // dance, so we invoke `Close()` which just sends a SCTP ABORT. + this->sctpAssociation->Close(); } this->isDestroying = true; @@ -1675,15 +1514,10 @@ namespace RTC } // Tell the SctpAssociation. - if (Settings::configuration.useBuiltInSctpStack && this->sctpAssociation) + if (this->sctpAssociation) { this->sctpAssociation->MayConnect(); } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else if (!Settings::configuration.useBuiltInSctpStack && this->oldSctpAssociation) - { - this->oldSctpAssociation->TransportConnected(); - } // Start the RTCP timer. this->rtcpTimer->Start(static_cast(RTC::RTCP::MaxVideoIntervalMs / 2)); @@ -1729,13 +1563,6 @@ namespace RTC dataConsumer->TransportDisconnected(); } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - // Tell the SctpAssociation. - if (!Settings::configuration.useBuiltInSctpStack && this->oldSctpAssociation) - { - this->oldSctpAssociation->TransportDisconnected(); - } - // Stop the RTCP timer. this->rtcpTimer->Stop(); @@ -1860,9 +1687,7 @@ namespace RTC { MS_TRACE(); - if ( - (Settings::configuration.useBuiltInSctpStack && !this->sctpAssociation) || - (!Settings::configuration.useBuiltInSctpStack && !this->oldSctpAssociation)) + if (!this->sctpAssociation) { MS_DEBUG_TAG(sctp, "ignoring SCTP packet (SCTP not enabled)"); @@ -1870,40 +1695,7 @@ namespace RTC } // Pass it to the SctpAssociation. - if (Settings::configuration.useBuiltInSctpStack) - { - this->sctpAssociation->ReceiveSctpData(data, len); - } - else - { - this->oldSctpAssociation->ProcessSctpData(data, len); - } - } - - // TODO: SCTP: Remove when we have our own SCTP stack running. - void Transport::SendSctpMessage( - RTC::DataConsumer* dataConsumer, const uint8_t* msg, size_t len, uint32_t ppid, onQueuedCallback* cb) - { - MS_TRACE(); - - MS_ASSERT( - !Settings::configuration.useBuiltInSctpStack, - "cannot use this method when built-in SCTP stack is enabled"); - - if (!this->oldSctpAssociation) - { - MS_THROW_ERROR("SCTP not enabled"); - - if (cb) - { - (*cb)(false, false); - delete cb; - } - - return; - } - - this->oldSctpAssociation->SendSctpMessage(dataConsumer, msg, len, ppid, cb); + this->sctpAssociation->ReceiveSctpData(data, len); } void Transport::SendSctpMessage( @@ -1914,10 +1706,6 @@ namespace RTC // NOTE: The `message` must already have its `streamId` pointing to the same // as in the `dataConsumer` if its type is "sctp", or 0 otherwise. - MS_ASSERT( - Settings::configuration.useBuiltInSctpStack, - "cannot use this method when built-in SCTP stack is not enabled"); - if (!this->sctpAssociation) { MS_THROW_ERROR("SCTP not enabled"); @@ -1973,9 +1761,7 @@ namespace RTC (*cb)(false, /*sctpSendBufferFull*/ true); } - // TODO: SCTP: We don't want this probably since we have events in Association - // for this. - dataConsumer->SctpAssociationSendBufferFull(); + dataConsumer->SctpSendBufferFull(); break; } @@ -2020,7 +1806,17 @@ namespace RTC } } - RTC::Producer* Transport::GetProducerById(const std::string& producerId) const + void Transport::CheckNoSctpDataConsumer(uint16_t streamId) const + { + MS_TRACE(); + + if (this->mapSctpStreamIdDataConsumers.find(streamId) != this->mapSctpStreamIdDataConsumers.end()) + { + MS_THROW_ERROR("an SCTP DataConsumer with same streamId %" PRIu16 " already exists", streamId); + } + } + + RTC::Producer* Transport::AssertAndGetProducerById(const std::string& producerId) const { MS_TRACE(); @@ -2034,7 +1830,7 @@ namespace RTC return it->second; } - RTC::Consumer* Transport::GetConsumerById(const std::string& consumerId) const + RTC::Consumer* Transport::AssertAndGetConsumerById(const std::string& consumerId) const { MS_TRACE(); @@ -2080,7 +1876,7 @@ namespace RTC return consumer; } - RTC::DataProducer* Transport::GetDataProducerById(const std::string& dataProducerId) const + RTC::DataProducer* Transport::AssertAndGetDataProducerById(const std::string& dataProducerId) const { MS_TRACE(); @@ -2094,7 +1890,7 @@ namespace RTC return it->second; } - RTC::DataConsumer* Transport::GetDataConsumerById(const std::string& dataConsumerId) const + RTC::DataConsumer* Transport::AssertAndGetDataConsumerById(const std::string& dataConsumerId) const { MS_TRACE(); @@ -2108,6 +1904,20 @@ namespace RTC return it->second; } + RTC::DataConsumer* Transport::GetSctpDataConsumerByStreamId(uint16_t streamId) const + { + MS_TRACE(); + + auto it = this->mapSctpStreamIdDataConsumers.find(streamId); + + if (it == this->mapSctpStreamIdDataConsumers.end()) + { + MS_THROW_ERROR("SCTP DataConsumer with streamId %" PRIu16 " not found", streamId); + } + + return it->second; + } + void Transport::HandleRtcpPacket(RTC::RTCP::Packet* packet) { MS_TRACE(); @@ -3038,6 +2848,8 @@ namespace RTC // Notify the listener. this->listener->OnTransportConsumerProducerClosed(this, consumer); + MS_DEBUG_DEV("Consumer closed [consumerId:%s]", consumer->id.c_str()); + // Delete it. delete consumer; @@ -3048,20 +2860,6 @@ namespace RTC } } - void Transport::OnDataProducerMessageReceived( - RTC::DataProducer* dataProducer, - const uint8_t* msg, - size_t len, - uint32_t ppid, - std::vector& subchannels, - std::optional requiredSubchannel) - { - MS_TRACE(); - - this->listener->OnTransportDataProducerMessageReceived( - this, dataProducer, msg, len, ppid, subchannels, requiredSubchannel); - } - void Transport::OnDataProducerMessageReceived( RTC::DataProducer* dataProducer, RTC::SCTP::Message message, @@ -3088,15 +2886,6 @@ namespace RTC this->listener->OnTransportDataProducerResumed(this, dataProducer); } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - void Transport::OnDataConsumerSendMessage( - RTC::DataConsumer* dataConsumer, const uint8_t* msg, size_t len, uint32_t ppid, onQueuedCallback* cb) - { - MS_TRACE(); - - SendMessage(dataConsumer, msg, len, ppid, cb); - } - void Transport::OnDataConsumerSendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, onQueuedCallback* cb) { @@ -3106,26 +2895,48 @@ namespace RTC } void Transport::OnDataConsumerNeedBufferedAmount( - RTC::DataConsumer* /*dataConsumer*/, uint32_t& bufferedAmount) + const RTC::DataConsumer* dataConsumer, uint32_t& bufferedAmount) const { MS_TRACE(); - if (Settings::configuration.useBuiltInSctpStack && this->sctpAssociation) + if (this->sctpAssociation) { - // TODO: SCTP: Let's see how to obtain `streamId` argument from the DataConsumer. - // bufferedAmount = this->sctpAssociation->GetStreamBufferedAmount(streamId); + bufferedAmount = static_cast(this->sctpAssociation->GetStreamBufferedAmount( + dataConsumer->GetSctpStreamParameters().streamId)); } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else if (!Settings::configuration.useBuiltInSctpStack && this->oldSctpAssociation) + else + { + bufferedAmount = 0; + } + } + + void Transport::OnDataConsumerNeedBufferedAmountLowThreshold( + const RTC::DataConsumer* dataConsumer, uint32_t& bufferedAmountLowThreshold) const + { + if (this->sctpAssociation) { - // NOTE: The underlaying SCTP association uses a common send buffer for all - // data consumers, hence the value given by this method indicates the data - // buffered for all data consumers in the transport. - bufferedAmount = this->oldSctpAssociation->GetSctpBufferedAmount(); + bufferedAmountLowThreshold = + static_cast(this->sctpAssociation->GetStreamBufferedAmountLowThreshold( + dataConsumer->GetSctpStreamParameters().streamId)); } else { - bufferedAmount = 0; + bufferedAmountLowThreshold = 0; + } + } + + void Transport::OnDataConsumerSetBufferedAmountLowThreshold( + const RTC::DataConsumer* dataConsumer, uint32_t bytes) const + { + MS_TRACE(); + + MS_ASSERT( + dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP, "DataConsumer must have type SCTP"); + + if (this->sctpAssociation) + { + this->sctpAssociation->SetStreamBufferedAmountLowThreshold( + dataConsumer->GetSctpStreamParameters().streamId, static_cast(bytes)); } } @@ -3136,26 +2947,22 @@ namespace RTC // Remove it from the maps. this->mapDataConsumers.erase(dataConsumer->id); - // Notify the listener. - this->listener->OnTransportDataConsumerDataProducerClosed(this, dataConsumer); - - if (Settings::configuration.useBuiltInSctpStack) + if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) { - if (this->sctpAssociation && dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) - { - // TODO: SCTP - } + this->mapSctpStreamIdDataConsumers.erase(dataConsumer->GetSctpStreamParameters().streamId); } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - else + + if (this->sctpAssociation) { - if (this->oldSctpAssociation && dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) - { - // Tell the SctpAssociation so it can reset the SCTP stream. - this->oldSctpAssociation->DataConsumerClosed(dataConsumer); - } + this->sctpAssociation->ResetStreams( + std::array{ dataConsumer->GetSctpStreamParameters().streamId }); } + // Notify the listener. + this->listener->OnTransportDataConsumerDataProducerClosed(this, dataConsumer); + + MS_DEBUG_DEV("DataConsumer closed [dataConsumerId:%s]", dataConsumer->id.c_str()); + // Delete it. delete dataConsumer; } @@ -3183,7 +2990,7 @@ namespace RTC MS_TRACE(); // Notify the Node Transport. - auto sctpStateChangeOffset = FBS::Transport::CreateSctpStateChangeNotification( + auto sctpStateChangeNotification = FBS::Transport::CreateSctpStateChangeNotification( this->shared->GetChannelNotifier()->GetBufferBuilder(), FBS::SctpAssociation::SctpState::CONNECTING); @@ -3191,7 +2998,7 @@ namespace RTC this->id, FBS::Notification::Event::TRANSPORT_SCTP_STATE_CHANGE, FBS::Notification::Body::Transport_SctpStateChangeNotification, - sctpStateChangeOffset); + sctpStateChangeNotification); } void Transport::OnAssociationConnected() @@ -3209,8 +3016,26 @@ namespace RTC } } - // Notify the Node Transport. - auto sctpStateChangeOffset = FBS::Transport::CreateSctpStateChangeNotification( + // Notify the upper layer. + + // First tell it about the SCTP negotiated capabilities. + auto sctpNegotiatedCapabilitiesOffset = FBS::SctpAssociation::CreateSctpNegotiatedCapabilities( + this->shared->GetChannelNotifier()->GetBufferBuilder(), + this->sctpAssociation->GetNegotiatedMaxOutboundStreams(), + this->sctpAssociation->GetNegotiatedMaxInboundStreams()); + + auto sctpNegotiatedCapabilitiesNotification = + FBS::Transport::CreateSctpNegotiatedCapabilitiesNotification( + this->shared->GetChannelNotifier()->GetBufferBuilder(), sctpNegotiatedCapabilitiesOffset); + + this->shared->GetChannelNotifier()->Emit( + this->id, + FBS::Notification::Event::TRANSPORT_SCTP_NEGOTIATED_CAPABILITIES, + FBS::Notification::Body::Transport_SctpNegotiatedCapabilitiesNotification, + sctpNegotiatedCapabilitiesNotification); + + // Then announce "connected" SCTP state. + auto sctpStateChangeNotification = FBS::Transport::CreateSctpStateChangeNotification( this->shared->GetChannelNotifier()->GetBufferBuilder(), FBS::SctpAssociation::SctpState::CONNECTED); @@ -3218,7 +3043,7 @@ namespace RTC this->id, FBS::Notification::Event::TRANSPORT_SCTP_STATE_CHANGE, FBS::Notification::Body::Transport_SctpStateChangeNotification, - sctpStateChangeOffset); + sctpStateChangeNotification); // For debugging purposes. #if MS_LOG_DEV_LEVEL == 3 @@ -3253,7 +3078,7 @@ namespace RTC } // Notify the Node Transport. - auto sctpStateChangeOffset = FBS::Transport::CreateSctpStateChangeNotification( + auto sctpStateChangeNotification = FBS::Transport::CreateSctpStateChangeNotification( this->shared->GetChannelNotifier()->GetBufferBuilder(), FBS::SctpAssociation::SctpState::FAILED); @@ -3261,7 +3086,7 @@ namespace RTC this->id, FBS::Notification::Event::TRANSPORT_SCTP_STATE_CHANGE, FBS::Notification::Body::Transport_SctpStateChangeNotification, - sctpStateChangeOffset); + sctpStateChangeNotification); } void Transport::OnAssociationClosed(RTC::SCTP::Types::ErrorKind errorKind, std::string_view errorMessage) @@ -3293,7 +3118,7 @@ namespace RTC } // Notify the Node Transport. - auto sctpStateChangeOffset = FBS::Transport::CreateSctpStateChangeNotification( + auto sctpStateChangeNotification = FBS::Transport::CreateSctpStateChangeNotification( this->shared->GetChannelNotifier()->GetBufferBuilder(), FBS::SctpAssociation::SctpState::CLOSED); @@ -3301,7 +3126,7 @@ namespace RTC this->id, FBS::Notification::Event::TRANSPORT_SCTP_STATE_CHANGE, FBS::Notification::Body::Transport_SctpStateChangeNotification, - sctpStateChangeOffset); + sctpStateChangeNotification); } void Transport::OnAssociationRestarted() @@ -3364,222 +3189,119 @@ namespace RTC { MS_TRACE(); - // TODO: SCTP + MS_DEBUG_DEV("SCTP association streams reset performed"); } void Transport::OnAssociationStreamsResetFailed( - std::span /*outboundStreamIds*/, std::string_view /*errorMessage*/) + std::span /*outboundStreamIds*/, std::string_view errorMessage) { MS_TRACE(); - // TODO: SCTP - } - - void Transport::OnAssociationInboundStreamsReset(std::span /*inboundStreamIds*/) - { - MS_TRACE(); - - // TODO: SCTP - } - - void Transport::OnAssociationStreamBufferedAmountLow(uint16_t /*streamId*/) - { - MS_TRACE(); - - // TODO: SCTP - } - - void Transport::OnAssociationTotalBufferedAmountLow() - { - MS_TRACE(); - - // TODO: SCTP + MS_WARN_TAG( + sctp, + "SCTP association streams reset failed [message:%.*s]", + static_cast(errorMessage.size()), + errorMessage.data()); } - bool Transport::OnAssociationIsTransportReadyForSctp() + void Transport::OnAssociationInboundStreamsReset(std::span inboundStreamIds) { MS_TRACE(); - // We are ready for SCTP traffic if the transport is connected (e.g. the - // WebRtcTransport has ICE and DTLS connected) and there is at least a - // DataProducer or DataConsumer. + // https://datatracker.ietf.org/doc/html/rfc8831#section-6.7 // - // NOTE: We don't want to start SCTP connection if there are no DataProducers - // and DataConsumers because the peer (e.g. a browser) may have not started - // its SCTP stack (e.g. no "m=application" media section in its SDP) so if we - // initiate the SCTP connection it would fail after some time. - return IsConnected() && (this->mapDataProducers.size() > 0 || this->mapDataConsumers.size() > 0); - } - - // TODO: SCTP: Add OnAssociationLifecycleMessageXxxxxx() methods. - - void Transport::OnSctpAssociationConnecting(RTC::SctpAssociation* /*sctpAssociation*/) - { - MS_TRACE(); - - // Notify the Node Transport. - auto sctpStateChangeOffset = FBS::Transport::CreateSctpStateChangeNotification( - this->shared->GetChannelNotifier()->GetBufferBuilder(), - FBS::SctpAssociation::SctpState::CONNECTING); - - this->shared->GetChannelNotifier()->Emit( - this->id, - FBS::Notification::Event::TRANSPORT_SCTP_STATE_CHANGE, - FBS::Notification::Body::Transport_SctpStateChangeNotification, - sctpStateChangeOffset); - } - - void Transport::OnSctpAssociationConnected(RTC::SctpAssociation* /*sctpAssociation*/) - { - MS_TRACE(); - - // Tell all DataConsumers. - for (auto& kv : this->mapDataConsumers) + // "Closing of a data channel MUST be signaled by resetting the corresponding + // outgoing streams [RFC6525]. This means that if one side decides to close + // the data channel, it resets the corresponding outgoing stream. When the + // peer sees that an incoming stream was reset, it also resets its + // corresponding outgoing stream." + if (this->sctpAssociation->IsDataChannel()) { - auto* dataConsumer = kv.second; + std::vector dataConsumersToClose; + std::vector streamsToReset; - if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) + for (const auto streamId : inboundStreamIds) { - dataConsumer->SctpAssociationConnected(); - } - } + // Only reset the outgoing stream if there is a live DataConsumer + // using it. If the DataChannel was closed by the app, the DataConsumer + // will have already been closed and removed. + const auto it = this->mapSctpStreamIdDataConsumers.find(streamId); - // Notify the Node Transport. - auto sctpStateChangeOffset = FBS::Transport::CreateSctpStateChangeNotification( - this->shared->GetChannelNotifier()->GetBufferBuilder(), - FBS::SctpAssociation::SctpState::CONNECTED); - - this->shared->GetChannelNotifier()->Emit( - this->id, - FBS::Notification::Event::TRANSPORT_SCTP_STATE_CHANGE, - FBS::Notification::Body::Transport_SctpStateChangeNotification, - sctpStateChangeOffset); - } - - void Transport::OnSctpAssociationFailed(RTC::SctpAssociation* /*sctpAssociation*/) - { - MS_TRACE(); + if (it != this->mapSctpStreamIdDataConsumers.end()) + { + auto* dataConsumer = it->second; - // Tell all DataConsumers. - for (auto& kv : this->mapDataConsumers) - { - auto* dataConsumer = kv.second; + dataConsumersToClose.push_back(dataConsumer); + streamsToReset.push_back(streamId); + } + } - if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) + if (!dataConsumersToClose.empty()) { - dataConsumer->SctpAssociationClosed(); - } - } + this->sctpAssociation->ResetStreams(streamsToReset); - // Notify the Node Transport. - auto sctpStateChangeOffset = FBS::Transport::CreateSctpStateChangeNotification( - this->shared->GetChannelNotifier()->GetBufferBuilder(), - FBS::SctpAssociation::SctpState::FAILED); + for (auto* dataConsumer : dataConsumersToClose) + { + // Remove it from the maps. + this->mapDataConsumers.erase(dataConsumer->id); - this->shared->GetChannelNotifier()->Emit( - this->id, - FBS::Notification::Event::TRANSPORT_SCTP_STATE_CHANGE, - FBS::Notification::Body::Transport_SctpStateChangeNotification, - sctpStateChangeOffset); - } + if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) + { + this->mapSctpStreamIdDataConsumers.erase(dataConsumer->GetSctpStreamParameters().streamId); + } - void Transport::OnSctpAssociationClosed(RTC::SctpAssociation* /*sctpAssociation*/) - { - MS_TRACE(); + // Notify the listener. + this->listener->OnTransportDataConsumerClosed(this, dataConsumer); - // Tell all DataConsumers. - for (auto& kv : this->mapDataConsumers) - { - auto* dataConsumer = kv.second; + MS_DEBUG_DEV( + "SCTP DataConsumer closed via SCTP inbound stream reset [dataConsumerId:%s, streamId:%" PRIu16 + "]", + dataConsumer->id.c_str(), + dataConsumer->GetSctpStreamParameters().streamId); - if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) - { - dataConsumer->SctpAssociationClosed(); + // Delete it. + delete dataConsumer; + } } } - - // Notify the Node Transport. - auto sctpStateChangeOffset = FBS::Transport::CreateSctpStateChangeNotification( - this->shared->GetChannelNotifier()->GetBufferBuilder(), - FBS::SctpAssociation::SctpState::CLOSED); - - this->shared->GetChannelNotifier()->Emit( - this->id, - FBS::Notification::Event::TRANSPORT_SCTP_STATE_CHANGE, - FBS::Notification::Body::Transport_SctpStateChangeNotification, - sctpStateChangeOffset); } - void Transport::OnSctpAssociationSendData( - RTC::SctpAssociation* /*sctpAssociation*/, const uint8_t* data, size_t len) + void Transport::OnAssociationStreamBufferedAmountLow(uint16_t streamId) { MS_TRACE(); - // Ignore if destroying. - // NOTE: This is because when the child class (i.e. WebRtcTransport) is deleted, - // its destructor is called first and then the parent Transport's destructor, - // and we would end here calling SendSctpData() which is an abstract method. - if (this->isDestroying) - { - MS_WARN_DEV("ignoring sending data because Transport is being destroying"); + const auto* dataConsumer = GetSctpDataConsumerByStreamId(streamId); + if (!dataConsumer) + { return; } - SendData(data, len); + dataConsumer->SctpBufferedAmountLow(this->sctpAssociation->GetStreamBufferedAmount(streamId)); } - void Transport::OnSctpAssociationMessageReceived( - RTC::SctpAssociation* /*sctpAssociation*/, - uint16_t streamId, - const uint8_t* msg, - size_t len, - uint32_t ppid) + void Transport::OnAssociationTotalBufferedAmountLow() { MS_TRACE(); - RTC::DataProducer* dataProducer = this->sctpListener.GetDataProducer(streamId); - - if (!dataProducer) - { - MS_WARN_TAG( - sctp, "no suitable DataProducer for received SCTP message [streamId:%" PRIu16 "]", streamId); - - return; - } - - // Pass the SCTP message to the corresponding DataProducer. - try - { - static thread_local std::vector emptySubchannels; - - dataProducer->ReceiveMessage( - msg, len, ppid, emptySubchannels, /*requiredSubchannel*/ std::nullopt); - } - catch (std::exception& error) - { - MS_WARN_TAG( - sctp, - "DataProducer::ReceiveMessage() failed for received SCTP message [streamId:%" PRIu16 "]: %s", - streamId, - error.what()); - } + // TODO: SCTP: Here we should emit a new event to the upper layer saying + // that the transport SCTP total buffered amount is low. However we don't + // expose `SctpOptions::totalBufferedAmountLowThreshold` to Transport. } - void Transport::OnSctpAssociationBufferedAmount( - RTC::SctpAssociation* /*sctpAssociation*/, uint32_t bufferedAmount) + bool Transport::OnAssociationIsTransportReadyForSctp() { MS_TRACE(); - for (const auto& kv : this->mapDataConsumers) - { - auto* dataConsumer = kv.second; - - if (dataConsumer->GetType() == RTC::DataConsumer::Type::SCTP) - { - dataConsumer->SetSctpAssociationBufferedAmount(bufferedAmount); - } - } + // We are ready for SCTP traffic if the transport is connected (e.g. the + // WebRtcTransport has ICE and DTLS connected) and there is at least a + // DataProducer or DataConsumer. + // + // NOTE: We don't want to start SCTP connection if there are no DataProducers + // and DataConsumers because the peer (e.g. a browser) may have not started + // its SCTP stack (e.g. no "m=application" media section in its SDP) so if we + // initiate the SCTP connection it would fail after some time. + return IsConnected() && (!this->mapDataProducers.empty() || !this->mapDataConsumers.empty()); } void Transport::OnTransportCongestionControlClientBitrates( diff --git a/worker/src/RTC/WebRtcServer.cpp b/worker/src/RTC/WebRtcServer.cpp index af575cc5f2..38cbf3ebdb 100644 --- a/worker/src/RTC/WebRtcServer.cpp +++ b/worker/src/RTC/WebRtcServer.cpp @@ -4,9 +4,9 @@ #include "Logger.hpp" #include "MediaSoupErrors.hpp" +#include "RTC/WebRtcServer.hpp" #include "Settings.hpp" #include "Utils.hpp" -#include "RTC/WebRtcServer.hpp" #include // std::pow() namespace RTC diff --git a/worker/src/RTC/WebRtcTransport.cpp b/worker/src/RTC/WebRtcTransport.cpp index 57586b9cd2..0384415578 100644 --- a/worker/src/RTC/WebRtcTransport.cpp +++ b/worker/src/RTC/WebRtcTransport.cpp @@ -2,11 +2,11 @@ // #define MS_LOG_DEV_LEVEL 3 #include "RTC/WebRtcTransport.hpp" +#include "FBS/webRtcTransport.h" #include "Logger.hpp" #include "MediaSoupErrors.hpp" #include "Settings.hpp" #include "Utils.hpp" -#include "FBS/webRtcTransport.h" #include // std::pow() namespace RTC @@ -859,15 +859,6 @@ namespace RTC RTC::Transport::DataSent(len); } - // TODO: SCTP: Remove once we only use built-in SCTP stack. - void WebRtcTransport::SendMessage( - RTC::DataConsumer* dataConsumer, const uint8_t* msg, size_t len, uint32_t ppid, onQueuedCallback* cb) - { - MS_TRACE(); - - SendSctpMessage(dataConsumer, msg, len, ppid, cb); - } - void WebRtcTransport::SendMessage( RTC::DataConsumer* dataConsumer, RTC::SCTP::Message message, onQueuedCallback* cb) { diff --git a/worker/src/Settings.cpp b/worker/src/Settings.cpp index ded575edcb..eb5e44f8c3 100644 --- a/worker/src/Settings.cpp +++ b/worker/src/Settings.cpp @@ -60,7 +60,6 @@ void Settings::SetConfiguration(int argc, char* argv[]) { .name="dtlsPrivateKeyFile", .has_arg=optional_argument, .flag=nullptr, .val='p' }, { .name="libwebrtcFieldTrials", .has_arg=optional_argument, .flag=nullptr, .val='W' }, { .name="disableLiburing", .has_arg=optional_argument, .flag=nullptr, .val='d' }, - { .name="useBuiltInSctpStack", .has_arg=optional_argument, .flag=nullptr, .val='s' }, { .name=nullptr, .has_arg=0, .flag=nullptr, .val=0 } }; // clang-format on @@ -172,22 +171,6 @@ void Settings::SetConfiguration(int argc, char* argv[]) break; } - case 's': - { - stringValue = std::string(optarg); - - if (stringValue == "true") - { - Settings::configuration.useBuiltInSctpStack = true; - } - else - { - Settings::configuration.useBuiltInSctpStack = false; - } - - break; - } - // Invalid option. case '?': { @@ -400,8 +383,6 @@ void Settings::PrintConfiguration() info, " libwebrtcFieldTrials: %s", Settings::configuration.libwebrtcFieldTrials.c_str()); } MS_DEBUG_TAG(info, " disableLiburing: %s", Settings::configuration.disableLiburing ? "yes" : "no"); - MS_DEBUG_TAG( - info, " useBuiltInSctpStack: %s", Settings::configuration.useBuiltInSctpStack ? "yes" : "no"); MS_DEBUG_TAG(info, ""); } diff --git a/worker/src/Shared.cpp b/worker/src/Shared.cpp index 292b9afdc1..facfff39fc 100644 --- a/worker/src/Shared.cpp +++ b/worker/src/Shared.cpp @@ -2,9 +2,9 @@ // #define MS_LOG_DEV_LEVEL 3 #include "Shared.hpp" -#include "Logger.hpp" #include "handles/BackoffTimerHandle.hpp" #include "handles/TimerHandle.hpp" +#include "Logger.hpp" Shared::Shared( Channel::ChannelMessageRegistrator* channelMessageRegistrator, diff --git a/worker/src/Worker.cpp b/worker/src/Worker.cpp index d10f227b2f..ea3a601b3b 100644 --- a/worker/src/Worker.cpp +++ b/worker/src/Worker.cpp @@ -5,14 +5,12 @@ #ifdef MS_LIBURING_SUPPORTED #include "DepLibUring.hpp" #endif +#include "FBS/response.h" +#include "FBS/worker.h" #include "DepLibUV.hpp" -// TODO: Remove once we only use built-in SCTP stack. -#include "DepUsrSCTP.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" #include "Settings.hpp" -#include "FBS/response.h" -#include "FBS/worker.h" /* Instance methods. */ @@ -35,13 +33,6 @@ Worker::Worker(::Channel::ChannelSocket* channel, SharedInterface* shared) } #endif - // TODO: Remove once we only use built-in SCTP stack. - if (!Settings::configuration.useBuiltInSctpStack) - { - // Create the Checker instance in DepUsrSCTP. - DepUsrSCTP::CreateChecker(this->shared); - } - #ifdef MS_LIBURING_SUPPORTED if (DepLibUring::IsEnabled()) { @@ -101,13 +92,6 @@ void Worker::Close() } this->mapWebRtcServers.clear(); - // TODO: Remove once we only use built-in SCTP stack. - if (!Settings::configuration.useBuiltInSctpStack) - { - // Close the Checker instance in DepUsrSCTP. - DepUsrSCTP::CloseChecker(); - } - #ifdef MS_LIBURING_SUPPORTED if (DepLibUring::IsEnabled()) { @@ -232,7 +216,7 @@ flatbuffers::Offset Worker::FillBufferResour uvRusage.ru_nivcsw); } -RTC::WebRtcServer* Worker::GetWebRtcServer(const std::string& webRtcServerId) const +RTC::WebRtcServer* Worker::AssertAndGetWebRtcServerById(const std::string& webRtcServerId) const { auto it = this->mapWebRtcServers.find(webRtcServerId); @@ -244,7 +228,7 @@ RTC::WebRtcServer* Worker::GetWebRtcServer(const std::string& webRtcServerId) co return it->second; } -RTC::Router* Worker::GetRouter(const std::string& routerId) const +RTC::Router* Worker::AssertAndGetRouterById(const std::string& routerId) const { MS_TRACE(); @@ -348,7 +332,7 @@ void Worker::HandleRequest(Channel::ChannelRequest* request) try { - webRtcServer = GetWebRtcServer(webRtcServerId); + webRtcServer = AssertAndGetWebRtcServerById(webRtcServerId); } catch (const MediaSoupError& error) { @@ -403,7 +387,7 @@ void Worker::HandleRequest(Channel::ChannelRequest* request) try { - router = GetRouter(routerId); + router = AssertAndGetRouterById(routerId); } catch (const MediaSoupError& error) { diff --git a/worker/src/lib.cpp b/worker/src/lib.cpp index 970612e012..7ac2ad9ea1 100644 --- a/worker/src/lib.cpp +++ b/worker/src/lib.cpp @@ -7,22 +7,20 @@ #ifdef MS_LIBURING_SUPPORTED #include "DepLibUring.hpp" #endif +#include "Channel/ChannelMessageRegistrator.hpp" +#include "Channel/ChannelNotifier.hpp" +#include "Channel/ChannelSocket.hpp" #include "DepLibUV.hpp" #include "DepLibWebRTC.hpp" #include "DepOpenSSL.hpp" -// TODO: Remove once we only use built-in SCTP stack. -#include "DepUsrSCTP.hpp" #include "Logger.hpp" #include "MediaSoupErrors.hpp" +#include "RTC/DtlsTransport.hpp" +#include "RTC/SrtpSession.hpp" #include "Settings.hpp" #include "Shared.hpp" #include "Utils.hpp" #include "Worker.hpp" -#include "Channel/ChannelMessageRegistrator.hpp" -#include "Channel/ChannelNotifier.hpp" -#include "Channel/ChannelSocket.hpp" -#include "RTC/DtlsTransport.hpp" -#include "RTC/SrtpSession.hpp" #include #include // sigaction() #include @@ -156,11 +154,6 @@ extern "C" int mediasoup_worker_run( // Initialize static stuff. DepOpenSSL::ClassInit(); DepLibSRTP::ClassInit(); - // TODO: Remove once we only use built-in SCTP stack. - if (!Settings::configuration.useBuiltInSctpStack) - { - DepUsrSCTP::ClassInit(); - } #ifdef MS_LIBURING_SUPPORTED DepLibUring::ClassInit(); #endif @@ -187,11 +180,6 @@ extern "C" int mediasoup_worker_run( DepLibUring::ClassDestroy(); #endif RTC::DtlsTransport::ClassDestroy(); - // TODO: Remove once we only use built-in SCTP stack. - if (!Settings::configuration.useBuiltInSctpStack) - { - DepUsrSCTP::ClassDestroy(); - } DepLibUV::ClassDestroy(); return 0; diff --git a/worker/subprojects/usrsctp.wrap b/worker/subprojects/usrsctp.wrap deleted file mode 100644 index 50eb970944..0000000000 --- a/worker/subprojects/usrsctp.wrap +++ /dev/null @@ -1,8 +0,0 @@ -[wrap-file] -directory = usrsctp-fd070e05a7474f38c7fecdf4d4b6005d2547ee00 -source_url = https://github.com/sctplab/usrsctp/archive/fd070e05a7474f38c7fecdf4d4b6005d2547ee00.zip -source_filename = fd070e05a7474f38c7fecdf4d4b6005d2547ee00.zip -source_hash = a0f9255a88fef2e375b590f2823ddbc70ab38142b9931cd3f1c7c0b700bf7043 - -[provide] -usrsctp = usrsctp_dep diff --git a/worker/test/include/RTC/ICE/iceCommon.hpp b/worker/test/include/RTC/ICE/iceCommon.hpp index acece3dbab..247a1cd928 100644 --- a/worker/test/include/RTC/ICE/iceCommon.hpp +++ b/worker/test/include/RTC/ICE/iceCommon.hpp @@ -3,9 +3,9 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" +#include "RTC/ICE/StunPacket.hpp" #include "Utils.hpp" #include "test/include/testHelpers.hpp" -#include "RTC/ICE/StunPacket.hpp" #include #include // std::malloc(), std::free() #include // std::memcpy() diff --git a/worker/test/include/RTC/RTP/rtpCommon.hpp b/worker/test/include/RTC/RTP/rtpCommon.hpp index b3890003bc..56fa065afb 100644 --- a/worker/test/include/RTC/RTP/rtpCommon.hpp +++ b/worker/test/include/RTC/RTP/rtpCommon.hpp @@ -3,8 +3,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/testHelpers.hpp" #include "RTC/RTP/Packet.hpp" +#include "test/include/testHelpers.hpp" #include #include // std::malloc(), std::free() #include // std::memcpy() diff --git a/worker/test/include/RTC/SCTP/sctpCommon.hpp b/worker/test/include/RTC/SCTP/sctpCommon.hpp index 1834fc22a8..5454b3fce7 100644 --- a/worker/test/include/RTC/SCTP/sctpCommon.hpp +++ b/worker/test/include/RTC/SCTP/sctpCommon.hpp @@ -3,14 +3,14 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "Utils.hpp" -#include "test/include/testHelpers.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/Packet.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/errorCauses/InvalidStreamIdentifierErrorCause.hpp" #include "RTC/SCTP/packet/parameters/HeartbeatInfoParameter.hpp" +#include "Utils.hpp" +#include "test/include/testHelpers.hpp" #include namespace sctpCommon diff --git a/worker/test/src/RTC/ICE/TestStunPacket.cpp b/worker/test/src/RTC/ICE/TestStunPacket.cpp index 89c0e9455e..a30aa32aea 100644 --- a/worker/test/src/RTC/ICE/TestStunPacket.cpp +++ b/worker/test/src/RTC/ICE/TestStunPacket.cpp @@ -1,8 +1,8 @@ #include "common.hpp" +#include "RTC/ICE/StunPacket.hpp" #include "Utils.hpp" #include "test/include/RTC/ICE/iceCommon.hpp" #include "test/include/testHelpers.hpp" -#include "RTC/ICE/StunPacket.hpp" #include #include #include // std::memset() diff --git a/worker/test/src/RTC/RTP/Codecs/TestVP8.cpp b/worker/test/src/RTC/RTP/Codecs/TestVP8.cpp index 763188ee45..535b2c849e 100644 --- a/worker/test/src/RTC/RTP/Codecs/TestVP8.cpp +++ b/worker/test/src/RTC/RTP/Codecs/TestVP8.cpp @@ -1,7 +1,7 @@ #include "common.hpp" -#include "test/include/RTC/RTP/rtpCommon.hpp" #include "RTC/RTP/Codecs/VP8.hpp" #include "RTC/RTP/Packet.hpp" +#include "test/include/RTC/RTP/rtpCommon.hpp" #include #include // std::memcmp(), std::memcpy() diff --git a/worker/test/src/RTC/RTP/Codecs/TestVP9.cpp b/worker/test/src/RTC/RTP/Codecs/TestVP9.cpp index 920804b66b..486af28133 100644 --- a/worker/test/src/RTC/RTP/Codecs/TestVP9.cpp +++ b/worker/test/src/RTC/RTP/Codecs/TestVP9.cpp @@ -1,7 +1,7 @@ #include "common.hpp" -#include "test/include/RTC/RTP/rtpCommon.hpp" #include "RTC/RTP/Codecs/VP9.hpp" #include "RTC/RTP/Packet.hpp" +#include "test/include/RTC/RTP/rtpCommon.hpp" #include #include // std::memcmp() diff --git a/worker/test/src/RTC/RTP/TestPacket.cpp b/worker/test/src/RTC/RTP/TestPacket.cpp index ffc61f7996..2a25b17687 100644 --- a/worker/test/src/RTC/RTP/TestPacket.cpp +++ b/worker/test/src/RTC/RTP/TestPacket.cpp @@ -1,10 +1,10 @@ #include "common.hpp" -#include "Utils.hpp" -#include "test/include/RTC/RTP/rtpCommon.hpp" -#include "test/include/testHelpers.hpp" #include "RTC/RTP/HeaderExtensionIds.hpp" #include "RTC/RTP/Packet.hpp" #include "RTC/RtpDictionaries.hpp" +#include "Utils.hpp" +#include "test/include/RTC/RTP/rtpCommon.hpp" +#include "test/include/testHelpers.hpp" #include #include // std::memset() #include diff --git a/worker/test/src/RTC/RTP/TestRtpStreamRecv.cpp b/worker/test/src/RTC/RTP/TestRtpStreamRecv.cpp index e69e290bb2..6fdff78481 100644 --- a/worker/test/src/RTC/RTP/TestRtpStreamRecv.cpp +++ b/worker/test/src/RTC/RTP/TestRtpStreamRecv.cpp @@ -1,8 +1,8 @@ #include "common.hpp" -#include "mocks/include/MockShared.hpp" #include "RTC/RTP/Packet.hpp" #include "RTC/RTP/RtpStream.hpp" #include "RTC/RTP/RtpStreamRecv.hpp" +#include "mocks/include/MockShared.hpp" #include #include diff --git a/worker/test/src/RTC/RTP/TestRtpStreamSend.cpp b/worker/test/src/RTC/RTP/TestRtpStreamSend.cpp index aa604d0b7d..3d07f268f0 100644 --- a/worker/test/src/RTC/RTP/TestRtpStreamSend.cpp +++ b/worker/test/src/RTC/RTP/TestRtpStreamSend.cpp @@ -1,5 +1,4 @@ #include "common.hpp" -#include "mocks/include/MockShared.hpp" #include "RTC/RTCP/FeedbackRtpNack.hpp" #include "RTC/RTP/Codecs/AV1.hpp" #include "RTC/RTP/Codecs/PayloadDescriptorHandler.hpp" @@ -9,6 +8,7 @@ #include "RTC/RTP/RtpStream.hpp" #include "RTC/RTP/RtpStreamSend.hpp" #include "RTC/RTP/SharedPacket.hpp" +#include "mocks/include/MockShared.hpp" #include #include // std::memcpy() #include diff --git a/worker/test/src/RTC/RTP/TestSharedPacket.cpp b/worker/test/src/RTC/RTP/TestSharedPacket.cpp index d3c1e3a41e..ced108a184 100644 --- a/worker/test/src/RTC/RTP/TestSharedPacket.cpp +++ b/worker/test/src/RTC/RTP/TestSharedPacket.cpp @@ -1,7 +1,7 @@ #include "common.hpp" -#include "test/include/RTC/RTP/rtpCommon.hpp" // in worker/test/include/ #include "RTC/RTP/Packet.hpp" #include "RTC/RTP/SharedPacket.hpp" +#include "test/include/RTC/RTP/rtpCommon.hpp" // in worker/test/include/ #include SCENARIO("RTP SharedPacket", "[rtp][sharedpacket]") diff --git a/worker/test/src/RTC/SCTP/association/TestHeartbeatHandler.cpp b/worker/test/src/RTC/SCTP/association/TestHeartbeatHandler.cpp index 1d3edd92a7..e0f4185037 100644 --- a/worker/test/src/RTC/SCTP/association/TestHeartbeatHandler.cpp +++ b/worker/test/src/RTC/SCTP/association/TestHeartbeatHandler.cpp @@ -1,10 +1,4 @@ #include "common.hpp" -#include "mocks/include/MockShared.hpp" -#include "mocks/include/RTC/SCTP/association/MockAssociationListener.hpp" -#include "mocks/include/RTC/SCTP/association/MockTransmissionControlBlockContext.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" -#include "test/include/catch2Macros.hpp" -#include "test/include/testHelpers.hpp" #include "RTC/SCTP/association/HeartbeatHandler.hpp" #include "RTC/SCTP/packet/Packet.hpp" #include "RTC/SCTP/packet/chunks/HeartbeatAckChunk.hpp" @@ -12,6 +6,12 @@ #include "RTC/SCTP/packet/parameters/HeartbeatInfoParameter.hpp" #include "RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp" #include "RTC/SCTP/public/SctpOptions.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" +#include "test/include/catch2Macros.hpp" +#include "test/include/testHelpers.hpp" +#include "mocks/include/MockShared.hpp" +#include "mocks/include/RTC/SCTP/association/MockAssociationListener.hpp" +#include "mocks/include/RTC/SCTP/association/MockTransmissionControlBlockContext.hpp" #include #include diff --git a/worker/test/src/RTC/SCTP/association/TestNegotiatedCapabilities.cpp b/worker/test/src/RTC/SCTP/association/TestNegotiatedCapabilities.cpp index d1dc486467..4c348d3220 100644 --- a/worker/test/src/RTC/SCTP/association/TestNegotiatedCapabilities.cpp +++ b/worker/test/src/RTC/SCTP/association/TestNegotiatedCapabilities.cpp @@ -1,5 +1,4 @@ #include "common.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/association/NegotiatedCapabilities.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/chunks/InitChunk.hpp" @@ -7,6 +6,7 @@ #include "RTC/SCTP/packet/parameters/SupportedExtensionsParameter.hpp" #include "RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp" #include "RTC/SCTP/public/SctpOptions.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include SCENARIO("SCTP Negotiated Capabilities", "[sctp][negotiatedcapabilities]") diff --git a/worker/test/src/RTC/SCTP/association/TestStateCookie.cpp b/worker/test/src/RTC/SCTP/association/TestStateCookie.cpp index dc898a0952..1ded9ac1b1 100644 --- a/worker/test/src/RTC/SCTP/association/TestStateCookie.cpp +++ b/worker/test/src/RTC/SCTP/association/TestStateCookie.cpp @@ -1,8 +1,8 @@ #include "common.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" // in worker/test/include/ #include "RTC/SCTP/association/NegotiatedCapabilities.hpp" #include "RTC/SCTP/association/StateCookie.hpp" #include "RTC/SCTP/public/SctpTypes.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" // in worker/test/include/ #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/association/TestTransmissionControlBlock.cpp b/worker/test/src/RTC/SCTP/association/TestTransmissionControlBlock.cpp new file mode 100644 index 0000000000..eeed36c33f --- /dev/null +++ b/worker/test/src/RTC/SCTP/association/TestTransmissionControlBlock.cpp @@ -0,0 +1,99 @@ +#include "common.hpp" +#include "DepLibUV.hpp" +#include "RTC/SCTP/association/NegotiatedCapabilities.hpp" +#include "RTC/SCTP/association/PacketSender.hpp" +#include "RTC/SCTP/association/TransmissionControlBlock.hpp" +#include "RTC/SCTP/packet/Packet.hpp" +#include "RTC/SCTP/public/SctpOptions.hpp" +#include "test/include/catch2Macros.hpp" +#include "mocks/include/MockShared.hpp" +#include "mocks/include/RTC/SCTP/association/MockAssociationListener.hpp" +#include "mocks/include/RTC/SCTP/tx/MockSendQueue.hpp" +#include + +SCENARIO("SCTP TransmissionControlBlock", "[sctp][transmissioncontrolblock]") +{ + constexpr uint32_t LocalVerificationTag{ 123 }; + constexpr uint32_t RemoteVerificationTag{ 456 }; + constexpr uint32_t LocalInitialTsn{ 10 }; + constexpr uint32_t RemoteInitialTsn{ 1000 }; + constexpr uint32_t Arwnd{ 65536 }; + constexpr uint64_t TieTag{ 12345678 }; + + class MockPacketSenderListener : public RTC::SCTP::PacketSender::Listener + { + public: + void OnPacketSenderPacketSent( + RTC::SCTP::PacketSender* /*packetSender*/, const RTC::SCTP::Packet* /*packet*/, bool /*sent*/) override + { + } + }; + + const RTC::SCTP::SctpOptions sctpOptions; + + mocks::RTC::SCTP::MockAssociationListener associationListener; + mocks::MockShared shared(/*getTimeMs*/ + []() + { + return DepLibUV::GetTimeMs(); + }); + mocks::RTC::SCTP::MockSendQueue sendQueue; + RTC::SCTP::NegotiatedCapabilities negotiatedCapabilities; + MockPacketSenderListener packetSenderListener; + RTC::SCTP::PacketSender packetSender(std::addressof(packetSenderListener), associationListener); + + auto isAssociationEstablished = []() + { + return true; + }; + + SECTION("without message interleaving") + { + negotiatedCapabilities.messageInterleaving = false; + + sendQueue.ExpectEnableMessageInterleavingCalledWith(false); + + const RTC::SCTP::TransmissionControlBlock tcb( + associationListener, + sctpOptions, + std::addressof(shared), + sendQueue, + packetSender, + LocalVerificationTag, + RemoteVerificationTag, + LocalInitialTsn, + RemoteInitialTsn, + Arwnd, + TieTag, + negotiatedCapabilities, + /*maxPacketLength*/ 1200, + isAssociationEstablished); + + REQUIRE_VERIFICATION_RESULT(sendQueue.VerifyExpectations()); + } + + SECTION("with message interleaving") + { + negotiatedCapabilities.messageInterleaving = true; + + sendQueue.ExpectEnableMessageInterleavingCalledWith(true); + + const RTC::SCTP::TransmissionControlBlock tcb( + associationListener, + sctpOptions, + std::addressof(shared), + sendQueue, + packetSender, + LocalVerificationTag, + RemoteVerificationTag, + LocalInitialTsn, + RemoteInitialTsn, + Arwnd, + TieTag, + negotiatedCapabilities, + /*maxPacketLength*/ 1200, + isAssociationEstablished); + + REQUIRE_VERIFICATION_RESULT(sendQueue.VerifyExpectations()); + } +} diff --git a/worker/test/src/RTC/SCTP/packet/TestChunk.cpp b/worker/test/src/RTC/SCTP/packet/TestChunk.cpp index 18bb6358fa..21405dcd20 100644 --- a/worker/test/src/RTC/SCTP/packet/TestChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/TestChunk.cpp @@ -1,12 +1,12 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/chunks/AbortAssociationChunk.hpp" #include "RTC/SCTP/packet/chunks/InitChunk.hpp" #include "RTC/SCTP/packet/errorCauses/OutOfResourceErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/ProtocolViolationErrorCause.hpp" #include "RTC/SCTP/packet/parameters/ForwardTsnSupportedParameter.hpp" #include "RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include SCENARIO("SCTP Chunk", "[serializable][sctp][chunk]") diff --git a/worker/test/src/RTC/SCTP/packet/TestPacket.cpp b/worker/test/src/RTC/SCTP/packet/TestPacket.cpp index b84c6396e3..3930d8b544 100644 --- a/worker/test/src/RTC/SCTP/packet/TestPacket.cpp +++ b/worker/test/src/RTC/SCTP/packet/TestPacket.cpp @@ -1,6 +1,5 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/Packet.hpp" #include "RTC/SCTP/packet/Parameter.hpp" @@ -13,6 +12,7 @@ #include "RTC/SCTP/packet/parameters/CookiePreservativeParameter.hpp" #include "RTC/SCTP/packet/parameters/HeartbeatInfoParameter.hpp" #include "RTC/SCTP/packet/parameters/IPv4AddressParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestAbortAssociationChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestAbortAssociationChunk.cpp index b9c31c14c2..2ae44f9c14 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestAbortAssociationChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestAbortAssociationChunk.cpp @@ -1,10 +1,10 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/chunks/AbortAssociationChunk.hpp" #include "RTC/SCTP/packet/errorCauses/StaleCookieErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestCookieAckChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestCookieAckChunk.cpp index f48dcd18c3..7ce57d9d90 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestCookieAckChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestCookieAckChunk.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/chunks/CookieAckChunk.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestCookieEchoChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestCookieEchoChunk.cpp index 943a74b2a5..0ff0e80180 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestCookieEchoChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestCookieEchoChunk.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/chunks/CookieEchoChunk.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestDataChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestDataChunk.cpp index a52cef1a2d..6633739d83 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestDataChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestDataChunk.cpp @@ -1,11 +1,11 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/UserData.hpp" #include "RTC/SCTP/packet/chunks/DataChunk.hpp" #include "RTC/SCTP/packet/parameters/IPv4AddressParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() #include diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestForwardTsnChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestForwardTsnChunk.cpp index dd45c15162..1886472306 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestForwardTsnChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestForwardTsnChunk.cpp @@ -1,9 +1,9 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/chunks/AnyForwardTsnChunk.hpp" #include "RTC/SCTP/packet/chunks/ForwardTsnChunk.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() #include diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatAckChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatAckChunk.cpp index 4c5cc25197..de21205a0d 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatAckChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatAckChunk.cpp @@ -1,11 +1,11 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/chunks/HeartbeatAckChunk.hpp" #include "RTC/SCTP/packet/parameters/HeartbeatInfoParameter.hpp" #include "RTC/SCTP/packet/parameters/UnknownParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatRequestChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatRequestChunk.cpp index c93c4a7fc1..d94c75d9e0 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatRequestChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestHeartbeatRequestChunk.cpp @@ -1,11 +1,11 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/chunks/HeartbeatRequestChunk.hpp" #include "RTC/SCTP/packet/parameters/HeartbeatInfoParameter.hpp" #include "RTC/SCTP/packet/parameters/UnknownParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestIDataChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestIDataChunk.cpp index 89467d09e6..8bf3c01b62 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestIDataChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestIDataChunk.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/chunks/IDataChunk.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() #include diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestIForwardTsnChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestIForwardTsnChunk.cpp index c8f8f16602..cdf2d8d1f3 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestIForwardTsnChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestIForwardTsnChunk.cpp @@ -1,9 +1,9 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/chunks/AnyForwardTsnChunk.hpp" #include "RTC/SCTP/packet/chunks/IForwardTsnChunk.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() #include diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestInitAckChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestInitAckChunk.cpp index 11365937d4..aa820b8006 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestInitAckChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestInitAckChunk.cpp @@ -1,10 +1,10 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/chunks/InitAckChunk.hpp" #include "RTC/SCTP/packet/parameters/IPv4AddressParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestInitChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestInitChunk.cpp index c06ab9bdcb..bf28b494e0 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestInitChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestInitChunk.cpp @@ -1,6 +1,5 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/chunks/InitChunk.hpp" @@ -8,6 +7,7 @@ #include "RTC/SCTP/packet/parameters/IPv4AddressParameter.hpp" #include "RTC/SCTP/packet/parameters/IPv6AddressParameter.hpp" #include "RTC/SCTP/packet/parameters/SupportedAddressTypesParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestOperationErrorChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestOperationErrorChunk.cpp index 705c1a81ac..fb7aafc564 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestOperationErrorChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestOperationErrorChunk.cpp @@ -1,6 +1,5 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/chunks/OperationErrorChunk.hpp" @@ -8,6 +7,7 @@ #include "RTC/SCTP/packet/errorCauses/OutOfResourceErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/UnknownErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/UnrecognizedChunkTypeErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestReConfigChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestReConfigChunk.cpp index 4ddf3d517a..a74cb1621d 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestReConfigChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestReConfigChunk.cpp @@ -1,12 +1,12 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/chunks/ReConfigChunk.hpp" #include "RTC/SCTP/packet/parameters/IncomingSsnResetRequestParameter.hpp" #include "RTC/SCTP/packet/parameters/OutgoingSsnResetRequestParameter.hpp" #include "RTC/SCTP/packet/parameters/ReconfigurationResponseParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() #include diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestSackChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestSackChunk.cpp index 8ec1e9aa3e..9d5a163d5b 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestSackChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestSackChunk.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/chunks/SackChunk.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() #include diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownAckChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownAckChunk.cpp index 04a8497ddd..1bb7d618e0 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownAckChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownAckChunk.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/chunks/ShutdownAckChunk.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownChunk.cpp index 4a67b36369..ae5fd54857 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownChunk.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/chunks/ShutdownChunk.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownCompleteChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownCompleteChunk.cpp index 23fbbbc626..f6b51f93bf 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownCompleteChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestShutdownCompleteChunk.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/chunks/ShutdownCompleteChunk.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/chunks/TestUnknownChunk.cpp b/worker/test/src/RTC/SCTP/packet/chunks/TestUnknownChunk.cpp index cb91a7e5e9..b55e62b75a 100644 --- a/worker/test/src/RTC/SCTP/packet/chunks/TestUnknownChunk.cpp +++ b/worker/test/src/RTC/SCTP/packet/chunks/TestUnknownChunk.cpp @@ -1,7 +1,7 @@ #include "common.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/chunks/UnknownChunk.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestCookieReceivedWhileShuttingDownErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestCookieReceivedWhileShuttingDownErrorCause.cpp index a7c6d269bd..1e71e6bbea 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestCookieReceivedWhileShuttingDownErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestCookieReceivedWhileShuttingDownErrorCause.cpp @@ -1,7 +1,7 @@ #include "common.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/CookieReceivedWhileShuttingDownErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestInvalidMandatoryParameterErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestInvalidMandatoryParameterErrorCause.cpp index f0cbd4eca8..2299e6f7f8 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestInvalidMandatoryParameterErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestInvalidMandatoryParameterErrorCause.cpp @@ -1,7 +1,7 @@ #include "common.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/InvalidMandatoryParameterErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestInvalidStreamIdentifierErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestInvalidStreamIdentifierErrorCause.cpp index d25ed32c2d..3acfdb71d7 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestInvalidStreamIdentifierErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestInvalidStreamIdentifierErrorCause.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/InvalidStreamIdentifierErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestMissingMandatoryParameterErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestMissingMandatoryParameterErrorCause.cpp index cb88789031..4f67d176a3 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestMissingMandatoryParameterErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestMissingMandatoryParameterErrorCause.cpp @@ -1,9 +1,9 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/errorCauses/MissingMandatoryParameterErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestNoUserDataErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestNoUserDataErrorCause.cpp index dfaae3f870..7357a10340 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestNoUserDataErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestNoUserDataErrorCause.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/NoUserDataErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestOutOfResourceErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestOutOfResourceErrorCause.cpp index 7eb11f1562..980f235eaf 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestOutOfResourceErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestOutOfResourceErrorCause.cpp @@ -1,7 +1,7 @@ #include "common.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/OutOfResourceErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestProtocolViolationErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestProtocolViolationErrorCause.cpp index cff1a54a23..00d0b692ab 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestProtocolViolationErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestProtocolViolationErrorCause.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/ProtocolViolationErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestRestartOfAnAssociationWithNewAddressesErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestRestartOfAnAssociationWithNewAddressesErrorCause.cpp index 1e922366f4..94deb226b1 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestRestartOfAnAssociationWithNewAddressesErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestRestartOfAnAssociationWithNewAddressesErrorCause.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/RestartOfAnAssociationWithNewAddressesErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestStaleCookieErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestStaleCookieErrorCause.cpp index e9fbf83cd1..00d9088f0e 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestStaleCookieErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestStaleCookieErrorCause.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/StaleCookieErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnknownErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnknownErrorCause.cpp index 643f1a608b..9285bc39ef 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnknownErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnknownErrorCause.cpp @@ -1,7 +1,7 @@ #include "common.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/UnknownErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnrecognizedChunkTypeErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnrecognizedChunkTypeErrorCause.cpp index 3040e0cba4..6f2007c33d 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnrecognizedChunkTypeErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnrecognizedChunkTypeErrorCause.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/UnrecognizedChunkTypeErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnrecognizedParametersErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnrecognizedParametersErrorCause.cpp index ed60f45f12..bc9fdd4ee0 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnrecognizedParametersErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnrecognizedParametersErrorCause.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/UnrecognizedParametersErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnresolvableAddressErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnresolvableAddressErrorCause.cpp index 34ac797f0a..03a6a56ab3 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnresolvableAddressErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestUnresolvableAddressErrorCause.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/UnresolvableAddressErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/errorCauses/TestUserInitiatedAbortErrorCause.cpp b/worker/test/src/RTC/SCTP/packet/errorCauses/TestUserInitiatedAbortErrorCause.cpp index 716537f24a..c87565d380 100644 --- a/worker/test/src/RTC/SCTP/packet/errorCauses/TestUserInitiatedAbortErrorCause.cpp +++ b/worker/test/src/RTC/SCTP/packet/errorCauses/TestUserInitiatedAbortErrorCause.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/ErrorCause.hpp" #include "RTC/SCTP/packet/errorCauses/UserInitiatedAbortErrorCause.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestAddIncomingStreamsRequestParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestAddIncomingStreamsRequestParameter.cpp index 1a38a5412e..0b70c968f2 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestAddIncomingStreamsRequestParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestAddIncomingStreamsRequestParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/AddIncomingStreamsRequestParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestAddOutgoingStreamsRequestParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestAddOutgoingStreamsRequestParameter.cpp index 050cac5dc3..7051454e39 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestAddOutgoingStreamsRequestParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestAddOutgoingStreamsRequestParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/AddOutgoingStreamsRequestParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestCookiePreservativeParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestCookiePreservativeParameter.cpp index de4590a23c..e184ca2c50 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestCookiePreservativeParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestCookiePreservativeParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/CookiePreservativeParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestForwardTsnSupportedParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestForwardTsnSupportedParameter.cpp index d9328910dc..a263d2aff4 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestForwardTsnSupportedParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestForwardTsnSupportedParameter.cpp @@ -1,7 +1,7 @@ #include "common.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/ForwardTsnSupportedParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestHeartbeatInfoParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestHeartbeatInfoParameter.cpp index f7971a1fb7..afd0232462 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestHeartbeatInfoParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestHeartbeatInfoParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/HeartbeatInfoParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestIPv4AddressParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestIPv4AddressParameter.cpp index bbca4e063b..d3ccc67bb4 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestIPv4AddressParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestIPv4AddressParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/IPv4AddressParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestIPv6AddressParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestIPv6AddressParameter.cpp index a7c88c24c0..0078460af6 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestIPv6AddressParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestIPv6AddressParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/IPv6AddressParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestIncomingSsnResetRequestParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestIncomingSsnResetRequestParameter.cpp index 17521cbc6e..78a14f54b5 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestIncomingSsnResetRequestParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestIncomingSsnResetRequestParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/IncomingSsnResetRequestParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() #include diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestOutgoingSsnResetRequestParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestOutgoingSsnResetRequestParameter.cpp index de37567584..8aae4a712a 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestOutgoingSsnResetRequestParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestOutgoingSsnResetRequestParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/OutgoingSsnResetRequestParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() #include diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestReconfigurationResponseParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestReconfigurationResponseParameter.cpp index cd589c0bb5..8aaab240af 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestReconfigurationResponseParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestReconfigurationResponseParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/ReconfigurationResponseParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestSsnTsnResetRequestParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestSsnTsnResetRequestParameter.cpp index 6c6dda67ef..2abf76d4e8 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestSsnTsnResetRequestParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestSsnTsnResetRequestParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/SsnTsnResetRequestParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestStateCookieParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestStateCookieParameter.cpp index 4848b05e54..a141a4e9bb 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestStateCookieParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestStateCookieParameter.cpp @@ -1,10 +1,10 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/association/NegotiatedCapabilities.hpp" #include "RTC/SCTP/association/StateCookie.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/StateCookieParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestSupportedAddressTypesParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestSupportedAddressTypesParameter.cpp index dedaa52521..f48f8c6bec 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestSupportedAddressTypesParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestSupportedAddressTypesParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/SupportedAddressTypesParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestSupportedExtensionsParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestSupportedExtensionsParameter.cpp index 0a6cd5ffcd..2f6ec47f0d 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestSupportedExtensionsParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestSupportedExtensionsParameter.cpp @@ -1,9 +1,9 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" // in worker/test/include/ #include "RTC/SCTP/packet/Chunk.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/SupportedExtensionsParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" // in worker/test/include/ #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestUnknownParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestUnknownParameter.cpp index fed217dfdf..dce497aa34 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestUnknownParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestUnknownParameter.cpp @@ -1,7 +1,7 @@ #include "common.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/UnknownParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestUnrecognizedParameterParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestUnrecognizedParameterParameter.cpp index 2448501c4f..c1332a7196 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestUnrecognizedParameterParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestUnrecognizedParameterParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/UnrecognizedParameterParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/packet/parameters/TestZeroChecksumAcceptableParameter.cpp b/worker/test/src/RTC/SCTP/packet/parameters/TestZeroChecksumAcceptableParameter.cpp index 2cb3a843e8..7ba0e772be 100644 --- a/worker/test/src/RTC/SCTP/packet/parameters/TestZeroChecksumAcceptableParameter.cpp +++ b/worker/test/src/RTC/SCTP/packet/parameters/TestZeroChecksumAcceptableParameter.cpp @@ -1,8 +1,8 @@ #include "common.hpp" #include "MediaSoupErrors.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/Parameter.hpp" #include "RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include // std::memset() diff --git a/worker/test/src/RTC/SCTP/rx/TestDataTracker.cpp b/worker/test/src/RTC/SCTP/rx/TestDataTracker.cpp index 42b15ac263..f87056d474 100644 --- a/worker/test/src/RTC/SCTP/rx/TestDataTracker.cpp +++ b/worker/test/src/RTC/SCTP/rx/TestDataTracker.cpp @@ -1,9 +1,9 @@ -#include "mocks/include/MockShared.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" +#include "handles/BackoffTimerHandleInterface.hpp" #include "RTC/SCTP/packet/Packet.hpp" #include "RTC/SCTP/packet/chunks/SackChunk.hpp" #include "RTC/SCTP/rx/DataTracker.hpp" -#include "handles/BackoffTimerHandleInterface.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" +#include "mocks/include/MockShared.hpp" #include #include #include diff --git a/worker/test/src/RTC/SCTP/tx/TestOutstandingData.cpp b/worker/test/src/RTC/SCTP/tx/TestOutstandingData.cpp index 84b929e5fb..e98e1723de 100644 --- a/worker/test/src/RTC/SCTP/tx/TestOutstandingData.cpp +++ b/worker/test/src/RTC/SCTP/tx/TestOutstandingData.cpp @@ -1,12 +1,12 @@ #include "common.hpp" -#include "Utils.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" #include "RTC/SCTP/packet/UserData.hpp" #include "RTC/SCTP/packet/chunks/DataChunk.hpp" #include "RTC/SCTP/packet/chunks/ForwardTsnChunk.hpp" #include "RTC/SCTP/packet/chunks/SackChunk.hpp" #include "RTC/SCTP/public/SctpTypes.hpp" #include "RTC/SCTP/tx/OutstandingData.hpp" +#include "Utils.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" #include #include #include diff --git a/worker/test/src/RTC/SCTP/tx/TestRetransmissionQueue.cpp b/worker/test/src/RTC/SCTP/tx/TestRetransmissionQueue.cpp index 6cb115d0e7..e926732a5a 100644 --- a/worker/test/src/RTC/SCTP/tx/TestRetransmissionQueue.cpp +++ b/worker/test/src/RTC/SCTP/tx/TestRetransmissionQueue.cpp @@ -1,10 +1,5 @@ #include "common.hpp" -#include "Utils.hpp" -#include "mocks/include/MockShared.hpp" -#include "mocks/include/RTC/SCTP/association/MockAssociationListener.hpp" -#include "mocks/include/RTC/SCTP/tx/MockSendQueue.hpp" -#include "test/include/RTC/SCTP/sctpCommon.hpp" -#include "test/include/catch2Macros.hpp" +#include "handles/BackoffTimerHandleInterface.hpp" #include "RTC/SCTP/packet/Packet.hpp" #include "RTC/SCTP/packet/UserData.hpp" #include "RTC/SCTP/packet/chunks/AnyForwardTsnChunk.hpp" @@ -13,7 +8,12 @@ #include "RTC/SCTP/public/SctpOptions.hpp" #include "RTC/SCTP/tx/RetransmissionQueue.hpp" #include "RTC/SCTP/tx/SendQueueInterface.hpp" -#include "handles/BackoffTimerHandleInterface.hpp" +#include "Utils.hpp" +#include "test/include/RTC/SCTP/sctpCommon.hpp" +#include "test/include/catch2Macros.hpp" +#include "mocks/include/MockShared.hpp" +#include "mocks/include/RTC/SCTP/association/MockAssociationListener.hpp" +#include "mocks/include/RTC/SCTP/tx/MockSendQueue.hpp" #include #include diff --git a/worker/test/src/RTC/SCTP/tx/TestRoundRobinSendQueue.cpp b/worker/test/src/RTC/SCTP/tx/TestRoundRobinSendQueue.cpp index ec17429fa6..8849ac3a89 100644 --- a/worker/test/src/RTC/SCTP/tx/TestRoundRobinSendQueue.cpp +++ b/worker/test/src/RTC/SCTP/tx/TestRoundRobinSendQueue.cpp @@ -1,8 +1,8 @@ #include "common.hpp" -#include "mocks/include/RTC/SCTP/association/MockAssociationListener.hpp" #include "RTC/SCTP/public/Message.hpp" #include "RTC/SCTP/public/SctpOptions.hpp" #include "RTC/SCTP/tx/RoundRobinSendQueue.hpp" +#include "mocks/include/RTC/SCTP/association/MockAssociationListener.hpp" #include #include #include diff --git a/worker/test/src/RTC/TestKeyFrameRequestManager.cpp b/worker/test/src/RTC/TestKeyFrameRequestManager.cpp index 693beb3f8e..aa4bba9c12 100644 --- a/worker/test/src/RTC/TestKeyFrameRequestManager.cpp +++ b/worker/test/src/RTC/TestKeyFrameRequestManager.cpp @@ -1,6 +1,6 @@ #include "common.hpp" -#include "mocks/include/MockShared.hpp" #include "RTC/KeyFrameRequestManager.hpp" +#include "mocks/include/MockShared.hpp" #include SCENARIO("KeyFrameRequestManager", "[rtp][keyframe]") diff --git a/worker/test/src/RTC/TestNackGenerator.cpp b/worker/test/src/RTC/TestNackGenerator.cpp index 6000e475e8..4fad4fcb78 100644 --- a/worker/test/src/RTC/TestNackGenerator.cpp +++ b/worker/test/src/RTC/TestNackGenerator.cpp @@ -1,9 +1,9 @@ #include "common.hpp" -#include "mocks/include/MockShared.hpp" -#include "test/include/RTC/RTP/rtpCommon.hpp" #include "RTC/NackGenerator.hpp" #include "RTC/RTP/Codecs/PayloadDescriptorHandler.hpp" #include "RTC/RTP/Packet.hpp" +#include "test/include/RTC/RTP/rtpCommon.hpp" +#include "mocks/include/MockShared.hpp" #include #include diff --git a/worker/test/src/RTC/TestSimpleConsumer.cpp b/worker/test/src/RTC/TestSimpleConsumer.cpp index 318989a6ae..44020045b5 100644 --- a/worker/test/src/RTC/TestSimpleConsumer.cpp +++ b/worker/test/src/RTC/TestSimpleConsumer.cpp @@ -1,5 +1,3 @@ -#include "flatbuffers/buffer.h" -#include "mocks/include/MockShared.hpp" #include "FBS/rtpParameters.h" #include "FBS/transport.h" #include "RTC/RTP/Packet.hpp" @@ -8,6 +6,8 @@ #include "RTC/RTP/SharedPacket.hpp" #include "RTC/RtpDictionaries.hpp" #include "RTC/SimpleConsumer.hpp" +#include "flatbuffers/buffer.h" +#include "mocks/include/MockShared.hpp" #include namespace diff --git a/worker/test/src/RTC/TestTransportCongestionControlServer.cpp b/worker/test/src/RTC/TestTransportCongestionControlServer.cpp index 368ec36d58..f0b6fd8c47 100644 --- a/worker/test/src/RTC/TestTransportCongestionControlServer.cpp +++ b/worker/test/src/RTC/TestTransportCongestionControlServer.cpp @@ -1,9 +1,9 @@ #include "common.hpp" -#include "mocks/include/MockShared.hpp" #include "RTC/Consts.hpp" #include "RTC/RTP/HeaderExtensionIds.hpp" #include "RTC/RTP/Packet.hpp" #include "RTC/TransportCongestionControlServer.hpp" +#include "mocks/include/MockShared.hpp" #include #include #include diff --git a/worker/test/src/tests.cpp b/worker/test/src/tests.cpp index 10832d2d64..721e99c13b 100644 --- a/worker/test/src/tests.cpp +++ b/worker/test/src/tests.cpp @@ -3,8 +3,6 @@ #include "DepLibUV.hpp" #include "DepLibWebRTC.hpp" #include "DepOpenSSL.hpp" -// TODO: Remove once we only use built-in SCTP stack. -#include "DepUsrSCTP.hpp" #include "Settings.hpp" #include "Utils.hpp" #include @@ -48,11 +46,6 @@ int main(int argc, char* argv[]) DepLibUV::ClassInit(); DepOpenSSL::ClassInit(); DepLibSRTP::ClassInit(); - // TODO: Remove once we only use built-in SCTP stack. - if (!Settings::configuration.useBuiltInSctpStack) - { - DepUsrSCTP::ClassInit(); - } DepLibWebRTC::ClassInit(); Utils::Crypto::ClassInit(); @@ -64,11 +57,6 @@ int main(int argc, char* argv[]) DepLibSRTP::ClassDestroy(); Utils::Crypto::ClassDestroy(); DepLibWebRTC::ClassDestroy(); - // TODO: Remove once we only use built-in SCTP stack. - if (!Settings::configuration.useBuiltInSctpStack) - { - DepUsrSCTP::ClassDestroy(); - } DepLibUV::ClassDestroy(); return status;