@stream-io/video-client 0.5.11 → 0.6.1

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.
Files changed (56) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/index.browser.es.js +377 -566
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +376 -565
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +377 -566
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/src/Call.d.ts +12 -13
  9. package/dist/src/StreamVideoClient.d.ts +4 -5
  10. package/dist/src/coordinator/connection/client.d.ts +7 -13
  11. package/dist/src/coordinator/connection/types.d.ts +16 -4
  12. package/dist/src/devices/SpeakerManager.d.ts +14 -3
  13. package/dist/src/events/call-permissions.d.ts +2 -2
  14. package/dist/src/events/call.d.ts +4 -4
  15. package/dist/src/events/internal.d.ts +2 -2
  16. package/dist/src/events/participant.d.ts +5 -5
  17. package/dist/src/rtc/Dispatcher.d.ts +19 -6
  18. package/dist/src/rtc/IceTrickleBuffer.d.ts +2 -3
  19. package/dist/src/rtc/signal.d.ts +2 -2
  20. package/dist/src/types.d.ts +7 -0
  21. package/package.json +4 -4
  22. package/src/Call.ts +46 -53
  23. package/src/StreamSfuClient.ts +1 -3
  24. package/src/StreamVideoClient.ts +14 -13
  25. package/src/__tests__/server-side/call.test.ts +1 -7
  26. package/src/coordinator/connection/client.ts +30 -53
  27. package/src/coordinator/connection/connection.ts +22 -9
  28. package/src/coordinator/connection/types.ts +16 -5
  29. package/src/devices/InputMediaDeviceManagerState.ts +10 -1
  30. package/src/devices/SpeakerManager.ts +25 -4
  31. package/src/devices/__tests__/InputMediaDeviceManagerState.test.ts +25 -1
  32. package/src/devices/__tests__/SpeakerManager.test.ts +32 -2
  33. package/src/events/__tests__/call-permissions.test.ts +10 -20
  34. package/src/events/__tests__/mutes.test.ts +26 -55
  35. package/src/events/__tests__/participant.test.ts +47 -87
  36. package/src/events/call-permissions.ts +3 -4
  37. package/src/events/call.ts +6 -13
  38. package/src/events/callEventHandlers.ts +7 -4
  39. package/src/events/internal.ts +14 -22
  40. package/src/events/mutes.ts +1 -4
  41. package/src/events/participant.ts +14 -19
  42. package/src/events/speaker.ts +2 -8
  43. package/src/gen/google/protobuf/struct.ts +12 -19
  44. package/src/gen/google/protobuf/timestamp.ts +4 -7
  45. package/src/gen/video/sfu/event/events.ts +83 -164
  46. package/src/gen/video/sfu/models/models.ts +81 -123
  47. package/src/gen/video/sfu/signal_rpc/signal.client.ts +1 -1
  48. package/src/gen/video/sfu/signal_rpc/signal.ts +38 -77
  49. package/src/helpers/DynascaleManager.ts +7 -5
  50. package/src/helpers/__tests__/DynascaleManager.test.ts +5 -0
  51. package/src/rtc/Dispatcher.ts +42 -25
  52. package/src/rtc/IceTrickleBuffer.ts +4 -8
  53. package/src/rtc/Publisher.ts +1 -3
  54. package/src/rtc/Subscriber.ts +2 -6
  55. package/src/rtc/signal.ts +3 -2
  56. package/src/types.ts +8 -0
@@ -1,4 +1,4 @@
1
- import { Publisher, SfuEventKinds, SfuEventListener, Subscriber } from './rtc';
1
+ import { Publisher, Subscriber } from './rtc';
2
2
  import { TrackType } from './gen/video/sfu/models/models';
3
3
  import { CallState } from './store';
4
4
  import { AcceptCallResponse, BlockUserResponse, EndCallResponse, GetCallResponse, GetOrCreateCallRequest, GetOrCreateCallResponse, GoLiveRequest, GoLiveResponse, ListRecordingsResponse, MuteUsersResponse, PinRequest, PinResponse, QueryMembersRequest, QueryMembersResponse, RejectCallResponse, RequestPermissionRequest, RequestPermissionResponse, SendEventResponse, SendReactionRequest, SendReactionResponse, StartHLSBroadcastingResponse, StartRecordingRequest, StartRecordingResponse, StopHLSBroadcastingResponse, StopLiveResponse, StopRecordingResponse, UnblockUserResponse, UnpinRequest, UnpinResponse, UpdateCallMembersRequest, UpdateCallMembersResponse, UpdateCallRequest, UpdateCallResponse, UpdateUserPermissionsRequest, UpdateUserPermissionsResponse } from './gen/coordinator';
