@stream-io/video-client 0.7.7 → 0.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -225,6 +225,18 @@ export declare class Call {
225
225
  * @param stopTrack if `true` the track will be stopped, else it will be just disabled
226
226
  */
227
227
  stopPublish: (trackType: TrackType, stopTrack?: boolean) => Promise<void>;
228
+ /**
229
+ * Notifies the SFU that a noise cancellation process has started.
230
+ *
231
+ * @internal
232
+ */
233
+ notifyNoiseCancellationStarting: () => Promise<void | import("@protobuf-ts/runtime-rpc").FinishedUnaryCall<import("./gen/video/sfu/signal_rpc/signal").StartNoiseCancellationRequest, import("./gen/video/sfu/signal_rpc/signal").StartNoiseCancellationResponse> | undefined>;
234
+ /**
235
+ * Notifies the SFU that a noise cancellation process has stopped.
236
+ *
237
+ * @internal
238
+ */
239
+ notifyNoiseCancellationStopped: () => Promise<void | import("@protobuf-ts/runtime-rpc").FinishedUnaryCall<import("./gen/video/sfu/signal_rpc/signal").StopNoiseCancellationRequest, import("./gen/video/sfu/signal_rpc/signal").StopNoiseCancellationResponse> | undefined>;
228
240
  /**
229
241
  * Update track subscription configuration for one or more participants.
230
242
  * You have to create a subscription for each participant for all the different kinds of tracks you want to receive.
@@ -109,6 +109,8 @@ export declare class StreamSfuClient {
109
109
  updateMuteState: (trackType: TrackType, muted: boolean) => Promise<FinishedUnaryCall<UpdateMuteStatesRequest, import("./gen/video/sfu/signal_rpc/signal").UpdateMuteStatesResponse>>;
110
110
  updateMuteStates: (data: Omit<UpdateMuteStatesRequest, 'sessionId'>) => Promise<FinishedUnaryCall<UpdateMuteStatesRequest, import("./gen/video/sfu/signal_rpc/signal").UpdateMuteStatesResponse>>;
111
111
  sendStats: (stats: Omit<SendStatsRequest, 'sessionId'>) => Promise<FinishedUnaryCall<SendStatsRequest, import("./gen/video/sfu/signal_rpc/signal").SendStatsResponse>>;
112
+ startNoiseCancellation: () => Promise<FinishedUnaryCall<import("./gen/video/sfu/signal_rpc/signal").StartNoiseCancellationRequest, import("./gen/video/sfu/signal_rpc/signal").StartNoiseCancellationResponse>>;
113
+ stopNoiseCancellation: () => Promise<FinishedUnaryCall<import("./gen/video/sfu/signal_rpc/signal").StopNoiseCancellationRequest, import("./gen/video/sfu/signal_rpc/signal").StopNoiseCancellationResponse>>;
112
114
  join: (data: Omit<JoinRequest, 'sessionId' | 'token'>) => Promise<void>;
113
115
  send: (message: SfuRequest) => Promise<void>;
114
116
  private keepAlive;
@@ -21,7 +21,7 @@ export declare abstract class InputMediaDeviceManager<T extends InputMediaDevice
21
21
  */
22
22
  stopOnLeave: boolean;
23
23
  logger: Logger;
24
- private subscriptions;
24
+ protected subscriptions: Function[];
25
25
  private isTrackStoppedDueToTrackEnd;
26
26
  private filters;
27
27
  protected constructor(call: Call, state: T, trackType: TrackType);
@@ -1,11 +1,28 @@
1
1
  import { Observable } from 'rxjs';
2
+ import type { INoiseCancellation } from '@stream-io/audio-filters-web';
2
3
  import { Call } from '../Call';
3
4
  import { InputMediaDeviceManager } from './InputMediaDeviceManager';
4
5
  import { MicrophoneManagerState } from './MicrophoneManagerState';
5
6
  export declare class MicrophoneManager extends InputMediaDeviceManager<MicrophoneManagerState> {
6
7
  private soundDetectorCleanup?;
7
8
  private rnSpeechDetector;
9
+ private noiseCancellation;
10
+ private noiseCancellationChangeUnsubscribe;
11
+ private noiseCancellationRegistration?;
8
12
  constructor(call: Call);
13
+ /**
14
+ * Enables noise cancellation for the microphone.
15
+ *
16
+ * Note: not supported in React Native.
17
+ * @param noiseCancellation - a noise cancellation instance to use.
18
+ */
19
+ enableNoiseCancellation(noiseCancellation: INoiseCancellation): Promise<void>;
20
+ /**
21
+ * Disables noise cancellation for the microphone.
22
+ *
23
+ * Note: not supported in React Native.
24
+ */
25
+ disableNoiseCancellation(): Promise<void>;
9
26
  protected getDevices(): Observable<MediaDeviceInfo[]>;
10
27
  protected getStream(constraints: MediaTrackConstraints): Promise<MediaStream>;
11
28
  protected publishStream(stream: MediaStream): Promise<void>;
@@ -86,6 +86,12 @@ export interface AudioSettings {
86
86
  * @memberof AudioSettings
87
87
  */
88
88
  mic_default_on: boolean;
89
+ /**
90
+ *
91
+ * @type {NoiseCancellationSettings}
92
+ * @memberof AudioSettings
93
+ */
94
+ noise_cancellation?: NoiseCancellationSettings;
89
95
  /**
90
96
  *
91
97
  * @type {boolean}
@@ -137,6 +143,12 @@ export interface AudioSettingsRequest {
137
143
  * @memberof AudioSettingsRequest
138
144
  */
139
145
  mic_default_on?: boolean;
146
+ /**
147
+ *
148
+ * @type {NoiseCancellationSettingsRequest}
149
+ * @memberof AudioSettingsRequest
150
+ */
151
+ noise_cancellation?: NoiseCancellationSettingsRequest;
140
152
  /**
141
153
  *
142
154
  * @type {boolean}
@@ -467,7 +479,6 @@ export interface CallEndedEvent {
467
479
  user?: UserResponse;
468
480
  }
469
481
  /**
470
- *
471
482
  * @export
472
483
  * @interface CallEvent
473
484
  */
@@ -2113,7 +2124,7 @@ export interface ClosedCaptionEvent {
2113
2124
  export interface CollectUserFeedbackRequest {
2114
2125
  /**
2115
2126
  *
2116
- * @type {object}
2127
+ * @type {{ [key:string]: any }}
2117
2128
  * @memberof CollectUserFeedbackRequest
2118
2129
  */
2119
2130
  custom?: {
@@ -3373,6 +3384,50 @@ export interface MuteUsersResponse {
3373
3384
  */
3374
3385
  duration: string;
3375
3386
  }
3387
+ /**
3388
+ *
3389
+ * @export
3390
+ * @interface NoiseCancellationSettings
3391
+ */
3392
+ export interface NoiseCancellationSettings {
3393
+ /**
3394
+ *
3395
+ * @type {string}
3396
+ * @memberof NoiseCancellationSettings
3397
+ */
3398
+ mode: NoiseCancellationSettingsModeEnum;
3399
+ }
3400
+ /**
3401
+ * @export
3402
+ */
3403
+ export declare const NoiseCancellationSettingsModeEnum: {
3404
+ readonly AVAILABLE: "available";
3405
+ readonly DISABLED: "disabled";
3406
+ readonly AUTO_ON: "auto-on";
3407
+ };
3408
+ export type NoiseCancellationSettingsModeEnum = (typeof NoiseCancellationSettingsModeEnum)[keyof typeof NoiseCancellationSettingsModeEnum];
3409
+ /**
3410
+ *
3411
+ * @export
3412
+ * @interface NoiseCancellationSettingsRequest
3413
+ */
3414
+ export interface NoiseCancellationSettingsRequest {
3415
+ /**
3416
+ *
3417
+ * @type {string}
3418
+ * @memberof NoiseCancellationSettingsRequest
3419
+ */
3420
+ mode?: NoiseCancellationSettingsRequestModeEnum;
3421
+ }
3422
+ /**
3423
+ * @export
3424
+ */
3425
+ export declare const NoiseCancellationSettingsRequestModeEnum: {
3426
+ readonly AVAILABLE: "available";
3427
+ readonly DISABLED: "disabled";
3428
+ readonly AUTO_ON: "auto-on";
3429
+ };
3430
+ export type NoiseCancellationSettingsRequestModeEnum = (typeof NoiseCancellationSettingsRequestModeEnum)[keyof typeof NoiseCancellationSettingsRequestModeEnum];
3376
3431
  /**
3377
3432
  * All possibility of string to use
3378
3433
  * @export
@@ -3381,6 +3436,7 @@ export declare const OwnCapability: {
3381
3436
  readonly BLOCK_USERS: "block-users";
3382
3437
  readonly CREATE_CALL: "create-call";
3383
3438
  readonly CREATE_REACTION: "create-reaction";
3439
+ readonly ENABLE_NOISE_CANCELLATION: "enable-noise-cancellation";
3384
3440
  readonly END_CALL: "end-call";
3385
3441
  readonly JOIN_BACKSTAGE: "join-backstage";
3386
3442
  readonly JOIN_CALL: "join-call";
@@ -5139,6 +5195,44 @@ export interface UserStats {
5139
5195
  */
5140
5196
  session_stats: Array<UserSessionStats>;
5141
5197
  }
5198
+ /**
5199
+ *
5200
+ * @export
5201
+ * @interface VideoQuality
5202
+ */
5203
+ export interface VideoQuality {
5204
+ /**
5205
+ *
5206
+ * @type {VideoResolution}
5207
+ * @memberof VideoQuality
5208
+ */
5209
+ resolution?: VideoResolution;
5210
+ /**
5211
+ *
5212
+ * @type {string}
5213
+ * @memberof VideoQuality
5214
+ */
5215
+ usage_type?: string;
5216
+ }
5217
+ /**
5218
+ *
5219
+ * @export
5220
+ * @interface VideoResolution
5221
+ */
5222
+ export interface VideoResolution {
5223
+ /**
5224
+ *
5225
+ * @type {number}
5226
+ * @memberof VideoResolution
5227
+ */
5228
+ height: number;
5229
+ /**
5230
+ *
5231
+ * @type {number}
5232
+ * @memberof VideoResolution
5233
+ */
5234
+ width: number;
5235
+ }
5142
5236
  /**
5143
5237
  *
5144
5238
  * @export
@@ -5231,38 +5325,6 @@ export declare const VideoSettingsRequestCameraFacingEnum: {
5231
5325
  readonly EXTERNAL: "external";
5232
5326
  };
5233
5327
  export type VideoSettingsRequestCameraFacingEnum = (typeof VideoSettingsRequestCameraFacingEnum)[keyof typeof VideoSettingsRequestCameraFacingEnum];
5234
- /**
5235
- *
5236
- * @export
5237
- * @interface VideoQuality
5238
- */
5239
- export interface VideoQuality {
5240
- /**
5241
- *
5242
- * @type {VideoResolution}
5243
- * @memberof VideoQuality
5244
- */
5245
- resolution: VideoResolution;
5246
- }
5247
- /**
5248
- *
5249
- * @export
5250
- * @interface VideoResolution
5251
- */
5252
- export interface VideoResolution {
5253
- /**
5254
- *
5255
- * @type {number}
5256
- * @memberof VideoResolution
5257
- */
5258
- height: number;
5259
- /**
5260
- *
5261
- * @type {number}
5262
- * @memberof VideoResolution
5263
- */
5264
- width: number;
5265
- }
5266
5328
  /**
5267
5329
  *
5268
5330
  * @export
@@ -1,5 +1,5 @@
1
1
  import type { RpcOptions, RpcTransport, ServiceInfo, UnaryCall } from '@protobuf-ts/runtime-rpc';
2
- import type { ICERestartRequest, ICERestartResponse, ICETrickleResponse, SendAnswerRequest, SendAnswerResponse, SendStatsRequest, SendStatsResponse, SetPublisherRequest, SetPublisherResponse, UpdateMuteStatesRequest, UpdateMuteStatesResponse, UpdateSubscriptionsRequest, UpdateSubscriptionsResponse } from './signal';
2
+ import type { ICERestartRequest, ICERestartResponse, ICETrickleResponse, SendAnswerRequest, SendAnswerResponse, SendStatsRequest, SendStatsResponse, SetPublisherRequest, SetPublisherResponse, StartNoiseCancellationRequest, StartNoiseCancellationResponse, StopNoiseCancellationRequest, StopNoiseCancellationResponse, UpdateMuteStatesRequest, UpdateMuteStatesResponse, UpdateSubscriptionsRequest, UpdateSubscriptionsResponse } from './signal';
3
3
  import type { ICETrickle } from '../models/models';
4
4
  /**
5
5
  * @generated from protobuf service stream.video.sfu.signal.SignalServer
@@ -42,6 +42,14 @@ export interface ISignalServerClient {
42
42
  * @generated from protobuf rpc: SendStats(stream.video.sfu.signal.SendStatsRequest) returns (stream.video.sfu.signal.SendStatsResponse);
43
43
  */
44
44
  sendStats(input: SendStatsRequest, options?: RpcOptions): UnaryCall<SendStatsRequest, SendStatsResponse>;
45
+ /**
46
+ * @generated from protobuf rpc: StartNoiseCancellation(stream.video.sfu.signal.StartNoiseCancellationRequest) returns (stream.video.sfu.signal.StartNoiseCancellationResponse);
47
+ */
48
+ startNoiseCancellation(input: StartNoiseCancellationRequest, options?: RpcOptions): UnaryCall<StartNoiseCancellationRequest, StartNoiseCancellationResponse>;
49
+ /**
50
+ * @generated from protobuf rpc: StopNoiseCancellation(stream.video.sfu.signal.StopNoiseCancellationRequest) returns (stream.video.sfu.signal.StopNoiseCancellationResponse);
51
+ */
52
+ stopNoiseCancellation(input: StopNoiseCancellationRequest, options?: RpcOptions): UnaryCall<StopNoiseCancellationRequest, StopNoiseCancellationResponse>;
45
53
  }
46
54
  /**
47
55
  * @generated from protobuf service stream.video.sfu.signal.SignalServer
@@ -91,4 +99,12 @@ export declare class SignalServerClient implements ISignalServerClient, ServiceI
91
99
  * @generated from protobuf rpc: SendStats(stream.video.sfu.signal.SendStatsRequest) returns (stream.video.sfu.signal.SendStatsResponse);
92
100
  */
93
101
  sendStats(input: SendStatsRequest, options?: RpcOptions): UnaryCall<SendStatsRequest, SendStatsResponse>;
102
+ /**
103
+ * @generated from protobuf rpc: StartNoiseCancellation(stream.video.sfu.signal.StartNoiseCancellationRequest) returns (stream.video.sfu.signal.StartNoiseCancellationResponse);
104
+ */
105
+ startNoiseCancellation(input: StartNoiseCancellationRequest, options?: RpcOptions): UnaryCall<StartNoiseCancellationRequest, StartNoiseCancellationResponse>;
106
+ /**
107
+ * @generated from protobuf rpc: StopNoiseCancellation(stream.video.sfu.signal.StopNoiseCancellationRequest) returns (stream.video.sfu.signal.StopNoiseCancellationResponse);
108
+ */
109
+ stopNoiseCancellation(input: StopNoiseCancellationRequest, options?: RpcOptions): UnaryCall<StopNoiseCancellationRequest, StopNoiseCancellationResponse>;
94
110
  }
@@ -2,6 +2,42 @@ import { Error, PeerType, TrackInfo, TrackType, VideoDimension } from '../models
2
2
  import { ServiceType } from '@protobuf-ts/runtime-rpc';
3
3
  import type { BinaryReadOptions, BinaryWriteOptions, IBinaryReader, IBinaryWriter, PartialMessage } from '@protobuf-ts/runtime';
4
4
  import { MessageType } from '@protobuf-ts/runtime';
5
+ /**
6
+ * @generated from protobuf message stream.video.sfu.signal.StartNoiseCancellationRequest
7
+ */
8
+ export interface StartNoiseCancellationRequest {
9
+ /**
10
+ * @generated from protobuf field: string session_id = 1;
11
+ */
12
+ sessionId: string;
13
+ }
14
+ /**
15
+ * @generated from protobuf message stream.video.sfu.signal.StartNoiseCancellationResponse
16
+ */
17
+ export interface StartNoiseCancellationResponse {
18
+ /**
19
+ * @generated from protobuf field: stream.video.sfu.models.Error error = 1;
20
+ */
21
+ error?: Error;
22
+ }
23
+ /**
24
+ * @generated from protobuf message stream.video.sfu.signal.StopNoiseCancellationRequest
25
+ */
26
+ export interface StopNoiseCancellationRequest {
27
+ /**
28
+ * @generated from protobuf field: string session_id = 1;
29
+ */
30
+ sessionId: string;
31
+ }
32
+ /**
33
+ * @generated from protobuf message stream.video.sfu.signal.StopNoiseCancellationResponse
34
+ */
35
+ export interface StopNoiseCancellationResponse {
36
+ /**
37
+ * @generated from protobuf field: stream.video.sfu.models.Error error = 1;
38
+ */
39
+ error?: Error;
40
+ }
5
41
  /**
6
42
  * @generated from protobuf message stream.video.sfu.signal.SendStatsRequest
7
43
  */
@@ -235,6 +271,46 @@ export interface SetPublisherResponse {
235
271
  */
236
272
  error?: Error;
237
273
  }
274
+ declare class StartNoiseCancellationRequest$Type extends MessageType<StartNoiseCancellationRequest> {
275
+ constructor();
276
+ create(value?: PartialMessage<StartNoiseCancellationRequest>): StartNoiseCancellationRequest;
277
+ internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: StartNoiseCancellationRequest): StartNoiseCancellationRequest;
278
+ internalBinaryWrite(message: StartNoiseCancellationRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter;
279
+ }
280
+ /**
281
+ * @generated MessageType for protobuf message stream.video.sfu.signal.StartNoiseCancellationRequest
282
+ */
283
+ export declare const StartNoiseCancellationRequest: StartNoiseCancellationRequest$Type;
284
+ declare class StartNoiseCancellationResponse$Type extends MessageType<StartNoiseCancellationResponse> {
285
+ constructor();
286
+ create(value?: PartialMessage<StartNoiseCancellationResponse>): StartNoiseCancellationResponse;
287
+ internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: StartNoiseCancellationResponse): StartNoiseCancellationResponse;
288
+ internalBinaryWrite(message: StartNoiseCancellationResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter;
289
+ }
290
+ /**
291
+ * @generated MessageType for protobuf message stream.video.sfu.signal.StartNoiseCancellationResponse
292
+ */
293
+ export declare const StartNoiseCancellationResponse: StartNoiseCancellationResponse$Type;
294
+ declare class StopNoiseCancellationRequest$Type extends MessageType<StopNoiseCancellationRequest> {
295
+ constructor();
296
+ create(value?: PartialMessage<StopNoiseCancellationRequest>): StopNoiseCancellationRequest;
297
+ internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: StopNoiseCancellationRequest): StopNoiseCancellationRequest;
298
+ internalBinaryWrite(message: StopNoiseCancellationRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter;
299
+ }
300
+ /**
301
+ * @generated MessageType for protobuf message stream.video.sfu.signal.StopNoiseCancellationRequest
302
+ */
303
+ export declare const StopNoiseCancellationRequest: StopNoiseCancellationRequest$Type;
304
+ declare class StopNoiseCancellationResponse$Type extends MessageType<StopNoiseCancellationResponse> {
305
+ constructor();
306
+ create(value?: PartialMessage<StopNoiseCancellationResponse>): StopNoiseCancellationResponse;
307
+ internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: StopNoiseCancellationResponse): StopNoiseCancellationResponse;
308
+ internalBinaryWrite(message: StopNoiseCancellationResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter;
309
+ }
310
+ /**
311
+ * @generated MessageType for protobuf message stream.video.sfu.signal.StopNoiseCancellationResponse
312
+ */
313
+ export declare const StopNoiseCancellationResponse: StopNoiseCancellationResponse$Type;
238
314
  declare class SendStatsRequest$Type extends MessageType<SendStatsRequest> {
239
315
  constructor();
240
316
  create(value?: PartialMessage<SendStatsRequest>): SendStatsRequest;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-client",
3
- "version": "0.7.7",
3
+ "version": "0.7.8",
4
4
  "packageManager": "yarn@3.2.4",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.es.js",
@@ -28,9 +28,9 @@
28
28
  "CHANGELOG.md"
29
29
  ],
30
30
  "dependencies": {
31
- "@protobuf-ts/runtime": "^2.9.3",
32
- "@protobuf-ts/runtime-rpc": "^2.9.3",
33
- "@protobuf-ts/twirp-transport": "^2.9.3",
31
+ "@protobuf-ts/runtime": "^2.9.4",
32
+ "@protobuf-ts/runtime-rpc": "^2.9.4",
33
+ "@protobuf-ts/twirp-transport": "^2.9.4",
34
34
  "@types/ws": "^8.5.7",
35
35
  "axios": "^1.6.0",
36
36
  "base64-js": "^1.5.1",
@@ -42,9 +42,10 @@
42
42
  "ws": "^8.14.2"
43
43
  },
44
44
  "devDependencies": {
45
- "@openapitools/openapi-generator-cli": "^2.7.0",
45
+ "@openapitools/openapi-generator-cli": "^2.13.4",
46
46
  "@rollup/plugin-replace": "^5.0.5",
47
47
  "@rollup/plugin-typescript": "^11.1.6",
48
+ "@stream-io/audio-filters-web": "workspace:^",
48
49
  "@stream-io/node-sdk": "^0.1.12",
49
50
  "@types/sdp-transform": "^2.4.7",
50
51
  "@types/ua-parser-js": "^0.7.37",
package/src/Call.ts CHANGED
@@ -1308,6 +1308,28 @@ export class Call {
1308
1308
  await this.publisher?.unpublishStream(trackType, stopTrack);
1309
1309
  };
1310
1310
 
1311
+ /**
1312
+ * Notifies the SFU that a noise cancellation process has started.
1313
+ *
1314
+ * @internal
1315
+ */
1316
+ notifyNoiseCancellationStarting = async () => {
1317
+ return this.sfuClient?.startNoiseCancellation().catch((err) => {
1318
+ this.logger('warn', 'Failed to notify start of noise cancellation', err);
1319
+ });
1320
+ };
1321
+
1322
+ /**
1323
+ * Notifies the SFU that a noise cancellation process has stopped.
1324
+ *
1325
+ * @internal
1326
+ */
1327
+ notifyNoiseCancellationStopped = async () => {
1328
+ return this.sfuClient?.stopNoiseCancellation().catch((err) => {
1329
+ this.logger('warn', 'Failed to notify stop of noise cancellation', err);
1330
+ });
1331
+ };
1332
+
1311
1333
  /**
1312
1334
  * Update track subscription configuration for one or more participants.
1313
1335
  * You have to create a subscription for each participant for all the different kinds of tracks you want to receive.
@@ -310,6 +310,26 @@ export class StreamSfuClient {
310
310
  );
311
311
  };
312
312
 
313
+ startNoiseCancellation = async () => {
314
+ return retryable(
315
+ () =>
316
+ this.rpc.startNoiseCancellation({
317
+ sessionId: this.sessionId,
318
+ }),
319
+ this.logger,
320
+ );
321
+ };
322
+
323
+ stopNoiseCancellation = async () => {
324
+ return retryable(
325
+ () =>
326
+ this.rpc.stopNoiseCancellation({
327
+ sessionId: this.sessionId,
328
+ }),
329
+ this.logger,
330
+ );
331
+ };
332
+
313
333
  join = async (data: Omit<JoinRequest, 'sessionId' | 'token'>) => {
314
334
  const joinRequest = JoinRequest.create({
315
335
  ...data,
@@ -28,7 +28,8 @@ export abstract class InputMediaDeviceManager<
28
28
  */
29
29
  stopOnLeave = true;
30
30
  logger: Logger;
31
- private subscriptions: Function[] = [];
31
+
32
+ protected subscriptions: Function[] = [];
32
33
  private isTrackStoppedDueToTrackEnd = false;
33
34
  private filters: MediaStreamFilter[] = [];
34
35
 
@@ -1,4 +1,5 @@
1
1
  import { combineLatest, Observable } from 'rxjs';
2
+ import type { INoiseCancellation } from '@stream-io/audio-filters-web';
2
3
  import { Call } from '../Call';
3
4
  import { InputMediaDeviceManager } from './InputMediaDeviceManager';
4
5
  import { MicrophoneManagerState } from './MicrophoneManagerState';
@@ -6,13 +7,20 @@ import { getAudioDevices, getAudioStream } from './devices';
6
7
  import { TrackType } from '../gen/video/sfu/models/models';
7
8
  import { createSoundDetector } from '../helpers/sound-detector';
8
9
  import { isReactNative } from '../helpers/platforms';
9
- import { OwnCapability } from '../gen/coordinator';
10
+ import {
11
+ NoiseCancellationSettingsModeEnum,
12
+ OwnCapability,
13
+ } from '../gen/coordinator';
10
14
  import { CallingState } from '../store';
15
+ import { createSubscription } from '../store/rxUtils';
11
16
  import { RNSpeechDetector } from '../helpers/RNSpeechDetector';
12
17
 
13
18
  export class MicrophoneManager extends InputMediaDeviceManager<MicrophoneManagerState> {
14
19
  private soundDetectorCleanup?: Function;
15
20
  private rnSpeechDetector: RNSpeechDetector | undefined;
21
+ private noiseCancellation: INoiseCancellation | undefined;
22
+ private noiseCancellationChangeUnsubscribe: (() => void) | undefined;
23
+ private noiseCancellationRegistration?: Promise<() => Promise<void>>;
16
24
 
17
25
  constructor(call: Call) {
18
26
  super(call, new MicrophoneManagerState(), TrackType.AUDIO);
@@ -39,6 +47,120 @@ export class MicrophoneManager extends InputMediaDeviceManager<MicrophoneManager
39
47
  await this.stopSpeakingWhileMutedDetection();
40
48
  }
41
49
  });
50
+
51
+ this.subscriptions.push(
52
+ createSubscription(this.call.state.callingState$, (callingState) => {
53
+ // do nothing when noise filtering isn't turned on
54
+ if (!this.noiseCancellationRegistration || !this.noiseCancellation)
55
+ return;
56
+
57
+ const autoOn =
58
+ this.call.state.settings?.audio.noise_cancellation?.mode ===
59
+ NoiseCancellationSettingsModeEnum.AUTO_ON;
60
+
61
+ if (autoOn && callingState === CallingState.JOINED) {
62
+ this.noiseCancellationRegistration
63
+ .then(() => this.noiseCancellation?.enable())
64
+ .catch((err) => {
65
+ this.logger('warn', `Failed to enable noise cancellation`, err);
66
+ return this.call.notifyNoiseCancellationStopped();
67
+ });
68
+ } else if (callingState === CallingState.LEFT) {
69
+ this.noiseCancellationRegistration
70
+ .then(() => this.noiseCancellation?.disable())
71
+ .catch((err) => {
72
+ this.logger('warn', `Failed to disable noise cancellation`, err);
73
+ });
74
+ }
75
+ }),
76
+ );
77
+ }
78
+
79
+ /**
80
+ * Enables noise cancellation for the microphone.
81
+ *
82
+ * Note: not supported in React Native.
83
+ * @param noiseCancellation - a noise cancellation instance to use.
84
+ */
85
+ async enableNoiseCancellation(noiseCancellation: INoiseCancellation) {
86
+ if (isReactNative()) {
87
+ throw new Error('Noise cancellation is not supported in React Native');
88
+ }
89
+
90
+ const { ownCapabilities, settings } = this.call.state;
91
+ const hasNoiseCancellationCapability = ownCapabilities.includes(
92
+ OwnCapability.ENABLE_NOISE_CANCELLATION,
93
+ );
94
+ if (!hasNoiseCancellationCapability) {
95
+ throw new Error('Noise cancellation is not available.');
96
+ }
97
+ const noiseCancellationSettings = settings?.audio.noise_cancellation;
98
+ if (
99
+ !noiseCancellationSettings ||
100
+ noiseCancellationSettings.mode ===
101
+ NoiseCancellationSettingsModeEnum.DISABLED
102
+ ) {
103
+ throw new Error('Noise cancellation is disabled for this call type.');
104
+ }
105
+ try {
106
+ this.noiseCancellation = noiseCancellation;
107
+
108
+ // listen for change events and notify the SFU
109
+ this.noiseCancellationChangeUnsubscribe = this.noiseCancellation.on(
110
+ 'change',
111
+ (enabled: boolean) => {
112
+ if (enabled) {
113
+ this.call.notifyNoiseCancellationStarting().catch((err) => {
114
+ this.logger('warn', `notifyNoiseCancellationStart failed`, err);
115
+ });
116
+ } else {
117
+ this.call.notifyNoiseCancellationStopped().catch((err) => {
118
+ this.logger('warn', `notifyNoiseCancellationStop failed`, err);
119
+ });
120
+ }
121
+ },
122
+ );
123
+
124
+ this.noiseCancellationRegistration = this.registerFilter(
125
+ noiseCancellation.toFilter(),
126
+ );
127
+ await this.noiseCancellationRegistration;
128
+
129
+ // handles an edge case where a noise cancellation is enabled after
130
+ // the participant as joined the call -> we immediately enable NC
131
+ if (
132
+ noiseCancellationSettings.mode ===
133
+ NoiseCancellationSettingsModeEnum.AUTO_ON &&
134
+ this.call.state.callingState === CallingState.JOINED
135
+ ) {
136
+ noiseCancellation.enable();
137
+ }
138
+ } catch (e) {
139
+ this.logger('warn', 'Failed to enable noise cancellation', e);
140
+ await this.disableNoiseCancellation().catch((err) => {
141
+ this.logger('warn', 'Failed to disable noise cancellation', err);
142
+ });
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Disables noise cancellation for the microphone.
148
+ *
149
+ * Note: not supported in React Native.
150
+ */
151
+ async disableNoiseCancellation() {
152
+ if (isReactNative()) {
153
+ throw new Error('Noise cancellation is not supported in React Native');
154
+ }
155
+ await this.noiseCancellationRegistration
156
+ ?.then((unregister) => unregister())
157
+ .then(() => this.noiseCancellation?.disable())
158
+ .then(() => this.noiseCancellationChangeUnsubscribe?.())
159
+ .catch((err) => {
160
+ this.logger('warn', 'Failed to unregister noise cancellation', err);
161
+ });
162
+
163
+ await this.call.notifyNoiseCancellationStopped();
42
164
  }
43
165
 
44
166
  protected getDevices(): Observable<MediaDeviceInfo[]> {