165 lines
4.0 KiB
TypeScript
165 lines
4.0 KiB
TypeScript
import type { MediaKind, ProducerOptions } from 'mediasoup-client/types'
|
|
import { createGlobalState } from '@vueuse/core'
|
|
import { markRaw } from 'vue'
|
|
import { useMediasoup } from './use-mediasoup'
|
|
import { useSignaling } from './use-signaling'
|
|
|
|
export const useProducers = createGlobalState(() => {
|
|
const { socket } = useSignaling()
|
|
const { device, sendTransport, producers } = useMediasoup()
|
|
|
|
async function createProducer(options: ProducerOptions) {
|
|
if (!sendTransport.value || !device.value || !options.track)
|
|
return
|
|
|
|
if (!device.value.canProduce(options.track.kind as MediaKind))
|
|
return
|
|
|
|
const producer = await sendTransport.value.produce({ disableTrackOnPause: true, ...options })
|
|
|
|
producer.observer.on('trackended', () => disableProducer(producer.id))
|
|
|
|
await producers.add({
|
|
id: producer.id,
|
|
paused: producer.paused,
|
|
kind: producer.kind,
|
|
appData: producer.appData as Record<string, unknown>,
|
|
ref: markRaw(producer),
|
|
})
|
|
}
|
|
|
|
async function disableProducer(producerId: string) {
|
|
const snap = producers.get(producerId)
|
|
if (!snap)
|
|
return
|
|
|
|
try {
|
|
snap.ref.close()
|
|
await socket.value?.emitWithAck('close-producer', { producerId })
|
|
}
|
|
catch {}
|
|
}
|
|
|
|
async function pauseProducer(producerId: string) {
|
|
const snap = producers.get(producerId)
|
|
if (!snap || snap.paused)
|
|
return
|
|
|
|
try {
|
|
snap.ref.pause()
|
|
await socket.value?.emitWithAck('pause-producer', { producerId })
|
|
}
|
|
catch {
|
|
snap.ref.resume()
|
|
}
|
|
}
|
|
|
|
async function resumeProducer(producerId: string) {
|
|
const snap = producers.get(producerId)
|
|
if (!snap || !snap.paused)
|
|
return
|
|
|
|
try {
|
|
snap.ref.resume()
|
|
await socket.value?.emitWithAck('resume-producer', { producerId })
|
|
}
|
|
catch {
|
|
snap.ref.pause()
|
|
}
|
|
}
|
|
|
|
async function enableMic() {
|
|
for (const snap of producers.store.value.values()) {
|
|
if (snap.kind === 'audio')
|
|
return
|
|
}
|
|
|
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
|
|
const track = stream.getAudioTracks()[0]
|
|
if (!track)
|
|
return
|
|
|
|
await createProducer({
|
|
track,
|
|
streamId: 'mic-video',
|
|
codecOptions: { opusStereo: true, opusDtx: true },
|
|
appData: { source: 'mic' },
|
|
})
|
|
}
|
|
|
|
async function disableMic() {
|
|
for (const snap of producers.store.value.values()) {
|
|
if (snap.kind === 'audio')
|
|
await disableProducer(snap.id)
|
|
}
|
|
}
|
|
|
|
async function enableVideo() {
|
|
for (const snap of producers.store.value.values()) {
|
|
if (snap.kind === 'video' && snap.appData.source !== 'share')
|
|
return
|
|
}
|
|
|
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
video: { width: { ideal: 1920 }, height: { ideal: 1080 }, frameRate: { ideal: 60 } },
|
|
})
|
|
const track = stream.getVideoTracks()[0]
|
|
if (!track)
|
|
return
|
|
|
|
await createProducer({
|
|
track,
|
|
streamId: 'mic-video',
|
|
appData: { source: 'camera' },
|
|
})
|
|
}
|
|
|
|
async function disableVideo() {
|
|
for (const snap of producers.store.value.values()) {
|
|
if (snap.kind === 'video' && snap.appData.source !== 'share')
|
|
await disableProducer(snap.id)
|
|
}
|
|
}
|
|
|
|
async function enableShare() {
|
|
for (const snap of producers.store.value.values()) {
|
|
if (snap.appData.source === 'share')
|
|
return
|
|
}
|
|
|
|
const stream = await navigator.mediaDevices.getDisplayMedia({
|
|
audio: false,
|
|
video: { displaySurface: 'monitor' },
|
|
})
|
|
const track = stream.getVideoTracks()[0]
|
|
if (!track)
|
|
return
|
|
|
|
await createProducer({
|
|
track,
|
|
streamId: 'share',
|
|
zeroRtpOnPause: true,
|
|
appData: { source: 'share' },
|
|
})
|
|
}
|
|
|
|
async function disableShare() {
|
|
for (const snap of producers.store.value.values()) {
|
|
if (snap.appData.source === 'share')
|
|
await disableProducer(snap.id)
|
|
}
|
|
}
|
|
|
|
return {
|
|
enableMic,
|
|
disableMic,
|
|
enableVideo,
|
|
disableVideo,
|
|
enableShare,
|
|
disableShare,
|
|
pauseProducer,
|
|
resumeProducer,
|
|
disableProducer,
|
|
}
|
|
})
|