@@ -7,7 +7,7 @@ import { VideoLayerSetting } from './gen/video/sfu/event/events';
7
7
  import { DynascaleManager } from './helpers/DynascaleManager';
8
8
  import { PermissionsContext } from './permissions';
9
9
  import { StreamClient } from './coordinator/connection/client';
10
- import { CallEventHandler, CallEventTypes, EventTypes, Logger } from './coordinator/connection/types';
10
+ import { CallEventListener, Logger } from './coordinator/connection/types';
11
11
  import { CameraManager, MicrophoneManager, ScreenShareManager, SpeakerManager } from './devices';
12
12
  /**
13
13
  * An object representation of a `Call`.
@@ -97,21 +97,20 @@ export declare class Call {
97
97
  private registerEffects;
98
98
  /**
99
99
  * You can subscribe to WebSocket events provided by the API. To remove a subscription, call the `off` method.
100
- * Please note that subscribing to WebSocket events is an advanced use-case, for most use-cases it should be enough to watch for changes in the [reactive state store](./StreamVideoClient.md/#readonlystatestore).
101
- * @param eventName
102
- * @param fn
103
- * @returns a function which can be called to unsubscribe from the given event(s)
100
+ * Please note that subscribing to WebSocket events is an advanced use-case.
101
+ * For most use-cases, it should be enough to watch for state changes.
102
+ *
103
+ * @param eventName the event name.
104
+ * @param fn the event handler.
104
105
  */
105
- on(eventName: SfuEventKinds, fn: SfuEventListener): () => void;
106
- on(eventName: EventTypes, fn: CallEventHandler): () => void;
106
+ on: <E extends import("./coordinator/connection/types").EventTypes | import("./rtc").SfuEventKinds>(eventName: E, fn: CallEventListener<E>) => () => void;
107
107
  /**
108
108
  * Remove subscription for WebSocket events that were created by the `on` method.
109
- * @param eventName
110
- * @param fn
111
- * @returns
109
+ *
110
+ * @param eventName the event name.
111
+ * @param fn the event handler.
112
112
  */
113
- off(eventName: SfuEventKinds, fn: SfuEventListener): void;
114
- off(eventName: CallEventTypes, fn: CallEventHandler): void;
113
+ off: <E extends import("./coordinator/connection/types").EventTypes | import("./rtc").SfuEventKinds>(eventName: E, fn: CallEventListener<E>) => void;
115
114
  /**
116
115
  * Leave the call and stop the media streams that were published by the call.
117
116
  */
@@ -2,7 +2,7 @@ import { Call } from './Call';
2
2
  import { StreamClient } from './coordinator/connection/client';
3
3
  import { StreamVideoReadOnlyStateStore, StreamVideoWriteableStateStore } from './store';
4
4
  import type { ConnectedEvent, CreateDeviceRequest, CreateGuestRequest, CreateGuestResponse, GetEdgesResponse, ListDevicesResponse, QueryCallsRequest } from './gen/coordinator';
5
- import type { EventHandler, EventTypes, Logger, LogLevel, StreamClientOptions, TokenOrProvider, TokenProvider, User, UserWithId } from './coordinator/connection/types';
5
+ import { ClientEventListener, Logger, LogLevel, StreamClientOptions, TokenOrProvider, TokenProvider, User, UserWithId } from './coordinator/connection/types';
6
6
  /**
7
7
  * A `StreamVideoClient` instance lets you communicate with our API, and authenticate users.
8
8
  */
