diff --git a/src/app/components/ProfileCircle.svelte b/src/app/components/ProfileCircle.svelte
index 255cbffe..8d4561b6 100644
--- a/src/app/components/ProfileCircle.svelte
+++ b/src/app/components/ProfileCircle.svelte
@@ -1,12 +1,14 @@
+ src={$profile?.picture ?? UserRounded} />
diff --git a/src/app/components/SpaceMenuRoomItem.svelte b/src/app/components/SpaceMenuRoomItem.svelte
index 19d4d4e1..1ac59b01 100644
--- a/src/app/components/SpaceMenuRoomItem.svelte
+++ b/src/app/components/SpaceMenuRoomItem.svelte
@@ -4,10 +4,10 @@
import Icon from "@lib/components/Icon.svelte"
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
import RoomNameWithImage from "@app/components/RoomNameWithImage.svelte"
+ import VoiceRoomItem from "@app/components/VoiceRoomItem.svelte"
import {deriveRoom, deriveShouldNotify, getRoomType, RoomType} from "@app/core/state"
import {notifications} from "@app/util/notifications"
import {makeRoomPath} from "@app/util/routes"
- import {joinVoiceRoom, currentVoiceSession} from "@app/voice"
interface Props {
url: any
@@ -24,21 +24,18 @@
const shouldNotifyForSpace = deriveShouldNotify(url)
const shouldNotifyForRoom = deriveShouldNotify(url, h)
const showDifferenceIcon = $derived($shouldNotifyForRoom !== $shouldNotifyForSpace)
-
- const handleClick = () => {
- if (roomType !== RoomType.Voice) return
- if ($currentVoiceSession?.url === url && $currentVoiceSession?.h === h) return
- void joinVoiceRoom(url, h)
- }
-
-
- {#if showDifferenceIcon}
-
- {/if}
-
+{#if roomType === RoomType.Voice}
+
+{:else}
+
+
+ {#if showDifferenceIcon}
+
+ {/if}
+
+{/if}
diff --git a/src/app/components/VoiceRoomItem.svelte b/src/app/components/VoiceRoomItem.svelte
index d77da0d1..6f37923e 100644
--- a/src/app/components/VoiceRoomItem.svelte
+++ b/src/app/components/VoiceRoomItem.svelte
@@ -11,7 +11,9 @@
joinVoiceRoom,
leaveVoiceRoom,
currentVoiceSession,
- speakingPubkeys,
+ isParticipantSpeaking,
+ participantKey,
+ type VoiceParticipant,
} from "@app/voice"
interface Props {
@@ -46,8 +48,8 @@
}
$effect(() => {
- for (const pk of $participants) {
- loadProfile(pk)
+ for (const p of $participants) {
+ if (p.pubkey) loadProfile(p.pubkey)
}
})
@@ -65,17 +67,17 @@
{#if $participants.length > 0}
- {#each $participants as pk (pk)}
+ {#each $participants as p (participantKey(p as VoiceParticipant))}
- {displayProfileByPubkey(pk)}
+ {p.pubkey ? displayProfileByPubkey(p.pubkey) : "Unknown"}
{/each}
diff --git a/src/app/core/sync.ts b/src/app/core/sync.ts
index f5737d45..ebe46474 100644
--- a/src/app/core/sync.ts
+++ b/src/app/core/sync.ts
@@ -55,7 +55,7 @@ import {
loadFeedsForPubkey,
} from "@app/core/state"
import {hasBlossomSupport} from "@app/core/commands"
-import {ROOM_PRESENCE} from "@app/voice"
+import {LIVEKIT_PARTICIPANTS} from "@app/voice"
// Utils
@@ -320,7 +320,7 @@ const syncSpace = (url: string, rooms: string[]) => {
pullAndListen({
url,
signal: controller.signal,
- filters: [{kinds: [ROOM_PRESENCE]}],
+ filters: [{kinds: [LIVEKIT_PARTICIPANTS]}],
})
return () => controller.abort()
diff --git a/src/app/voice.ts b/src/app/voice.ts
index 2a952474..7c9289b7 100644
--- a/src/app/voice.ts
+++ b/src/app/voice.ts
@@ -4,21 +4,19 @@
*/
import {DisconnectReason, Room, RoomEvent, Track} from "livekit-client"
import {derived, get, writable} from "svelte/store"
-import {now} from "@welshman/lib"
-import {makeEvent, makeHttpAuth, makeHttpAuthHeader, getTagValue} from "@welshman/util"
-import {signer, publishThunk} from "@welshman/app"
+import {uniqBy} from "@welshman/lib"
+import type {TrustedEvent} from "@welshman/util"
+import {makeHttpAuth, makeHttpAuthHeader, getTags} from "@welshman/util"
+import {signer} from "@welshman/app"
import {getLivekitEndpoint} from "$lib/livekit"
import {AbortError, whenAborted, whenTimeout} from "$lib/util"
-import {deriveEventsForUrl} from "@app/core/state"
+import {deriveLatestEventForUrl} from "@app/core/state"
import {pushToast} from "@app/util/toast"
-export const ROOM_PRESENCE = 10312
+export const LIVEKIT_PARTICIPANTS = 39004
export {checkRelayHasLivekit} from "$lib/livekit"
-const PRESENCE_INTERVAL_MS = 60_000
-const PRESENCE_EXPIRY_S = 300
-
export type VoiceSession = {
url: string
h: string
@@ -26,9 +24,49 @@ export type VoiceSession = {
muted: boolean
}
+export type Pubkey = string
+
+export type VoiceParticipant = {pubkey?: Pubkey; identity: string}
+
export const currentVoiceSession = writable(undefined)
-export const speakingPubkeys = writable(new Set())
+export const participantPubkeyMap = writable