вебкамера там, туда-сюда
All checks were successful
Deploy / publish-web (push) Successful in 1m16s

This commit is contained in:
2026-02-02 14:39:16 +06:00
parent 0922fc4f41
commit 269b19a5be
20 changed files with 546 additions and 211 deletions

View File

@@ -28,7 +28,7 @@
</div>
<div v-if="hasBadges" class="flex justify-end align-center gap-1 mt-2">
<PrimeBadge v-if="!!shareConsumer" v-tooltip.top="'Watch'" severity="success" value="Streaming" size="small" @click.stop="watchStream" />
<PrimeBadge v-if="streaming" v-tooltip.top="'Watch'" severity="success" value="Streaming" size="small" @click.stop="watchStream" />
<PrimeBadge v-if="premuted" severity="danger" value="Muted" size="small" />
<PrimeBadge v-else-if="client.outputMuted" severity="info" value="No sound" size="small" />
@@ -60,7 +60,6 @@
<script setup lang="ts">
import type { ChadClient } from '#shared/types'
import { useLocalStorage } from '@vueuse/core'
import { ChevronDown, ChevronUp, User } from 'lucide-vue-next'
import CollapseTransition from '~/components/CollapseTransition.vue'
@@ -69,44 +68,40 @@ const props = defineProps<{
}>()
const { outputMuted } = useApp()
const { consumers: allConsumers, micProducer, speakingClients } = useMediasoup()
const { consumers: allConsumers, micProducer } = useMediasoup()
const { me } = useClients()
const { show } = useFullscreenVideo()
const expanded = ref(false)
const volume = useLocalStorage<number>(computed(() => `CLIENT_VOLUME_${props.client.userId}`), 100, { writeDefaults: false })
const premuted = useLocalStorage<boolean>(computed(() => `CLIENT_PREMUTED_${props.client.userId}`), false, { writeDefaults: false })
const {
volume,
premuted,
speaking,
audioConsumers,
videoConsumers,
shareConsumers,
streaming,
} = useClient(toRef(() => props.client.socketId))
const isMe = computed(() => {
return me.value && props.client.userId === me.value.userId
})
const consumers = computed(() => {
return allConsumers.value.values().filter(consumer => consumer.appData.socketId === props.client.socketId).toArray()
})
const audioConsumer = computed(() => {
return consumers.value.find(consumer => consumer.track.kind === 'audio')
})
const videoConsumers = computed(() => {
return consumers.value.filter(consumer => consumer.track.kind === 'video')
})
const shareConsumer = computed(() => {
return videoConsumers.value.find(consumer => consumer.appData.source === 'share')
return audioConsumers.value[0]
})
const audioTrack = computed(() => {
return audioConsumer.value?.track
return audioConsumer.value?.raw.track
})
const speaking = computed(() => {
return speakingClients.value.find(speaker => speaker.clientId === props.client.socketId)
})
const audioConsumerPaused = computed(() => {
if (Object.keys(allConsumers.value).length === 0)
return false
const audioConsumerPaused = ref(false)
return audioConsumer.value?.paused ?? false
})
const inputMuted = computed(() => {
if (isMe.value)
@@ -116,17 +111,13 @@ const inputMuted = computed(() => {
})
const hasBadges = computed(() => {
return !!shareConsumer.value
return shareConsumers.value.length > 0
|| premuted.value
|| inputMuted.value
|| props.client.outputMuted
|| isMe.value
})
watch(allConsumers, () => {
audioConsumerPaused.value = audioConsumer.value?.paused ?? false
})
const { setGain } = useAudioContext(audioTrack)
watchEffect(() => {
@@ -141,9 +132,11 @@ function toggleExpand() {
}
function watchStream() {
if (!shareConsumer.value)
if (!streaming.value)
return
show(new MediaStream([shareConsumer.value.track]))
const consumer = [...videoConsumers.value, ...shareConsumers.value][0]!
show(new MediaStream([consumer.raw.track]))
}
</script>