Skip to content

Commit

Permalink
typescript: Strict mode enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
bekriebel committed Aug 24, 2021
1 parent e0e5722 commit 88c92c5
Show file tree
Hide file tree
Showing 10 changed files with 373 additions and 167 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"livekit-server-sdk": "^0.5.1"
},
"devDependencies": {
"@league-of-foundry-developers/foundry-vtt-types": "^0.8.9-0",
"@league-of-foundry-developers/foundry-vtt-types": "^0.8.9-2",
"buffer": "^6.0.3",
"copy-webpack-plugin": "^9.0.1",
"crypto-browserify": "^3.12.0",
Expand Down
105 changes: 67 additions & 38 deletions src/LiveKitAVClient.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { connect as liveKitConnect, LogLevel, RoomState } from "livekit-client";
import {
connect as liveKitConnect,
ConnectOptions,
LocalTrack,
LogLevel,
RoomState,
} from "livekit-client";
import { LANG_NAME, MODULE_NAME } from "./utils/constants";
import * as log from "./utils/logging";

import LiveKitClient from "./LiveKitClient";
import { getGame } from "./utils/helpers";
import { ConnectionSettings } from "../types/avclient-livekit";

/**
* An AVClient implementation that uses WebRTC and the LiveKit library.
Expand All @@ -12,11 +19,11 @@ import { getGame } from "./utils/helpers";
* @param {AVSettings} settings The audio/video settings being used
*/
export default class LiveKitAVClient extends AVClient {
room: any;
_liveKitClient: any;
room: string | null;
_liveKitClient: LiveKitClient;
audioBroadcastEnabled: boolean;

constructor(master, settings) {
constructor(master: AVMaster, settings: AVSettings) {
super(master, settings);

this._liveKitClient = new LiveKitClient(this);
Expand All @@ -30,32 +37,33 @@ export default class LiveKitAVClient extends AVClient {
* Is audio broadcasting push-to-talk enabled?
* @returns {boolean}
*/
get isVoicePTT() {
get isVoicePTT(): boolean {
return this.settings.client.voice.mode === "ptt";
}

/**
* Is audio broadcasting always enabled?
* @returns {boolean}
*/
get isVoiceAlways() {
get isVoiceAlways(): boolean {
return this.settings.client.voice.mode === "always";
}

/**
* Is audio broadcasting voice-activation enabled?
* @returns {boolean}
*/
get isVoiceActivated() {
return this.settings.client.voice.mode === "activity";
get isVoiceActivated(): boolean {
// This module does not allow for voice activation
return false;
}

/**
* Is the current user muted?
* @returns {boolean}
*/
get isMuted() {
return this.settings.client.users[getGame().user?.id || ""]?.muted;
get isMuted(): boolean {
return this.settings.client.users[getGame().user?.id || ""]?.muted || false;
}

/* -------------------------------------------- */
Expand All @@ -67,7 +75,7 @@ export default class LiveKitAVClient extends AVClient {
* This will be called only once when the Game object is first set-up.
* @return {Promise<void>}
*/
async initialize() {
async initialize(): Promise<void> {
log.debug("LiveKitAVClient initialize");

if (this.settings.get("client", "voice.mode") === "activity") {
Expand All @@ -89,10 +97,13 @@ export default class LiveKitAVClient extends AVClient {
* This function should return a boolean for whether the connection attempt was successful.
* @return {Promise<boolean>} Was the connection attempt successful?
*/
async connect() {
async connect(): Promise<boolean> {
log.debug("LiveKitAVClient connect");

const connectionSettings: any = this.settings.get("world", "server");
const connectionSettings = this.settings.get(
"world",
"server"
) as ConnectionSettings;

// Set a room name if one doesn't yet exist
if (!connectionSettings.room) {
Expand All @@ -105,31 +116,46 @@ export default class LiveKitAVClient extends AVClient {
log.debug("Meeting room name:", this.room);

// Set the user's metadata
const metadata = {
const metadata = JSON.stringify({
fvttUserId: getGame().user?.id,
};
});

const userName = getGame().user?.name;

if (!this.room || !userName) {
log.error(
"Missing required room information, cannot connect. room:",
this.room,
"username:",
userName
);
return false;
}

// Get an access token
const accessToken = this._liveKitClient.getAccessToken(
connectionSettings.username,
connectionSettings.password,
this.room,
getGame().user?.name,
userName,
metadata
);

const localTracks: any = [];
const localTracks: LocalTrack[] = [];
if (this._liveKitClient.audioTrack)
localTracks.push(this._liveKitClient.audioTrack);
if (this._liveKitClient.videoTrack)
localTracks.push(this._liveKitClient.videoTrack);

// Set the livekit connection options
const livekitConnectionOptions: any = {
const livekitConnectionOptions: ConnectOptions = {
tracks: localTracks,
};

if (getGame().settings.get(MODULE_NAME, "livekitTrace")) {
if (
getGame().settings.get(MODULE_NAME, "debug") &&
getGame().settings.get(MODULE_NAME, "livekitTrace")
) {
log.debug("Setting livekit trace logging");
livekitConnectionOptions.logLevel = LogLevel.trace;
}
Expand Down Expand Up @@ -173,7 +199,7 @@ export default class LiveKitAVClient extends AVClient {
* This function should return a boolean for whether a valid disconnection occurred.
* @return {Promise<boolean>} Did a disconnection occur?
*/
async disconnect() {
async disconnect(): Promise<boolean> {
log.debug("LiveKitAVClient disconnect");
if (
this._liveKitClient.liveKitRoom &&
Expand All @@ -196,7 +222,7 @@ export default class LiveKitAVClient extends AVClient {
* Each object key should be a device id and the key should be a human-readable label.
* @returns {Promise<{object}>}
*/
async getAudioSinks() {
async getAudioSinks(): Promise<Record<string, string>> {
return this._getSourcesOfType("audiooutput");
}

Expand All @@ -207,7 +233,7 @@ export default class LiveKitAVClient extends AVClient {
* Each object key should be a device id and the key should be a human-readable label.
* @returns {Promise<{object}>}
*/
async getAudioSources() {
async getAudioSources(): Promise<Record<string, string>> {
return this._getSourcesOfType("audioinput");
}

Expand All @@ -218,7 +244,7 @@ export default class LiveKitAVClient extends AVClient {
* Each object key should be a device id and the key should be a human-readable label.
* @returns {Promise<{object}>}
*/
async getVideoSources() {
async getVideoSources(): Promise<Record<string, string>> {
return this._getSourcesOfType("videoinput");
}

Expand All @@ -230,9 +256,11 @@ export default class LiveKitAVClient extends AVClient {
* @returns {Promise<{object}>}
* @private
*/
async _getSourcesOfType(kind) {
async _getSourcesOfType(
kind: MediaDeviceKind
): Promise<Record<string, string>> {
const devices = await navigator.mediaDevices.enumerateDevices();
return devices.reduce((obj, device) => {
return devices.reduce((obj: Record<string, string>, device) => {
if (device.kind === kind) {
obj[device.deviceId] =
device.label || getGame().i18n.localize("WEBRTC.UnknownDevice");
Expand All @@ -250,7 +278,7 @@ export default class LiveKitAVClient extends AVClient {
* The current user should also be included as a connected user in addition to all peers.
* @return {string[]} The connected User IDs
*/
getConnectedUsers() {
getConnectedUsers(): string[] {
const connectedUsers: string[] = Array.from(
this._liveKitClient.liveKitParticipants.keys()
);
Expand All @@ -267,7 +295,7 @@ export default class LiveKitAVClient extends AVClient {
* @return {MediaStream|null} The MediaStream for the user, or null if the user does not have
* one
*/
getMediaStreamForUser() {
getMediaStreamForUser(): MediaStream | null {
log.debug("getMediaStreamForUser called but is not used with", MODULE_NAME);
return null;
}
Expand All @@ -278,7 +306,7 @@ export default class LiveKitAVClient extends AVClient {
* Is outbound audio enabled for the current user?
* @return {boolean}
*/
isAudioEnabled() {
isAudioEnabled(): boolean {
return this.audioBroadcastEnabled;
}

Expand All @@ -288,7 +316,7 @@ export default class LiveKitAVClient extends AVClient {
* Is outbound video enabled for the current user?
* @return {boolean}
*/
isVideoEnabled() {
isVideoEnabled(): boolean {
let videoTrackEnabled = false;
if (
this._liveKitClient.videoTrack &&
Expand All @@ -308,7 +336,7 @@ export default class LiveKitAVClient extends AVClient {
* @param {boolean} enable Whether the outbound audio track should be enabled (true) or
* disabled (false)
*/
toggleAudio(enable) {
toggleAudio(enable: boolean): void {
log.debug("Toggling audio:", enable);

// If "always on" broadcasting is not enabled, don't proceed
Expand All @@ -326,7 +354,7 @@ export default class LiveKitAVClient extends AVClient {
* activation modes.
* @param {boolean} broadcast Whether outbound audio should be sent to connected peers or not?
*/
toggleBroadcast(broadcast) {
toggleBroadcast(broadcast: boolean): void {
log.debug("Toggling broadcast audio:", broadcast);

this.audioBroadcastEnabled = broadcast;
Expand All @@ -342,7 +370,7 @@ export default class LiveKitAVClient extends AVClient {
* @param {boolean} enable Whether the outbound video track should be enabled (true) or
* disabled (false)
*/
toggleVideo(enable) {
toggleVideo(enable: boolean): void {
if (!this._liveKitClient.videoTrack) {
log.debug("toggleVideo called but no video track available");
return;
Expand All @@ -364,7 +392,10 @@ export default class LiveKitAVClient extends AVClient {
* @param {string} userId The User ID to set to the element
* @param {HTMLVideoElement} videoElement The HTMLVideoElement to which the video should be set
*/
async setUserVideo(userId, videoElement) {
async setUserVideo(
userId: string,
videoElement: HTMLVideoElement
): Promise<void> {
log.debug("Setting video element:", videoElement, "for user:", userId);

// Make sure the room is active first
Expand Down Expand Up @@ -422,19 +453,17 @@ export default class LiveKitAVClient extends AVClient {
* Handle changes to A/V configuration settings.
* @param {object} changed The settings which have changed
*/
onSettingsChanged(changed) {
onSettingsChanged(changed: DeepPartial<AVSettings.Settings>): void {
log.debug("onSettingsChanged:", changed);
const keys = new Set(Object.keys(foundry.utils.flattenObject(changed)));

// Change audio source
const audioSourceChange = ["client.audioSrc"].some((k) => keys.has(k));
if (audioSourceChange)
this._liveKitClient.changeAudioSource(changed.client.audioSrc);
if (audioSourceChange) this._liveKitClient.changeAudioSource();

// Change video source
const videoSourceChange = ["client.videoSrc"].some((k) => keys.has(k));
if (videoSourceChange)
this._liveKitClient.changeVideoSource(changed.client.videoSrc);
if (videoSourceChange) this._liveKitClient.changeVideoSource();

// Change voice broadcasting mode
const modeChange = [
Expand Down
Loading

0 comments on commit 88c92c5

Please sign in to comment.