This commit is contained in:
dank074 2025-04-18 12:40:03 -05:00
parent c845d2070c
commit 9e202803a9
5 changed files with 40 additions and 12 deletions

2
package-lock.json generated
View File

@ -9377,7 +9377,7 @@
},
"node_modules/spacebar-webrtc-types": {
"version": "1.0.1",
"resolved": "git+ssh://git@github.com/dank074/spacebar-webrtc-types.git#04044902e71f2c80fc39c256ec5d27fdb8ca425a",
"resolved": "git+ssh://git@github.com/dank074/spacebar-webrtc-types.git#e8e13a32c7c0b446fb5c1b35111591ff1a55b919",
"dev": true,
"license": "ISC"
},

View File

@ -40,7 +40,7 @@ export async function onIdentify(this: WebRtcWebSocket, data: VoicePayload) {
// server_id can be one of the following: a unique id for a GO Live stream, a channel id for a DM voice call, or a guild id for a guild voice channel
// not sure if there's a way to determine whether a snowflake is a channel id or a guild id without checking if it exists in db
// luckily we will only have to determine this once
let type: "guild-voice" | "dm-voice" | "stream";
let type: "guild-voice" | "dm-voice" | "stream" = "guild-voice";
let authenticated = false;
// first check if its a guild voice connection or DM voice call
@ -54,6 +54,9 @@ export async function onIdentify(this: WebRtcWebSocket, data: VoicePayload) {
if (voiceState) {
type = voiceState.guild_id === server_id ? "guild-voice" : "dm-voice";
authenticated = true;
this.guild_id =
type === "guild-voice" ? voiceState.guild_id : undefined;
this.channel_id = voiceState.channel_id;
} else {
// if its not a guild/dm voice connection, check if it is a go live stream
const streamSession = await StreamSession.findOne({
@ -64,6 +67,7 @@ export async function onIdentify(this: WebRtcWebSocket, data: VoicePayload) {
session_id,
used: false,
},
relations: ["stream"],
});
if (streamSession) {
@ -72,6 +76,8 @@ export async function onIdentify(this: WebRtcWebSocket, data: VoicePayload) {
streamSession.used = true;
await streamSession.save();
this.channel_id = streamSession.stream.channel_id;
this.once("close", async () => {
await streamSession.remove();
});
@ -84,8 +90,15 @@ export async function onIdentify(this: WebRtcWebSocket, data: VoicePayload) {
this.user_id = user_id;
this.session_id = session_id;
this.type = type!;
this.webRtcClient = mediaServer.join(server_id, this.user_id, this, type!);
this.type = type;
const voiceRoomId = type === "stream" ? server_id : voiceState!.channel_id;
this.webRtcClient = mediaServer.join(
voiceRoomId,
this.user_id,
this,
type!,
);
this.on("close", () => {
// ice-lite media server relies on this to know when the peer went away

View File

@ -32,7 +32,7 @@ export async function onSpeaking(this: WebRtcWebSocket, data: VoicePayload) {
await Promise.all(
Array.from(
mediaServer.getClientsForRtcServer<WebRtcWebSocket>(
this.webRtcClient.rtc_server_id,
this.webRtcClient.voiceRoomId,
),
).map((client) => {
if (client.user_id === this.user_id) return Promise.resolve();

View File

@ -28,13 +28,13 @@ import type { WebRtcClient } from "spacebar-webrtc-types";
export async function onVideo(this: WebRtcWebSocket, payload: VoicePayload) {
if (!this.webRtcClient || !this.webRtcClient.webrtcConnected) return;
const { rtc_server_id } = this.webRtcClient;
const { voiceRoomId } = this.webRtcClient;
const d = validateSchema("VoiceVideoSchema", payload.d) as VoiceVideoSchema;
if (this.type === "stream") {
const stream = await Stream.findOne({
where: { id: rtc_server_id },
where: { id: voiceRoomId },
});
if (!stream) return;
@ -50,9 +50,20 @@ export async function onVideo(this: WebRtcWebSocket, payload: VoicePayload) {
await Send(this, { op: VoiceOPCodes.MEDIA_SINK_WANTS, d: { any: 100 } });
const clientsThatNeedUpdate = new Set<WebRtcClient<WebRtcWebSocket>>();
const wantsToProduceAudio = d.audio_ssrc !== 0;
const wantsToProduceVideo = d.video_ssrc !== 0 && stream?.active;
// first check if we need stop any tracks
if (!wantsToProduceAudio && this.webRtcClient.isProducingAudio()) {
this.webRtcClient.stopPublishingTrack("audio");
}
if (!wantsToProduceVideo && this.webRtcClient.isProducingVideo()) {
this.webRtcClient.stopPublishingTrack("video");
}
// check if client has signaled that it will send audio
if (d.audio_ssrc !== 0) {
if (wantsToProduceAudio) {
// check if we are already producing audio, if not, publish a new audio track for it
if (!this.webRtcClient!.isProducingAudio()) {
console.log(
@ -65,7 +76,7 @@ export async function onVideo(this: WebRtcWebSocket, payload: VoicePayload) {
// now check that all clients have subscribed to our audio
for (const client of mediaServer.getClientsForRtcServer<WebRtcWebSocket>(
rtc_server_id,
voiceRoomId,
)) {
if (client.user_id === this.user_id) continue;
@ -80,7 +91,7 @@ export async function onVideo(this: WebRtcWebSocket, payload: VoicePayload) {
}
}
// check if client has signaled that it will send video
if (d.video_ssrc !== 0 && stream?.active) {
if (wantsToProduceVideo) {
this.webRtcClient!.videoStream = stream;
// check if we are already publishing video, if not, publish a new video track for it
if (!this.webRtcClient!.isProducingVideo()) {
@ -95,7 +106,7 @@ export async function onVideo(this: WebRtcWebSocket, payload: VoicePayload) {
// now check that all clients have subscribed to our video track
for (const client of mediaServer.getClientsForRtcServer<WebRtcWebSocket>(
rtc_server_id,
voiceRoomId,
)) {
if (client.user_id === this.user_id) continue;
@ -136,8 +147,10 @@ export async function onVideo(this: WebRtcWebSocket, payload: VoicePayload) {
export async function subscribeToProducers(
this: WebRtcWebSocket,
): Promise<void> {
if (!this.webRtcClient || !this.webRtcClient.webrtcConnected) return;
const clients = mediaServer.getClientsForRtcServer<WebRtcWebSocket>(
this.webRtcClient!.rtc_server_id,
this.webRtcClient.voiceRoomId,
);
await Promise.all(

View File

@ -3,5 +3,7 @@ import type { WebRtcClient } from "spacebar-webrtc-types";
export interface WebRtcWebSocket extends WebSocket {
type: "guild-voice" | "dm-voice" | "stream";
guild_id?: string;
channel_id: string;
webRtcClient?: WebRtcClient<WebRtcWebSocket>;
}