Skip to content

Commit

Permalink
Use explicit defaults for room and connect options (#436)
Browse files Browse the repository at this point in the history
* use explicit defaults for room and connect options

* indicate reconnect

* use user facing room options in constructor

* adaptiveStream default to false

* changeset

* consolidate defaults in one file
  • Loading branch information
lukasIO committed Sep 13, 2022
1 parent 4004426 commit 1715877
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 55 deletions.
5 changes: 5 additions & 0 deletions .changeset/ten-oranges-sip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'livekit-client': patch
---

Use explicit defaults for room and connect options
45 changes: 20 additions & 25 deletions src/api/SignalClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { getClientInfo, sleep } from '../room/utils';

// internal options
interface ConnectOpts {
autoSubscribe?: boolean;
autoSubscribe: boolean;
/** internal */
reconnect?: boolean;

Expand All @@ -49,7 +49,7 @@ interface ConnectOpts {

// public options
export interface SignalOptions {
autoSubscribe?: boolean;
autoSubscribe: boolean;
/** @deprecated */
publishOnly?: string;
adaptiveStream?: boolean;
Expand Down Expand Up @@ -128,6 +128,8 @@ export class SignalClient {

ws?: WebSocket;

private options?: SignalOptions;

private pingTimeout: ReturnType<typeof setTimeout> | undefined;

private pingTimeoutDuration: number | undefined;
Expand All @@ -147,33 +149,27 @@ export class SignalClient {
async join(
url: string,
token: string,
opts?: SignalOptions,
opts: SignalOptions,
abortSignal?: AbortSignal,
): Promise<JoinResponse> {
// during a full reconnect, we'd want to start the sequence even if currently
// connected
this.isConnected = false;
const res = await this.connect(
url,
token,
{
autoSubscribe: opts?.autoSubscribe,
publishOnly: opts?.publishOnly,
adaptiveStream: opts?.adaptiveStream,
},
abortSignal,
);
this.options = opts;
const res = await this.connect(url, token, opts, abortSignal);
return res as JoinResponse;
}

async reconnect(url: string, token: string, sid?: string): Promise<void> {
if (!this.options) {
log.warn('attempted to reconnect without signal options being set, ignoring');
return;
}
this.isReconnecting = true;
// clear ping interval and restart it once reconnected
this.clearPingInterval();
await this.connect(url, token, {
reconnect: true,
sid,
});

await this.connect(url, token, { ...this.options, reconnect: true, sid });
}

connect(
Expand Down Expand Up @@ -607,20 +603,19 @@ export function toProtoSessionDescription(
return sd;
}

function createConnectionParams(token: string, info: ClientInfo, opts?: ConnectOpts): string {
function createConnectionParams(token: string, info: ClientInfo, opts: ConnectOpts): string {
const params = new URLSearchParams();
params.set('access_token', token);

// opts
if (opts?.reconnect) {
if (opts.reconnect) {
params.set('reconnect', '1');
if (opts?.sid) {
if (opts.sid) {
params.set('sid', opts.sid);
}
}
if (opts?.autoSubscribe !== undefined) {
params.set('auto_subscribe', opts.autoSubscribe ? '1' : '0');
}

params.set('auto_subscribe', opts.autoSubscribe ? '1' : '0');

// ClientInfo
params.set('sdk', 'js');
Expand All @@ -642,11 +637,11 @@ function createConnectionParams(token: string, info: ClientInfo, opts?: ConnectO
params.set('browser_version', info.browserVersion);
}

if (opts?.publishOnly !== undefined) {
if (opts.publishOnly !== undefined) {
params.set('publish', opts.publishOnly);
}

if (opts?.adaptiveStream) {
if (opts.adaptiveStream) {
params.set('adaptive_stream', '1');
}

Expand Down
28 changes: 19 additions & 9 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import type { AdaptiveStreamSettings } from './room/track/types';
import type { ReconnectPolicy } from './room/ReconnectPolicy';

/**
* Options for when creating a new room
* @internal
*/
export interface RoomOptions {
export interface InternalRoomOptions {
/**
* AdaptiveStream lets LiveKit automatically manage quality of subscribed
* video tracks to optimize for bandwidth and CPU.
Expand All @@ -19,14 +19,14 @@ export interface RoomOptions {
* When none of the video elements are visible, it'll temporarily pause
* the data flow until they are visible again.
*/
adaptiveStream?: AdaptiveStreamSettings | boolean;
adaptiveStream: AdaptiveStreamSettings | boolean;

/**
* enable Dynacast, off by default. With Dynacast dynamically pauses
* video layers that are not being consumed by any subscribers, significantly
* reducing publishing CPU and bandwidth usage.
*/
dynacast?: boolean;
dynacast: boolean;

/**
* default options to use when capturing user's audio
Expand All @@ -47,7 +47,7 @@ export interface RoomOptions {
* should local tracks be stopped when they are unpublished. defaults to true
* set this to false if you would prefer to clean up unpublished local tracks manually.
*/
stopLocalTrackOnUnpublish?: boolean;
stopLocalTrackOnUnpublish: boolean;

/**
* @internal
Expand All @@ -58,15 +58,20 @@ export interface RoomOptions {
/**
* policy to use when attempting to reconnect
*/
reconnectPolicy?: ReconnectPolicy;
reconnectPolicy: ReconnectPolicy;
}

/**
* Options for Room.connect()
* Options for when creating a new room
*/
export interface RoomOptions extends Partial<InternalRoomOptions> {}

/**
* @internal
*/
export interface RoomConnectOptions {
export interface InternalRoomConnectOptions {
/** autosubscribe to room tracks after joining, defaults to true */
autoSubscribe?: boolean;
autoSubscribe: boolean;

/**
* use to override any RTCConfiguration options.
Expand All @@ -79,3 +84,8 @@ export interface RoomConnectOptions {
*/
publishOnly?: string;
}

/**
* Options for Room.connect()
*/
export interface RoomConnectOptions extends Partial<InternalRoomConnectOptions> {}
13 changes: 8 additions & 5 deletions src/room/RTCEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { EventEmitter } from 'events';
import type TypedEventEmitter from 'typed-emitter';
import { SignalClient, SignalOptions } from '../api/SignalClient';
import log from '../logger';
import type { RoomOptions } from '../options';
import type { InternalRoomOptions } from '../options';
import {
ClientConfigSetting,
ClientConfiguration,
Expand All @@ -20,7 +20,6 @@ import {
SignalTarget,
TrackPublishedResponse,
} from '../proto/livekit_rtc';
import DefaultReconnectPolicy from './DefaultReconnectPolicy';
import {
ConnectionError,
NegotiationError,
Expand Down Expand Up @@ -122,17 +121,17 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit

private participantSid?: string;

constructor(private options: RoomOptions) {
constructor(private options: InternalRoomOptions) {
super();
this.client = new SignalClient();
this.client.signalLatency = this.options.expSignalLatency;
this.reconnectPolicy = this.options.reconnectPolicy ?? new DefaultReconnectPolicy();
this.reconnectPolicy = this.options.reconnectPolicy;
}

async join(
url: string,
token: string,
opts?: SignalOptions,
opts: SignalOptions,
abortSignal?: AbortSignal,
): Promise<JoinResponse> {
this.url = url;
Expand Down Expand Up @@ -774,6 +773,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit

let joinResponse: JoinResponse;
try {
if (!this.signalOpts) {
log.warn('attempted connection restart, without signal options present');
throw new SignalReconnectError();
}
joinResponse = await this.join(this.url, this.token, this.signalOpts);
} catch (e) {
throw new SignalReconnectError();
Expand Down
37 changes: 23 additions & 14 deletions src/room/Room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import { EventEmitter } from 'events';
import type TypedEmitter from 'typed-emitter';
import { toProtoSessionDescription } from '../api/SignalClient';
import log from '../logger';
import type { RoomConnectOptions, RoomOptions } from '../options';
import type {
InternalRoomConnectOptions,
InternalRoomOptions,
RoomConnectOptions,
RoomOptions,
} from '../options';
import {
DataPacket_Kind,
DisconnectReason,
Expand All @@ -21,6 +26,13 @@ import {
StreamStateUpdate,
SubscriptionPermissionUpdate,
} from '../proto/livekit_rtc';
import {
roomConnectOptionDefaults,
roomOptionDefaults,
audioDefaults,
publishDefaults,
videoDefaults,
} from './defaults';
import DeviceManager from './DeviceManager';
import { ConnectionError, UnsupportedServer } from './errors';
import { EngineEvent, ParticipantEvent, RoomEvent, TrackEvent } from './events';
Expand All @@ -29,7 +41,6 @@ import type Participant from './participant/Participant';
import type { ConnectionQuality } from './participant/Participant';
import RemoteParticipant from './participant/RemoteParticipant';
import RTCEngine, { maxICEConnectTimeout } from './RTCEngine';
import { audioDefaults, publishDefaults, videoDefaults } from './track/defaults';
import LocalAudioTrack from './track/LocalAudioTrack';
import type LocalTrackPublication from './track/LocalTrackPublication';
import LocalVideoTrack from './track/LocalVideoTrack';
Expand Down Expand Up @@ -87,12 +98,12 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
metadata: string | undefined = undefined;

/** options of room */
options: RoomOptions;
options: InternalRoomOptions;

private identityToSid: Map<string, string>;

/** connect options of room */
private connOptions?: RoomConnectOptions;
private connOptions?: InternalRoomConnectOptions;

private audioEnabled = true;

Expand All @@ -115,7 +126,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
super();
this.participants = new Map();
this.identityToSid = new Map();
this.options = options || {};
this.options = { ...roomOptionDefaults, ...options };

this.options.audioCaptureDefaults = {
...audioDefaults,
Expand Down Expand Up @@ -229,23 +240,21 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)

this.acquireAudioContext();

if (opts?.rtcConfig) {
this.engine.rtcConfig = opts.rtcConfig;
}
this.connOptions = { ...roomConnectOptionDefaults, ...opts } as InternalRoomConnectOptions;

this.connOptions = opts;
if (this.connOptions.rtcConfig) {
this.engine.rtcConfig = this.connOptions.rtcConfig;
}

try {
const joinResponse = await this.engine.join(
url,
token,
{
autoSubscribe: opts?.autoSubscribe,
publishOnly: opts?.publishOnly,
autoSubscribe: this.connOptions.autoSubscribe,
publishOnly: this.connOptions.publishOnly,
adaptiveStream:
typeof this.options?.adaptiveStream === 'object'
? true
: this.options?.adaptiveStream,
typeof this.options.adaptiveStream === 'object' ? true : this.options.adaptiveStream,
},
this.abortController.signal,
);
Expand Down
15 changes: 14 additions & 1 deletion src/room/track/defaults.ts → src/room/defaults.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type { InternalRoomConnectOptions, InternalRoomOptions } from '../options';
import DefaultReconnectPolicy from './DefaultReconnectPolicy';
import {
AudioCaptureOptions,
AudioPresets,
ScreenSharePresets,
TrackPublishDefaults,
VideoCaptureOptions,
VideoPresets,
} from './options';
} from './track/options';

export const publishDefaults: TrackPublishDefaults = {
audioBitrate: AudioPresets.speech.maxBitrate,
Expand All @@ -26,3 +28,14 @@ export const audioDefaults: AudioCaptureOptions = {
export const videoDefaults: VideoCaptureOptions = {
resolution: VideoPresets.h720.resolution,
};

export const roomOptionDefaults: InternalRoomOptions = {
adaptiveStream: false,
dynacast: false,
stopLocalTrackOnUnpublish: false,
reconnectPolicy: new DefaultReconnectPolicy(),
} as const;

export const roomConnectOptionDefaults: InternalRoomConnectOptions = {
autoSubscribe: true,
} as const;
2 changes: 1 addition & 1 deletion src/room/track/create.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import DeviceManager from '../DeviceManager';
import { TrackInvalidError } from '../errors';
import { mediaTrackToLocalTrack } from '../participant/publishUtils';
import { audioDefaults, videoDefaults } from './defaults';
import { audioDefaults, videoDefaults } from '../defaults';
import LocalAudioTrack from './LocalAudioTrack';
import type LocalTrack from './LocalTrack';
import LocalVideoTrack from './LocalVideoTrack';
Expand Down

0 comments on commit 1715877

Please sign in to comment.