@signalwire/js 4.0.0-dev-20260421201955 → 4.0.0-dev-20260422003445

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1742,11 +1742,31 @@ declare class Participant extends Destroyable implements CallParticipant {
1742
1742
  get videoMuted$(): Observable<boolean | undefined>;
1743
1743
  /** Observable indicating whether the participant is deafened. */
1744
1744
  get deaf$(): Observable<boolean | undefined>;
1745
- /** Observable of the participant's microphone input volume. */
1745
+ /**
1746
+ * Observable of the participant's **server-side** microphone input volume
1747
+ * as reported by the mix engine. This is gain applied on the bridged audio
1748
+ * leg (FreeSWITCH channel read volume), NOT the local browser mic. For a
1749
+ * local PC mic control, see {@link Call.setLocalMicrophoneGain}.
1750
+ *
1751
+ * @see {@link setAudioInputVolume}
1752
+ */
1746
1753
  get inputVolume$(): Observable<number | undefined>;
1747
- /** Observable of the participant's speaker output volume. */
1754
+ /**
1755
+ * Observable of the participant's **server-side** speaker output volume as
1756
+ * reported by the mix engine (FreeSWITCH channel write volume). NOT the
1757
+ * local HTML `<audio>` element volume — set that on your own element.
1758
+ *
1759
+ * @see {@link setAudioOutputVolume}
1760
+ */
1748
1761
  get outputVolume$(): Observable<number | undefined>;
1749
- /** Observable of the microphone input sensitivity level. */
1762
+ /**
1763
+ * Observable of the **conference-only** microphone energy/gate sensitivity
1764
+ * level for this member. Routes through the conferencing mix engine and has
1765
+ * no effect on 1:1 WebRTC calls. Populated from `member.updated` events for
1766
+ * conference members.
1767
+ *
1768
+ * @see {@link setAudioInputSensitivity}
1769
+ */
1750
1770
  get inputSensitivity$(): Observable<number | undefined>;
1751
1771
  /** Observable indicating whether echo cancellation is enabled. */
1752
1772
  get echoCancellation$(): Observable<boolean | undefined>;
@@ -1790,11 +1810,21 @@ declare class Participant extends Destroyable implements CallParticipant {
1790
1810
  get videoMuted(): boolean;
1791
1811
  /** Whether the participant is deafened (incoming audio muted). */
1792
1812
  get deaf(): boolean;
1793
- /** Current microphone input volume level, or `undefined` if not set. */
1813
+ /**
1814
+ * Current **server-side** microphone input volume as reported by the mix
1815
+ * engine, or `undefined` if not set. Not the local PC mic — see
1816
+ * {@link Call.setLocalMicrophoneGain} for browser-side control.
1817
+ */
1794
1818
  get inputVolume(): number | undefined;
1795
- /** Current speaker output volume level, or `undefined` if not set. */
1819
+ /**
1820
+ * Current **server-side** speaker output volume from the mix engine, or
1821
+ * `undefined` if not set. Not the local `<audio>` element volume.
1822
+ */
1796
1823
  get outputVolume(): number | undefined;
1797
- /** Current microphone input sensitivity level, or `undefined` if not set. */
1824
+ /**
1825
+ * Current **conference-only** microphone sensitivity/gate level, or
1826
+ * `undefined` if not set. Applies only to conference members.
1827
+ */
1798
1828
  get inputSensitivity(): number | undefined;
1799
1829
  /** Whether echo cancellation is enabled. */
1800
1830
  get echoCancellation(): boolean;
@@ -1839,15 +1869,40 @@ declare class Participant extends Destroyable implements CallParticipant {
1839
1869
  /** Toggles noise suppression on the audio input. */
1840
1870
  toggleNoiseSuppression(): Promise<void>;
1841
1871
  toggleLowbitrate(): Promise<void>;
1842
- /** Sets the microphone input sensitivity level. */
1872
+ /**
1873
+ * Adjusts the **conference-only** microphone energy gate / sensitivity level
1874
+ * for this member. Routes through the conferencing mix engine
1875
+ * (`signalwire.conferencing member.set_input_sensitivity`) and has no effect
1876
+ * on 1:1 WebRTC calls — for those, use browser audio constraints via
1877
+ * {@link Call.setNoiseSuppression} / {@link Call.setAutoGainControl}.
1878
+ *
1879
+ * This is **not** a local PC mic gain control; it only changes how the
1880
+ * server-side mixer decides to open the mic gate on this participant.
1881
+ *
1882
+ * @param value - Sensitivity level as understood by the conference engine
1883
+ * (integer, larger values are more sensitive).
1884
+ */
1843
1885
  setAudioInputSensitivity(value: number): Promise<void>;
1844
1886
  /**
1845
- * Sets the microphone input volume level.
1887
+ * Sets the **server-side** microphone volume on this participant's bridged
1888
+ * call leg. Applies a multiplier to the audio flowing through the mix
1889
+ * engine (FreeSWITCH channel read volume) — changes what other participants
1890
+ * hear, not what the local browser captures.
1891
+ *
1892
+ * For local PC mic gain, use {@link Call.setLocalMicrophoneGain} instead.
1893
+ *
1846
1894
  * @param value - Volume level (0-100).
1847
1895
  */
1848
1896
  setAudioInputVolume(value: number): Promise<void>;
1849
1897
  /**
1850
- * Sets the speaker output volume level.
1898
+ * Sets the **server-side** speaker volume on this participant's bridged call
1899
+ * leg (FreeSWITCH channel write volume) — what this participant hears from
1900
+ * the mix before it reaches their client.
1901
+ *
1902
+ * For local playback volume (the `<audio>` element the consumer attaches
1903
+ * `remoteStream` to), set `audioElement.volume` directly in the consumer's
1904
+ * code.
1905
+ *
1851
1906
  * @param value - Volume level (0-100).
1852
1907
  */
1853
1908
  setAudioOutputVolume(value: number): Promise<void>;
@@ -3586,6 +3641,21 @@ declare class SignalWire extends Destroyable implements DeviceController {
3586
3641
  selectVideoInputDevice(device: MediaDeviceInfo | null): void;
3587
3642
  /** Sets the preferred audio output device. */
3588
3643
  selectAudioOutputDevice(device: MediaDeviceInfo | null): void;
3644
+ /**
3645
+ * Apply the currently selected audio output device to an HTMLMediaElement
3646
+ * (e.g. the `<audio>` or `<video>` element the consumer attached the
3647
+ * remote stream to). Uses `HTMLMediaElement.setSinkId` under the hood.
3648
+ * Returns a `Promise<boolean>`: `true` if the sink was applied,
3649
+ * `false` if the browser doesn't support `setSinkId` or no device is
3650
+ * selected.
3651
+ *
3652
+ * @example
3653
+ * ```ts
3654
+ * audioEl.srcObject = call.remoteStream;
3655
+ * await client.applySelectedAudioOutputDevice(audioEl);
3656
+ * ```
3657
+ */
3658
+ applySelectedAudioOutputDevice(element: HTMLMediaElement): Promise<boolean>;
3589
3659
  /** Starts monitoring for media device changes (connect/disconnect). */
3590
3660
  enableDeviceMonitoring(): void;
3591
3661
  /** Stops monitoring for media device changes. */
@@ -3686,6 +3756,109 @@ declare class StaticCredentialProvider implements CredentialProvider {
3686
3756
  authenticate(): Promise<SDKCredential>;
3687
3757
  }
3688
3758
  //#endregion
3759
+ //#region src/controllers/LocalAudioPipeline.d.ts
3760
+ /**
3761
+ * Options for {@link LocalAudioPipeline}.
3762
+ */
3763
+ interface LocalAudioPipelineOptions {
3764
+ /** Factory for AudioContext — override for tests. Defaults to `new AudioContext()`. */
3765
+ audioContextFactory?: () => AudioContext;
3766
+ /** Initial gain (0..2, where 1 is unity). Defaults to 1. */
3767
+ initialGain?: number;
3768
+ /** RMS level [0..1] above which speaking$ emits true. Defaults to {@link VAD_THRESHOLD}. */
3769
+ speakingThreshold?: number;
3770
+ /**
3771
+ * Milliseconds of silence below the threshold before speaking$ flips back to
3772
+ * false. Prevents flicker on normal speech gaps. Defaults to {@link VAD_HOLD_MS}.
3773
+ */
3774
+ speakingHoldMs?: number;
3775
+ /** Polling interval for level$. Defaults to {@link AUDIO_LEVEL_POLL_INTERVAL_MS}. */
3776
+ pollIntervalMs?: number;
3777
+ }
3778
+ /**
3779
+ * Web Audio pipeline for the local microphone stream.
3780
+ *
3781
+ * Wraps the raw mic `MediaStreamTrack` in a graph of:
3782
+ *
3783
+ * ```
3784
+ * MediaStreamAudioSourceNode → GainNode → AnalyserNode → MediaStreamAudioDestinationNode
3785
+ * ```
3786
+ *
3787
+ * The {@link outputTrack} from the destination node is what callers should
3788
+ * attach to the `RTCRtpSender` in place of the raw mic track. The same
3789
+ * destination track is reused across input changes (device switch, mute /
3790
+ * unmute track replacement) so the sender reference stays stable — only the
3791
+ * source end of the graph is rebuilt.
3792
+ *
3793
+ * The pipeline owns a single {@link AudioContext}. Callers must invoke
3794
+ * {@link destroy} to release it when the call ends.
3795
+ */
3796
+ declare class LocalAudioPipeline extends Destroyable {
3797
+ private readonly _audioContext;
3798
+ private readonly _gainNode;
3799
+ private readonly _analyser;
3800
+ private readonly _destination;
3801
+ private readonly _analyserBuffer;
3802
+ private readonly _speakingThreshold;
3803
+ private readonly _speakingHoldMs;
3804
+ private readonly _pollIntervalMs;
3805
+ private _inputSource;
3806
+ private _inputStream;
3807
+ private _lastSpokeAt;
3808
+ private _gain$;
3809
+ /** 1 when audio should pass through, 0 when silenced by PTT. */
3810
+ private _pttMultiplier;
3811
+ constructor(options?: LocalAudioPipelineOptions);
3812
+ /** Observable of the current gain value (0..2). */
3813
+ get gain$(): Observable<number>;
3814
+ /** Current gain value (0..2). */
3815
+ get gain(): number;
3816
+ /**
3817
+ * Processed output track to attach to the RTCRtpSender. Stable reference
3818
+ * across input changes, so `sender.replaceTrack(pipeline.outputTrack)` only
3819
+ * needs to be called once.
3820
+ */
3821
+ get outputTrack(): MediaStreamTrack;
3822
+ /**
3823
+ * Root-mean-square audio level of the input signal, 0..1. Emits on a fixed
3824
+ * interval (~30fps by default).
3825
+ */
3826
+ get level$(): Observable<number>;
3827
+ /**
3828
+ * Boolean VAD derived from {@link level$}. True while level ≥ threshold or
3829
+ * during the hold window after the last frame that crossed the threshold.
3830
+ */
3831
+ get speaking$(): Observable<boolean>;
3832
+ /**
3833
+ * Set gain multiplier applied to the input signal. 0 = silence,
3834
+ * 1 = unity, 2 = 2x. Values are clamped to [0, 2]. The effective gain on
3835
+ * the graph also respects the current PTT state.
3836
+ */
3837
+ setGain(value: number): void;
3838
+ /**
3839
+ * Silence the graph when `active = false`, otherwise restore the configured
3840
+ * gain. Use this from a PTT handler: released → `false`, held → `true`.
3841
+ * Orthogonal to {@link setGain} — once PTT returns to active, the last
3842
+ * configured gain reappears.
3843
+ */
3844
+ setPTTActive(active: boolean): void;
3845
+ private applyEffectiveGain;
3846
+ /**
3847
+ * Wire a new raw mic track as the pipeline's input. Replaces any previous
3848
+ * input source and reconnects the graph so {@link outputTrack} continues
3849
+ * to emit the processed audio. Pass `null` to disconnect the input (the
3850
+ * output track stays alive but emits silence).
3851
+ *
3852
+ * Also resumes the underlying AudioContext on attach — Chrome creates it
3853
+ * in a suspended state and the graph won't process (the destination
3854
+ * track emits silence) until resume() succeeds.
3855
+ */
3856
+ setInputTrack(track: MediaStreamTrack | null): void;
3857
+ destroy(): void;
3858
+ private computeLevel;
3859
+ private evaluateSpeaking;
3860
+ }
3861
+ //#endregion
3689
3862
  //#region src/controllers/RTCPeerConnectionController.d.ts
3690
3863
  interface RTCPeerConnectionControllerOptions extends MediaOptions {
3691
3864
  callId?: string;
@@ -3746,6 +3919,7 @@ declare class RTCPeerConnectionController extends Destroyable {
3746
3919
  private _remoteDescription$;
3747
3920
  private _remoteStream$;
3748
3921
  private _remoteOfferMediaDirections;
3922
+ private _localAudioPipeline;
3749
3923
  constructor(options?: RTCPeerConnectionControllerOptionsPartial, remoteSessionDescription?: string, deviceController?: DeviceController);
3750
3924
  private get iceGatheringController();
3751
3925
  private get shouldEmitLocalDescription();
@@ -3858,6 +4032,17 @@ declare class RTCPeerConnectionController extends Destroyable {
3858
4032
  private getDisplayMedia;
3859
4033
  private setupRemoteTracks;
3860
4034
  restoreTrackSender(kind: 'audio' | 'video' | 'both'): Promise<void>;
4035
+ /**
4036
+ * Return the lazily-created {@link LocalAudioPipeline}, constructing it on
4037
+ * first access. On creation the current audio sender's track is routed
4038
+ * through the pipeline (input → gain → analyser → destination) and the
4039
+ * sender is switched to emit the processed track. Returns `null` when no
4040
+ * audio sender exists yet (pre-negotiation).
4041
+ */
4042
+ ensureLocalAudioPipeline(): LocalAudioPipeline | null;
4043
+ /** The active LocalAudioPipeline, or null if it hasn't been created yet. */
4044
+ get localAudioPipeline(): LocalAudioPipeline | null;
4045
+ private applyLocalAudioPipelineToSender;
3861
4046
  /**
3862
4047
  * Add a local media track to the peer connection.
3863
4048
  * @param track - The MediaStreamTrack to add
@@ -3928,6 +4113,10 @@ interface WebRTCVerto extends VertoManager {
3928
4113
  requestIceRestartAll?: (relayOnly?: boolean) => Promise<void>;
3929
4114
  /** Request keyframes on all video-receiving legs (skips send-only screen share). */
3930
4115
  requestKeyframeAll?: () => void;
4116
+ /** Lazily create (or return) the local audio pipeline for the main peer connection. */
4117
+ ensureLocalAudioPipeline(): LocalAudioPipeline | null;
4118
+ /** Current local audio pipeline, or null if it has not been created yet. */
4119
+ readonly localAudioPipeline: LocalAudioPipeline | null;
3931
4120
  }
3932
4121
  //#endregion
3933
4122
  //#region src/managers/CallEventsManager.d.ts
@@ -4075,6 +4264,8 @@ declare class WebRTCCall extends Destroyable implements CallManager {
4075
4264
  private _bandwidthConstrained$;
4076
4265
  private _mediaParamsUpdated$;
4077
4266
  private _customSubscriptions;
4267
+ private _pushToTalkEnabled;
4268
+ private _remoteAudioMeter;
4078
4269
  constructor(clientSession: ClientSession, options: CallOptions, initialization: CallInitialization, address?: Address | undefined);
4079
4270
  /** Observable stream of errors from media, signaling, and peer connection layers. */
4080
4271
  get errors$(): Observable<CallError>;
@@ -4402,6 +4593,79 @@ declare class WebRTCCall extends Destroyable implements CallManager {
4402
4593
  * @see {@link status$} to observe the transfer progress.
4403
4594
  */
4404
4595
  transfer(options: TransferOptions): Promise<void>;
4596
+ /**
4597
+ * Set the local microphone gain as a percentage applied before transmission.
4598
+ *
4599
+ * - `0` = silent
4600
+ * - `100` = unity (no change, default)
4601
+ * - `200` = 2× digital boost (max; expect clipping / noise amplification)
4602
+ *
4603
+ * Values are clamped to [0, 200]. Engages the local audio pipeline on
4604
+ * first use (one-time cost).
4605
+ *
4606
+ * Note: this is a **digital** multiplier applied in a Web Audio GainNode
4607
+ * between your mic track and the RTCRtpSender — it does not change the
4608
+ * physical mic's hardware sensitivity. Browsers' autoGainControl can
4609
+ * fight the setting; call {@link setAutoGainControl}(false) for
4610
+ * predictable behaviour.
4611
+ *
4612
+ * @param value - Gain percentage (0..200; 100 = unity).
4613
+ */
4614
+ setLocalMicrophoneGain(value: number): void;
4615
+ /** Observable of the current local microphone gain (0..200, where 100 = unity). */
4616
+ get localMicrophoneGain$(): Observable<number>;
4617
+ /**
4618
+ * Observable of the RMS audio level of the local microphone, 0..1.
4619
+ * Emits at ~30fps while a mic track is active. Engages the local audio
4620
+ * pipeline on first subscription.
4621
+ */
4622
+ get localAudioLevel$(): Observable<number>;
4623
+ /**
4624
+ * Observable that is `true` while the local participant is speaking
4625
+ * (RMS level above the VAD threshold, with hold time to avoid flicker).
4626
+ */
4627
+ get localSpeaking$(): Observable<boolean>;
4628
+ /**
4629
+ * Enable push-to-talk: while {@link setPushToTalkActive} has been called
4630
+ * with `false`, the microphone gain is forced to 0; calling
4631
+ * {@link setPushToTalkActive} with `true` restores the configured gain.
4632
+ * Use this instead of mute/unmute for instant talk/silence transitions
4633
+ * because it doesn't rebuild the track.
4634
+ *
4635
+ * This method installs the pipeline but does not attach any keyboard
4636
+ * listener — consumers bind the key themselves and call
4637
+ * {@link setPushToTalkActive} on keydown/keyup.
4638
+ */
4639
+ enablePushToTalk(): void;
4640
+ /** Disable push-to-talk; mic gain returns to the configured value. */
4641
+ disablePushToTalk(): void;
4642
+ /**
4643
+ * While push-to-talk is enabled, sets the talk state. `true` = transmitting,
4644
+ * `false` = silent. No-op if push-to-talk has not been enabled.
4645
+ */
4646
+ setPushToTalkActive(active: boolean): void;
4647
+ /**
4648
+ * Toggle echo cancellation on the local mic at runtime. Applied via
4649
+ * `track.applyConstraints`; browsers that don't honour runtime constraints
4650
+ * (notably iOS Safari) fall back to re-acquiring the track with the new
4651
+ * constraint set and plumbing the replacement through the local audio
4652
+ * pipeline if one is active.
4653
+ */
4654
+ setEchoCancellation(enabled: boolean): Promise<void>;
4655
+ /** Toggle browser noise suppression on the local mic at runtime. */
4656
+ setNoiseSuppression(enabled: boolean): Promise<void>;
4657
+ /** Toggle browser automatic gain control on the local mic at runtime. */
4658
+ setAutoGainControl(enabled: boolean): Promise<void>;
4659
+ /**
4660
+ * Observable of the aggregate remote audio level, 0..1 RMS. The server
4661
+ * delivers a single mixed audio stream for all remote participants — this
4662
+ * meter reports that mix. Per-participant audio is not available client-side.
4663
+ *
4664
+ * Engages a shared AudioContext on first subscription (cheap — one
4665
+ * AnalyserNode, no GainNode, no destination) so it does not affect the
4666
+ * caller's audio element playback.
4667
+ */
4668
+ get remoteAudioLevel$(): Observable<number>;
4405
4669
  /** Destroys the call, releasing all resources and subscriptions. */
4406
4670
  destroy(): void;
4407
4671
  /**