Skip to content

Commit

Permalink
fixes and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
itzTheMeow committed Sep 16, 2023
1 parent 600013f commit a4c4967
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 38 deletions.
2 changes: 1 addition & 1 deletion voice/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"mediasoup-client": "^3.6.84",
"msc-node": "^0.0.10",
"prism-media": "github:itzTheMeow/prism-media",
"revkit": "^1.1.3"
"revkit": "^1.1.8"
},
"devDependencies": {
"@types/node": "^20.1.1",
Expand Down
8 changes: 4 additions & 4 deletions voice/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 14 additions & 7 deletions voice/src/Signaling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default class Signaling<Platform extends MSCPlatform> extends EventEmitte
error: (event: WebSocket.Event) => void;
data: (data: any) => void;
}> {
/** Vortex WebSocket */
public ws: WebSocket | null = null;
/** Index for pending packets. */
private index: number = 0;
Expand All @@ -27,14 +28,19 @@ export default class Signaling<Platform extends MSCPlatform> extends EventEmitte
super();
}

connected(): boolean {
/** If the vortex socket is connected. */
get connected(): boolean {
return (
!!this.ws &&
this.ws.readyState !== WebSocket.CLOSING &&
this.ws.readyState !== WebSocket.CLOSED
);
}

/**
* Connects to vortex.
* @param address The socket address to use.
*/
connect(address: string): Promise<void> {
this.disconnect();
this.ws = new WebSocket(address);
Expand All @@ -59,13 +65,9 @@ export default class Signaling<Platform extends MSCPlatform> extends EventEmitte
});
}

/** Disconnects the websocket. */
disconnect() {
if (
this.ws &&
this.ws.readyState !== WebSocket.CLOSED &&
this.ws.readyState !== WebSocket.CLOSING
)
this.ws.close(1000);
if (this.connected) this.ws.close(1000);
}

private parseData(event: WebSocket.MessageEvent) {
Expand Down Expand Up @@ -117,10 +119,15 @@ export default class Signaling<Platform extends MSCPlatform> extends EventEmitte
});
}

/** Authenticates with vortex. */
public authenticate(token: string, roomId: string): Promise<AuthenticationResult<Platform>> {
return this.sendRequest(WSCommands.Authenticate, { token, roomId });
}

