feat: peer stuff

This commit is contained in:
2026-01-11 22:14:05 +01:00
parent 08e44e61ff
commit d67dd9e5bf
5 changed files with 94 additions and 81 deletions

View File

@@ -6,35 +6,103 @@ import {
SelectSeparator,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import { Plus } from 'lucide-vue-next';
const router = useRouter()
const selectedValue = ref('')
} from "@/components/ui/select";
import { Plus } from "lucide-vue-next";
import type { ApiResponse, PresetUser } from "~/lib/types/PresetGetResponse";
import { useStreamerStore } from "~/state/streamer";
const router = useRouter();
const selectedValue = ref("");
const presets = ref<PresetUser[]>([]);
const loading = ref(true);
const streamerStore = useStreamerStore();
onMounted(async () => {
try {
const response = await $fetch<ApiResponse>("/api/presets");
if (response.success) {
presets.value = response.data;
const defaultPreset = presets.value.find((p) => p.isDefault);
if (defaultPreset) {
selectedValue.value = defaultPreset.presetId;
// Load the default preset's ice servers
loadPresetIceServers(defaultPreset.presetId);
}
}
} catch (error) {
console.error("Failed to fetch presets:", error);
} finally {
loading.value = false;
}
});
async function loadPresetIceServers(presetId: string) {
try {
const response = await $fetch(`/api/presets/${presetId}`);
const preset = response?.data || response;
if (preset && preset.iceServers) {
// Parse ice servers if it's a string
let iceServers = preset.iceServers;
if (typeof iceServers === "string") {
iceServers = JSON.parse(iceServers);
}
// Set the ice servers on the streamer store
streamerStore.setIceServers(iceServers);
}
} catch (error) {
console.error("Failed to load preset ice servers:", error);
}
}
watch(selectedValue, (newValue) => {
if (newValue === 'create-new') {
router.push('/presets/new')
if (newValue === "create-new") {
router.push("/presets/new");
selectedValue.value = "";
} else if (newValue) {
// Load ice servers for the selected preset
loadPresetIceServers(newValue);
}
})
});
</script>
<template>
<Select v-model="selectedValue">
<Select v-model="selectedValue" :disabled="loading">
<SelectTrigger class="w-[180px]">
<SelectValue placeholder="Select a preset" />
<SelectValue
:placeholder="loading ? 'Loading presets...' : 'Select a preset'"
/>
</SelectTrigger>
<SelectContent>
<SelectItem value="default">
Default
</SelectItem>
<SelectSeparator />
<div
v-if="presets.length === 0 && !loading"
class="px-2 py-1.5 text-sm text-muted-foreground"
>
No presets available
</div>
<div v-else-if="!loading">
<div v-for="preset in presets" :key="preset.presetId">
<SelectItem :value="preset.presetId">
<span :class="{ 'font-semibold': preset.isDefault }">
{{ preset.preset.name }}
</span>
<span
v-if="preset.isDefault"
class="ml-2 text-xs text-muted-foreground"
>(default)</span
>
</SelectItem>
</div>
<SelectSeparator />
</div>
<SelectItem value="create-new">
<div class="font-bold flex gap-2 items-center">
<Plus class="size-4" />
Create New Preset
</div>
</SelectItem>
<!-- add database provided presets here -->
</SelectContent>
</Select>
</template>

View File

@@ -13,7 +13,7 @@ interface Preset {
shareable: boolean;
createdAt: string;
}
interface PresetUser {
export interface PresetUser {
id: string;
presetId: string;
userId: string;

View File

@@ -45,38 +45,7 @@ const { send } = useWebSocket(wsUrl, {
const message = JSON.parse(ev.data);
if (message.event === "offer") {
viewerStore.setConnectionStatus("creating rtc peer connections...");
const peerConnection = new RTCPeerConnection({
iceServers: [
{ urls: "stun:stun.l.google.com:19302" },
{ urls: "stun:stun1.l.google.com:19302" },
{
urls: "turn:5.161.207.54:3478",
username: "username",
credential: "password",
},
{
urls: "turn:5.161.49.183:3478",
username: "username",
credential: "password",
},
{
urls: "turn:135.181.147.65:3478",
username: "username",
credential: "password",
},
{
urls: "turn:5.78.83.26:3478",
username: "username",
credential: "password",
},
{
urls: "turn:5.223.48.157:3478",
username: "username",
credential: "password",
},
],
iceTransportPolicy: "relay",
});
const peerConnection = new RTCPeerConnection();
viewerStore.setPeerConnection(peerConnection);
peerConnection.ontrack = (event) => {
@@ -175,4 +144,3 @@ watch(codeRef, (newCode) => {
}
});
</script>

View File

@@ -36,35 +36,7 @@ const { send } = useWebSocket(wsUrl, {
if (message.event === "viewer-joined") {
const peerConnection = new RTCPeerConnection({
iceServers: [
{ urls: "stun:stun.l.google.com:19302" },
{ urls: "stun:stun1.l.google.com:19302" },
{
urls: "turn:5.161.207.54:3478",
username: "username",
credential: "password",
},
{
urls: "turn:5.161.49.183:3478",
username: "username",
credential: "password",
},
{
urls: "turn:135.181.147.65:3478",
username: "username",
credential: "password",
},
{
urls: "turn:5.78.83.26:3478",
username: "username",
credential: "password",
},
{
urls: "turn:5.223.48.157:3478",
username: "username",
credential: "password",
},
],
iceServers: streamerStore.iceServers,
iceTransportPolicy: "relay",
});
streamerStore.addPeerConnection(message.viewerId, peerConnection);

View File

@@ -1,9 +1,10 @@
import { defineStore} from 'pinia';
import { defineStore } from "pinia";
export const useStreamerStore = defineStore('streamer', {
export const useStreamerStore = defineStore("streamer", {
state: () => ({
code: '',
code: "",
peerConnections: {} as Record<string, RTCPeerConnection>,
iceServers: [] as RTCIceServer[],
}),
actions: {
setCode(code: string) {
@@ -12,5 +13,9 @@ export const useStreamerStore = defineStore('streamer', {
addPeerConnection(id: string, pc: RTCPeerConnection) {
this.peerConnections[id] = pc;
},
setIceServers(iceServers: RTCIceServer[]) {
this.iceServers = iceServers;
},
},
});
});