@@ -60,14 +60,14 @@ export declare class StreamVideoClient {
60
60
  * @param callback the callback which will be called when the event is emitted.
61
61
  * @returns an unsubscribe function.
62
62
  */
63
- on: (eventName: EventTypes, callback: EventHandler) => () => void;
63
+ on: <E extends import("./coordinator/connection/types").AllClientEventTypes>(eventName: E, callback: ClientEventListener<E>) => () => void;
64
64
  /**
65
65
  * Remove subscription for WebSocket events that were created by the `on` method.
66
66
  *
67
- * @param event the event name.
67
+ * @param eventName the event name.
68
68
  * @param callback the callback which was passed to the `on` method.
69
69
  */
70
- off: (event: string, callback: EventHandler) => void;
70
+ off: <E extends import("./coordinator/connection/types").AllClientEventTypes>(eventName: E, callback: ClientEventListener<E>) => void;
71
71
  /**
72
72
  * Creates a new call.
73
73
  *
@@ -125,7 +125,6 @@ export declare class StreamVideoClient {
125
125
  *
126
126
  * @param {string} id The device id
127
127
  * @param {string} [userID] The user id. Only specify this for serverside requests
128
- *
129
128
  */
130
129
  removeDevice: (id: string, userID?: string) => Promise<unknown>;
131
130
  /**
@@ -1,10 +1,9 @@
1
1
  /// <reference types="node" />
2
2
  import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
3
- import WebSocket from 'isomorphic-ws';
4
3
  import { StableWSConnection } from './connection';
5
4
  import { TokenManager } from './token_manager';
6
5
  import { WSConnectionFallback } from './connection_fallback';
7
- import { APIErrorResponse, ConnectAPIResponse, ErrorFromResponse, EventHandler, Logger, StreamClientOptions, StreamVideoEvent, TokenOrProvider, User, UserWithId } from './types';
6
+ import { AllClientEventTypes, APIErrorResponse, ClientEventListener, ConnectAPIResponse, ErrorFromResponse, Logger, StreamClientOptions, StreamVideoEvent, TokenOrProvider, User, UserWithId } from './types';
8
7
  import { InsightMetrics } from './insights';
9
8
  import { CreateGuestResponse } from '../../gen/coordinator';
10
9
  export declare class StreamClient {
@@ -17,7 +16,7 @@ export declare class StreamClient {
17
16
  cleaningIntervalRef?: NodeJS.Timeout;
18
17
  clientID?: string;
19
18
  key: string;
20
- listeners: Record<string, Array<(event: StreamVideoEvent) => void>>;
19
+ listeners: Partial<Record<AllClientEventTypes, ClientEventListener<any>[] | undefined>>;
21
20
  logger: Logger;
22
21
  private locationHint;
23
22
  node: boolean;
@@ -108,20 +107,17 @@ export declare class StreamClient {
108
107
  * on - Listen to events on all channels and users your watching
109
108
  *
110
109
  * client.on('message.new', event => {console.log("my new message", event, channel.state.messages)})
111
- * or
112
- * client.on(event => {console.log(event.type)})
113
110
  *
114
- * @param {EventHandler | string} callbackOrEventName The event type to listen for (optional)
115
- * @param {EventHandler} [callbackOrNothing] The callback to call
111
+ * @param eventName The event type to listen for (optional)
112
+ * @param callback The callback to call
116
113
  *
117
- * @return {Function} Returns a function which, when called, unsubscribes the event handler.
114
+ * @return Returns a function which, when called, unsubscribes the event handler.
118
115
  */
119
- on: (callbackOrEventName: EventHandler | string, callbackOrNothing?: EventHandler) => () => void;
116
+ on: <E extends AllClientEventTypes>(eventName: E, callback: ClientEventListener<E>) => () => void;
120
117
  /**
121
118
  * off - Remove the event handler
122
- *
123
119
  */
124
- off: (callbackOrEventName: EventHandler | string, callbackOrNothing?: EventHandler) => void;
120
+ off: <E extends AllClientEventTypes>(eventName: E, callback: ClientEventListener<E>) => void;
125
121
  _logApiRequest: (type: string, url: string, data: unknown, config: AxiosRequestConfig<any> & {
126
122
  config?: (AxiosRequestConfig<any> & {
127
123
  maxBodyLength?: number | undefined;
@@ -144,8 +140,6 @@ export declare class StreamClient {
144
140
  errorFromResponse: (response: AxiosResponse<APIErrorResponse>) => ErrorFromResponse<APIErrorResponse>;
145
141
  handleResponse: <T>(response: AxiosResponse<T, any>) => T;
146
142
  dispatchEvent: (event: StreamVideoEvent) => void;
147
- handleEvent: (messageEvent: WebSocket.MessageEvent) => void;
148
- _callClientListeners: (event: StreamVideoEvent) => void;
149
143
  /**
150
144
  * @private
151
145
  */
@@ -1,6 +1,7 @@
1
1
  import { AxiosRequestConfig, AxiosResponse } from 'axios';
2
2
  import { StableWSConnection } from './connection';
3
3
  import { ConnectedEvent, UserRequest, VideoEvent } from '../../gen/coordinator';
4
+ import { AllSfuEvents } from '../../rtc';
4
5
  export type UR = Record<string, unknown>;
5
6
  export type User = (Omit<UserRequest, 'role'> & {
6
7
  type?: 'authenticated';
@@ -55,10 +56,21 @@ export type StreamVideoEvent = (VideoEvent | ConnectionChangedEvent | TransportC
55
56
  export type StreamCallEvent = Extract<StreamVideoEvent, {
56
57
  call_cid: string;
57
58
  }>;
58
- export type EventHandler = (event: StreamVideoEvent) => void;
59
- export type CallEventHandler = (event: StreamCallEvent) => void;
60
- export type EventTypes = 'all' | StreamVideoEvent['type'];
61
- export type CallEventTypes = StreamCallEvent['type'];
59
+ export type EventTypes = 'all' | VideoEvent['type'];
60
+ export type AllClientEventTypes = 'all' | StreamVideoEvent['type'];
61
+ export type AllClientEvents = {
62
+ [K in AllClientEventTypes]: Extract<StreamVideoEvent, {
63
+ type: K;
64
+ }>;
65
+ };
66
+ export type ClientEventListener<E extends keyof AllClientEvents> = (event: AllClientEvents[E]) => void;
67
+ export type AllClientCallEvents = {
68
+ [K in EventTypes]: Extract<VideoEvent, {
69
+ type: K;
70
+ }>;
71
+ };
72
+ export type AllCallEvents = AllClientCallEvents & AllSfuEvents;
73
+ export type CallEventListener<E extends keyof AllCallEvents> = (event: AllCallEvents[E]) => void;
62
74
  export type Logger = (logLevel: LogLevel, message: string, ...args: unknown[]) => void;
63
75
  export type StreamClientOptions = Partial<AxiosRequestConfig> & {
64
76
  /**
@@ -1,8 +1,10 @@
1
+ import { Call } from '../Call';
1
2
  import { SpeakerState } from './SpeakerState';
2
3
  export declare class SpeakerManager {
3
4
  readonly state: SpeakerState;
4
5
  private subscriptions;
5
- constructor();
6
+ private readonly call;
7
+ constructor(call: Call);
6
8
  /**
7
9
  * Lists the available audio output devices
8
10
  *
@@ -12,7 +14,7 @@ export declare class SpeakerManager {
12
14
  */
13
15
  listDevices(): import("rxjs").Observable<MediaDeviceInfo[]>;
14
16
  /**
15
- * Select device
17
+ * Select a device.
16
18
  *
17
19
  * Note: this method is not supported in React Native
18
20
  *
@@ -22,9 +24,18 @@ export declare class SpeakerManager {
22
24
  removeSubscriptions: () => void;
23
25
  /**
24
26
  * Set the volume of the audio elements
25
- * @param volume a number between 0 and 1
27
+ * @param volume a number between 0 and 1.
26
28
  *
27
29
  * Note: this method is not supported in React Native
28
30
  */
29
31
  setVolume(volume: number): void;
32
+ /**
33
+ * Set the volume of a participant.
34
+ *
35
+ * Note: this method is not supported in React Native.
36
+ *
37
+ * @param sessionId the participant's session id.
38
+ * @param volume a number between 0 and 1. Set it to `undefined` to use the default volume.
39
+ */
40
+ setParticipantVolume(sessionId: string, volume: number | undefined): void;
30
41
  }
@@ -1,8 +1,8 @@
1
1
  import { CallState } from '../store';
2
- import { SfuEvent } from '../gen/video/sfu/event/events';
2
+ import type { CallGrantsUpdated } from '../gen/video/sfu/event/events';
3
3
  /**
4
4
  * Event handler that watches for `callGrantsUpdated` events.
5
5
  *
6
6
  * @param state the call state to update.
7
7
  */
8
- export declare const watchCallGrantsUpdated: (state: CallState) => (event: SfuEvent) => void;
8
+ export declare const watchCallGrantsUpdated: (state: CallState) => (event: CallGrantsUpdated) => void;
@@ -1,16 +1,16 @@
1
- import { StreamVideoEvent } from '../coordinator/connection/types';
2
1
  import { Call } from '../Call';
2
+ import type { CallAcceptedEvent, CallRejectedEvent } from '../gen/coordinator';
3
3
  /**
4
4
  * Event handler that watched the delivery of `call.accepted`.
5
5
  * Once the event is received, the call is joined.
6
6
  */
7
- export declare const watchCallAccepted: (call: Call) => (event: StreamVideoEvent) => Promise<void>;
7
+ export declare const watchCallAccepted: (call: Call) => (event: CallAcceptedEvent) => Promise<void>;
8
8
  /**
9
9
  * Event handler that watches delivery of `call.rejected` Websocket event.
10
10
  * Once the event is received, the call is left.
11
11
  */
12
- export declare const watchCallRejected: (call: Call) => (event: StreamVideoEvent) => Promise<void>;
12
+ export declare const watchCallRejected: (call: Call) => (event: CallRejectedEvent) => Promise<void>;
13
13
  /**
14
14
  * Event handler that watches the delivery of `call.ended` Websocket event.
15
15
  */
16
- export declare const watchCallEnded: (call: Call) => (event: StreamVideoEvent) => Promise<void>;
16
+ export declare const watchCallEnded: (call: Call) => () => Promise<void>;
@@ -1,7 +1,7 @@
1
1
  import { Dispatcher } from '../rtc';
2
2
  import { Call } from '../Call';
3
3
  import { CallState } from '../store';
4
- import { SfuEvent } from '../gen/video/sfu/event/events';
4
+ import type { PinsChanged } from '../gen/video/sfu/event/events';
5
5
  /**
6
6
  * An event responder which handles the `changePublishQuality` event.
7
7
  */
@@ -21,4 +21,4 @@ export declare const watchSfuErrorReports: (dispatcher: Dispatcher) => () => voi
21
21
  * Watches for `pinsUpdated` events and updates the pinned state of participants
22
22
  * in the call.
23
23
  */
24
- export declare const watchPinsUpdated: (state: CallState) => (e: SfuEvent) => void;
24
+ export declare const watchPinsUpdated: (state: CallState) => (e: PinsChanged) => void;
@@ -1,20 +1,20 @@
1
- import { SfuEvent } from '../gen/video/sfu/event/events';
1
+ import type { ParticipantJoined, ParticipantLeft, TrackPublished, TrackUnpublished } from '../gen/video/sfu/event/events';
2
2
  import { CallState } from '../store';
3
3
  /**
4
4
  * An event responder which handles the `participantJoined` event.
5
5
  */
6
- export declare const watchParticipantJoined: (state: CallState) => (e: SfuEvent) => void;
6
+ export declare const watchParticipantJoined: (state: CallState) => (e: ParticipantJoined) => void;
7
7
  /**
8
8
  * An event responder which handles the `participantLeft` event.
9
9
  */
10
- export declare const watchParticipantLeft: (state: CallState) => (e: SfuEvent) => void;
10
+ export declare const watchParticipantLeft: (state: CallState) => (e: ParticipantLeft) => void;
11
11
  /**
12
12
  * An event responder which handles the `trackPublished` event.
13
13
  * The SFU will send this event when a participant publishes a track.
14
14
  */
15
- export declare const watchTrackPublished: (state: CallState) => (e: SfuEvent) => void;
15
+ export declare const watchTrackPublished: (state: CallState) => (e: TrackPublished) => void;
16
16
  /**
17
17
  * An event responder which handles the `trackUnpublished` event.
18
18
  * The SFU will send this event when a participant unpublishes a track.
19
19
  */
20
- export declare const watchTrackUnpublished: (state: CallState) => (e: SfuEvent) => void;
20
+ export declare const watchTrackUnpublished: (state: CallState) => (e: TrackUnpublished) => void;
@@ -1,13 +1,26 @@
1
- import { EventTypes } from '../coordinator/connection/types';
1
+ import { CallEventListener, EventTypes } from '../coordinator/connection/types';
2
2
  import type { SfuEvent } from '../gen/video/sfu/event/events';
3
3
  export type SfuEventKinds = NonNullable<SfuEvent['eventPayload']['oneofKind']>;
4
+ export type AllSfuEvents = {
5
+ [K in SfuEventKinds]: K extends keyof Extract<SfuEvent['eventPayload'], {
6
+ oneofKind: K;
7
+ }> ? Extract<SfuEvent['eventPayload'], {
8
+ oneofKind: K;
9
+ }>[K] : never;
10
+ };
11
+ export type DispatchableMessage<K extends SfuEventKinds> = {
12
+ eventPayload: {
13
+ oneofKind: K;
14
+ } & {
15
+ [Key in K]: AllSfuEvents[Key];
16
+ };
17
+ };
4
18
  export declare const isSfuEvent: (eventName: SfuEventKinds | EventTypes) => eventName is SfuEventKinds;
5
- export type SfuEventListener = (event: SfuEvent) => void;
6
19
  export declare class Dispatcher {
7
- private subscribers;
8
20
  private readonly logger;
9
- dispatch: (message: SfuEvent) => void;
10
- on: (eventName: SfuEventKinds, fn: SfuEventListener) => () => void;
11
- off: (eventName: SfuEventKinds, fn: SfuEventListener) => void;
21
+ private subscribers;
22
+ dispatch: <K extends SfuEventKinds>(message: DispatchableMessage<K>) => void;
23
+ on: <E extends SfuEventKinds>(eventName: E, fn: CallEventListener<E>) => () => void;
24
+ off: <E extends SfuEventKinds>(eventName: E, fn: CallEventListener<E>) => void;
12
25
  offAll: (eventName?: SfuEventKinds) => void;
13
26
  }
@@ -1,5 +1,5 @@
1
1
  import { ReplaySubject } from 'rxjs';
2
- import { ICETrickle } from '../gen/video/sfu/models/models';
2
+ import { ICETrickle } from '../gen/video/sfu/event/events';
3
3
  /**
4
4
  * A buffer for ICE Candidates. Used for ICE Trickle:
5
5
  * - https://bloggeek.me/webrtcglossary/trickle-ice/
@@ -7,7 +7,6 @@ import { ICETrickle } from '../gen/video/sfu/models/models';
7
7
  export declare class IceTrickleBuffer {
8
8
  readonly subscriberCandidates: ReplaySubject<ICETrickle>;
9
9
  readonly publisherCandidates: ReplaySubject<ICETrickle>;
10
- private logger?;
11
- constructor();
10
+ private readonly logger;
12
11
  push: (iceTrickle: ICETrickle) => void;
13
12
  }
@@ -1,6 +1,6 @@
1
1
  import WebSocket from 'isomorphic-ws';
2
- import { SfuEvent } from '../gen/video/sfu/event/events';
2
+ import { DispatchableMessage, SfuEventKinds } from './Dispatcher';
3
3
  export declare const createWebSocketSignalChannel: (opts: {
4
4
  endpoint: string;
5
- onMessage: (message: SfuEvent) => void;
5
+ onMessage: <K extends SfuEventKinds>(message: DispatchableMessage<K>) => void;
6
6
  }) => WebSocket;
@@ -64,6 +64,13 @@ export interface StreamVideoParticipant extends Participant {
64
64
  * The visibility state of the participant's tracks within a defined viewport.
65
65
  */
66
66
  viewportVisibilityState?: Record<VideoTrackType, VisibilityState>;
67
+ /**
68
+ * The volume of the participant's audio stream (from 0 to 1).
69
+ * Set it to `undefined` to use the default volume.
70
+ *
71
+ * Note: this value is not applicable in React Native.
72
+ */
73
+ audioVolume?: number;
67
74
  }
68
75
  export type VideoTrackType = 'videoTrack' | 'screenShareTrack';
69
76
  export type AudioTrackType = 'audioTrack' | 'screenShareAudioTrack';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-client",
3
- "version": "0.5.11",
3
+ "version": "0.6.1",
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.1",
32
- "@protobuf-ts/runtime-rpc": "^2.9.1",
33
- "@protobuf-ts/twirp-transport": "^2.9.1",
31
+ "@protobuf-ts/runtime": "^2.9.3",
32
+ "@protobuf-ts/runtime-rpc": "^2.9.3",
33
+ "@protobuf-ts/twirp-transport": "^2.9.3",
34
34
  "@types/ws": "^8.5.7",
35
35
  "axios": "^1.6.0",
36
36
  "base64-js": "^1.5.1",
package/src/Call.ts CHANGED
@@ -4,8 +4,6 @@ import {
4
4
  getGenericSdp,
5
5
  isSfuEvent,
6
6
  Publisher,
7
- SfuEventKinds,
8
- SfuEventListener,
9
7
  Subscriber,
10
8
  } from './rtc';
11
9
  import { muteTypeToTrackType } from './rtc/helpers/tracks';
@@ -108,10 +106,8 @@ import {
108
106
  sleep,
109
107
  } from './coordinator/connection/utils';
110
108
  import {
111
- CallEventHandler,
112
- CallEventTypes,
113
- EventHandler,
114
- EventTypes,
109
+ AllCallEvents,
110
+ CallEventListener,
115
111
  Logger,
116
112
  StreamCallEvent,
117
113
  } from './coordinator/connection/types';
@@ -222,7 +218,7 @@ export class Call {
222
218
  private readonly leaveCallHooks: Set<Function> = new Set();
223
219
 
224
220
  private readonly streamClientBasePath: string;
225
- private streamClientEventHandlers = new Map<Function, CallEventHandler>();
221
+ private streamClientEventHandlers = new Map<Function, () => void>();
226
222
 
227
223
  /**
228
224
  * Constructs a new `Call` instance.
@@ -287,7 +283,7 @@ export class Call {
287
283
 
288
284
  this.camera = new CameraManager(this);
289
285
  this.microphone = new MicrophoneManager(this);
290
- this.speaker = new SpeakerManager();
286
+ this.speaker = new SpeakerManager(this);
291
287
  this.screenShare = new ScreenShareManager(this);
292
288
  }
293
289
 
@@ -411,55 +407,54 @@ export class Call {
411
407
 
412
408
  /**
413
409
  * You can subscribe to WebSocket events provided by the API. To remove a subscription, call the `off` method.
414
- * Please note that subscribing to WebSocket events is an advanced use-case, for most use-cases it should be enough to watch for changes in the [reactive state store](./StreamVideoClient.md/#readonlystatestore).
415
- * @param eventName
416
- * @param fn
417
- * @returns a function which can be called to unsubscribe from the given event(s)
418
- */
419
- on(eventName: SfuEventKinds, fn: SfuEventListener): () => void;
420
- on(eventName: EventTypes, fn: CallEventHandler): () => void;
421
- on(
422
- eventName: SfuEventKinds | EventTypes,
423
- fn: SfuEventListener | CallEventHandler,
424
- ) {
410
+ * Please note that subscribing to WebSocket events is an advanced use-case.
411
+ * For most use-cases, it should be enough to watch for state changes.
412
+ *
413
+ * @param eventName the event name.
414
+ * @param fn the event handler.
415
+ */
416
+ on = <E extends keyof AllCallEvents>(
417
+ eventName: E,
418
+ fn: CallEventListener<E>,
419
+ ) => {
425
420
  if (isSfuEvent(eventName)) {
426
- return this.dispatcher.on(eventName, fn as SfuEventListener);
427
- } else {
428
- const eventHandler: CallEventHandler = (event: StreamCallEvent) => {
429
- if (event.call_cid && event.call_cid === this.cid) {
430
- (fn as EventHandler)(event);
431
- }
432
- };
433
- this.streamClientEventHandlers.set(fn, eventHandler);
434
-
435
- return this.streamClient.on(eventName, eventHandler as EventHandler);
421
+ return this.dispatcher.on(eventName, fn);
436
422
  }
437
- }
423
+
424
+ const offHandler = this.streamClient.on(eventName, (e) => {
425
+ const event = e as StreamCallEvent;
426
+ if (event.call_cid && event.call_cid === this.cid) {
427
+ fn(event as AllCallEvents[E]);
428
+ }
429
+ });
430
+
431
+ // keep the 'off' reference returned by the stream client
432
+ this.streamClientEventHandlers.set(fn, offHandler);
433
+ return () => {
434
+ this.off(eventName, fn);
435
+ };
436
+ };
438
437
 
439
438
  /**
440
439
  * Remove subscription for WebSocket events that were created by the `on` method.
441
- * @param eventName
442
- * @param fn
443
- * @returns
440
+ *
441
+ * @param eventName the event name.
442
+ * @param fn the event handler.
444
443
  */
445
- off(eventName: SfuEventKinds, fn: SfuEventListener): void;
446
- off(eventName: CallEventTypes, fn: CallEventHandler): void;
447
- off(
448
- eventName: SfuEventKinds | CallEventTypes,
449
- fn: SfuEventListener | CallEventHandler,
450
- ) {
444
+ off = <E extends keyof AllCallEvents>(
445
+ eventName: E,
446
+ fn: CallEventListener<E>,
447
+ ) => {
451
448
  if (isSfuEvent(eventName)) {
452
- return this.dispatcher.off(eventName, fn as SfuEventListener);
453
- } else {
454
- const registeredEventHandler = this.streamClientEventHandlers.get(fn);
455
- if (registeredEventHandler) {
456
- return this.streamClient.off(
457
- eventName,
458
- registeredEventHandler as EventHandler,
459
- );
460
- }
449
+ return this.dispatcher.off(eventName, fn);
461
450
  }
462
- }
451
+
452
+ // unsubscribe from the stream client event by using the 'off' reference
453
+ const registeredOffHandler = this.streamClientEventHandlers.get(fn);
454
+ if (registeredOffHandler) {
455
+ registeredOffHandler();
456
+ }
457
+ };
463
458
 
464
459
  /**
465
460
  * Leave the call and stop the media streams that were published by the call.
@@ -858,8 +853,7 @@ export class Call {
858
853
  sfuClient.signalReady.then(() => {
859
854
  // register a handler for the "goAway" event
860
855
  const unregisterGoAway = this.dispatcher.on('goAway', (event) => {
861
- if (event.eventPayload.oneofKind !== 'goAway') return;
862
- const { reason } = event.eventPayload.goAway;
856
+ const { reason } = event;
863
857
  this.logger(
864
858
  'info',
865
859
  `[Migration]: Going away from SFU... Reason: ${GoAwayReason[reason]}`,
@@ -1132,10 +1126,9 @@ export class Call {
1132
1126
  private waitForJoinResponse = (timeout: number = 5000) => {
1133
1127
  return new Promise<JoinResponse>((resolve, reject) => {
1134
1128
  const unsubscribe = this.on('joinResponse', (event) => {
1135
- if (event.eventPayload.oneofKind !== 'joinResponse') return;
1136
1129
  clearTimeout(timeoutId);
1137
1130
  unsubscribe();
1138
- resolve(event.eventPayload.joinResponse);
1131
+ resolve(event);
1139
1132
  });
1140
1133
 
1141
1134
  const timeoutId = setTimeout(() => {
@@ -185,9 +185,7 @@ export class StreamSfuClient {
185
185
  // connection is established. In that case, those events (ICE candidates)
186
186
  // need to be buffered and later added to the appropriate PeerConnection
187
187
  // once the remoteDescription is known and set.
188
- this.unsubscribeIceTrickle = dispatcher.on('iceTrickle', (e) => {
189
- if (e.eventPayload.oneofKind !== 'iceTrickle') return;
190
- const { iceTrickle } = e.eventPayload;
188
+ this.unsubscribeIceTrickle = dispatcher.on('iceTrickle', (iceTrickle) => {
191
189
  this.iceTrickleBuffer.push(iceTrickle);
192
190
  });
193
191
 
@@ -14,10 +14,9 @@ import type {
14
14
  QueryCallsRequest,
15
15
  QueryCallsResponse,
16
16
  } from './gen/coordinator';
17
- import type {
18
- ConnectionChangedEvent,
19
- EventHandler,
20
- EventTypes,
17
+ import {
18
+ AllClientEvents,
19
+ ClientEventListener,
21
20
  Logger,
22
21
  LogLevel,
23
22
  StreamClientOptions,
@@ -167,8 +166,7 @@ export class StreamVideoClient {
167
166
  }
168
167
 
169
168
  this.eventHandlersToUnregister.push(
170
- this.on('connection.changed', (e) => {
171
- const event = e as ConnectionChangedEvent;
169
+ this.on('connection.changed', (event) => {
172
170
  if (event.online) {
173
171
  const callsToReWatch = this.writeableStateStore.calls
174
172
  .filter((call) => call.watching)
@@ -197,7 +195,6 @@ export class StreamVideoClient {
197
195
 
198
196
  this.eventHandlersToUnregister.push(
199
197
  this.on('call.created', (event) => {
200
- if (event.type !== 'call.created') return;
201
198
  const { call, members } = event;
202
199
  if (user.id === call.created_by.id) {
203
200
  this.logger(
@@ -222,7 +219,6 @@ export class StreamVideoClient {
222
219
 
223
220
  this.eventHandlersToUnregister.push(
224
221
  this.on('call.ring', async (event) => {
225
- if (event.type !== 'call.ring') return;
226
222
  const { call, members } = event;
227
223
  if (user.id === call.created_by.id) {
228
224
  this.logger(
@@ -290,18 +286,24 @@ export class StreamVideoClient {
290
286
  * @param callback the callback which will be called when the event is emitted.
291
287
  * @returns an unsubscribe function.
292
288
  */
293
- on = (eventName: EventTypes, callback: EventHandler) => {
289
+ on = <E extends keyof AllClientEvents>(
290
+ eventName: E,
291
+ callback: ClientEventListener<E>,
292
+ ) => {
294
293
  return this.streamClient.on(eventName, callback);
295
294
  };
296
295
 
297
296
  /**
298
297
  * Remove subscription for WebSocket events that were created by the `on` method.
299
298
  *
300
- * @param event the event name.
299
+ * @param eventName the event name.
301
300
  * @param callback the callback which was passed to the `on` method.
302
301
  */
303
- off = (event: string, callback: EventHandler) => {
304
- return this.streamClient.off(event, callback);
302
+ off = <E extends keyof AllClientEvents>(
303
+ eventName: E,
304
+ callback: ClientEventListener<E>,
305
+ ) => {
306
+ return this.streamClient.off(eventName, callback);
305
307
  };
306
308
 
307
309
  /**
@@ -435,7 +437,6 @@ export class StreamVideoClient {
435
437
  *
436
438
  * @param {string} id The device id
437
439
  * @param {string} [userID] The user id. Only specify this for serverside requests
438
- *
439
440
  */
440
441
  removeDevice = async (id: string, userID?: string) => {
441
442
  return await this.streamClient.delete('/devices', {