/**
* Gets information about the currently joined channel.
* @returns Room info.
*/
public async roomInfo(): Promise<Room> {
const room = await this.sendRequest(WSCommands.RoomInfo);
return {
Expand Down
39 changes: 23 additions & 16 deletions voice/src/VoiceClient.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import EventEmitter from "eventemitter3";
import type * as MSCBrowser from "mediasoup-client";
import type * as MSCNode from "msc-node";
import { Client, MiniMapEmitter } from "revkit";
import { Client, DMChannel, GroupDMChannel, MiniMapEmitter, VoiceChannel } from "revkit";
import Signaling from "./Signaling";
import type { MSCPlatform, MediaSoup } from "./msc";
import {
RevkitClientOptions,
VoiceClientOptions,
VoiceStatus,
WSEvents,
type ProduceType,
Expand Down Expand Up @@ -62,8 +62,7 @@ export class VoiceClient<
return this.status == VoiceStatus.CONNECTED && !!this.channelID;
}

public token: string;
public type: "user" | "bot";
private sessionDetails: { token: string; type: "user" | "bot" } | null = null;
public client = new Client();
public channelID: string | null = null;
public get channel() {
Expand All @@ -78,7 +77,7 @@ export class VoiceClient<
*/
constructor(
public readonly platform: Platform,
client: Client | RevkitClientOptions,
client: Client | VoiceClientOptions,
private msc: Platform extends "node" ? typeof MSCNode : typeof MSCBrowser,
private createDevice: () => MSC["Device"],
private consumeTrack?: VoiceClientConsumer<Platform>
Expand All @@ -87,12 +86,10 @@ export class VoiceClient<
this.supported = this.msc.detectDevice() !== undefined;
if (client instanceof Client) {
this.client = client;
this.token = this.client.session.token;
this.type = this.client.session.type;
this.sessionDetails = { token: this.client.session.token, type: this.client.session.type };
} else {
this.client = new Client(client.baseURL ? { apiURL: client.baseURL } : undefined);
this.token = client.token;
this.type = client.type;
this.client = new Client(client.apiURL ? { apiURL: client.apiURL } : undefined);
this.sessionDetails = { token: client.token, type: client.type };
}

this.signaling.on(
Expand Down Expand Up @@ -202,7 +199,7 @@ export class VoiceClient<
}

public disconnectTransport(error?: VoiceError, forceDisconnect = false) {
if (!this.signaling.connected() && !forceDisconnect) return;
if (!this.signaling.connected && !forceDisconnect) return;
this.signaling.disconnect();
this.participants.clear();
this.participants.fireUpdate([]);
Expand Down Expand Up @@ -390,18 +387,28 @@ export class VoiceClient<
this.emit("status", status);
}

public async connect(channelID?: string) {
/**
* Connect to a channel.
* @param channel Voice channel, DM/GDM, or channel ID.
* @returns Itself.
*/
public async connect(channelResolvable: VoiceChannel | DMChannel | GroupDMChannel | string) {
if (!this.client.session) {
await this.client.login(this.token, this.type, false);
await this.client.users.fetch("@me");
if (this.sessionDetails) {
await this.client.login(this.sessionDetails.token, this.sessionDetails.type, false);
await this.client.users.fetch("@me");
}
}

const channel =
channelID == undefined ? this.channel : await this.client.channels.fetch(channelID);
typeof channelResolvable == "string"
? await this.client.channels.fetch(channelResolvable)
: channelResolvable;

if (this.status > VoiceStatus.READY) return;
if (!this.supported) throw new Error("RTC is unavailable.");
if (!channel.isVoice()) throw new Error("Not a voice channel.");
if (!channel.isVoice() && !channel.isDMBased())
throw new Error("Not a voice or (Group) DM channel.");
await this.client.fetchConfiguration();
const vortexURL = this.client.config?.features.voso?.enabled
? this.client.config.features.voso.ws
Expand Down
7 changes: 4 additions & 3 deletions voice/src/browser.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as MSC from "mediasoup-client";
import { VoiceClient as BaseVoiceClient, type VoiceClientConsumer } from "./VoiceClient";
import type { ProduceType, RevkitClientOptions } from "./types";
import { Client } from "revkit";
import { VoiceClient as BaseVoiceClient, type VoiceClientConsumer } from "./VoiceClient";
import type { ProduceType, VoiceClientOptions } from "./types";

/** A default audio consumer for voice. (plays the audio with `Audio`) */
export const DEFAULT_CONSUMER: VoiceClientConsumer<"browser"> = (type, track) => {
if (type == "audio") {
const mediaStream = new MediaStream([track]);
Expand All @@ -22,7 +23,7 @@ export default class VoiceClient extends BaseVoiceClient<"browser"> {
/**
* @param trackConsumer A function that is called when there is a new `MediaStreamTrack` to play. The function returned will be called when the track ends.
*/
constructor(client: Client | RevkitClientOptions, trackConsumer?: VoiceClientConsumer<"browser">) {
constructor(client: Client | VoiceClientOptions, trackConsumer?: VoiceClientConsumer<"browser">) {
super("browser", client, MSC, () => new MSC.Device(), trackConsumer);
}

Expand Down
13 changes: 8 additions & 5 deletions voice/src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import { FFmpeg, VolumeTransformer } from "prism-media";
import { Client } from "revkit";
import { Readable } from "stream";
import { VoiceClient as BaseVoiceClient } from "./VoiceClient";
import type { ProduceType, RevkitClientOptions, VoiceParticipant } from "./types";
import type { ProduceType, VoiceClientOptions, VoiceParticipant } from "./types";

const AUDIO_ENCODING = "s16le",
RTP_PAYLOAD_TYPE = 100,
PORT_MIN = 5030,
PORT_MAX = 65535;

export interface VoiceClientOptions {
/** Options for the node voice client. (most of these don't need changed) */
export interface NodeVoiceClientOptions {
/** Additional FFmpeg args to use. */
args: string[];
/** Number of channels for the audio played. (default 2) */
Expand All @@ -34,14 +35,16 @@ export interface VoiceClientOptions {
* A VoiceClient implementation for use with node.js.
*/
export default class VoiceClient extends BaseVoiceClient<"node"> {
public options: VoiceClientOptions;
/** Node-specific client options. */
public options: NodeVoiceClientOptions;
/** The port used for ffmpeg. */
public port: number = 5002;

/**
* @param options Additional options for the player. Some of them also apply to incoming tracks. (you shouldn't need to mess with these)
*/
constructor(client: Client | RevkitClientOptions, options: Partial<VoiceClientOptions> = {}) {
const opts: VoiceClientOptions = {
constructor(client: Client | VoiceClientOptions, options: Partial<NodeVoiceClientOptions> = {}) {
const opts: NodeVoiceClientOptions = {
args: [],
audioChannels: 2,
frameSize: 960,
Expand Down
8 changes: 6 additions & 2 deletions voice/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,12 @@ export enum VoiceStatus {
CONNECTED,
}

export interface RevkitClientOptions {
/** Options for creating a RevKit client for the voice client. */
export interface VoiceClientOptions {
/** Bot or user session token. */
token: string;
/** Type for the token. */
type: "user" | "bot";
baseURL?: string;
/** Optional API url for custom instances. (passed to `ClientOptions.apiURL`) */
apiURL?: string;
}

0 comments on commit a4c4967

Please sign in to comment.