175 lines
4.4 KiB
TypeScript
175 lines
4.4 KiB
TypeScript
import type { Socket } from 'socket.io-client'
|
|
import { createGlobalState } from '@vueuse/core'
|
|
import * as mediasoupClient from 'mediasoup-client'
|
|
import { io } from 'socket.io-client'
|
|
|
|
const ICE_SERVERS: RTCIceServer[] = [
|
|
{ urls: 'stun:stun.l.google.com:19302' },
|
|
{ urls: 'stun:stun.l.google.com:5349' },
|
|
{ urls: 'stun:stun1.l.google.com:3478' },
|
|
{ urls: 'stun:stun1.l.google.com:5349' },
|
|
{ urls: 'stun:stun2.l.google.com:19302' },
|
|
{ urls: 'stun:stun2.l.google.com:5349' },
|
|
{ urls: 'stun:stun3.l.google.com:3478' },
|
|
{ urls: 'stun:stun3.l.google.com:5349' },
|
|
{ urls: 'stun:stun4.l.google.com:19302' },
|
|
{ urls: 'stun:stun4.l.google.com:5349' },
|
|
]
|
|
|
|
export const useMediasoup = createGlobalState(() => {
|
|
const socket: Socket = io('https://api.koptilnya.xyz/webrtc', {
|
|
path: '/chad/ws',
|
|
transports: ['websocket'],
|
|
})
|
|
|
|
const initializing = ref(false)
|
|
const connected = ref(false)
|
|
const streams = shallowRef<MediaStream[]>([])
|
|
let device: mediasoupClient.Device
|
|
let sendTransport: mediasoupClient.types.Transport
|
|
let recvTransport: mediasoupClient.types.Transport
|
|
|
|
socket.on('producers', async (producers) => {
|
|
watch(connected, async () => {
|
|
if (!connected.value)
|
|
return
|
|
|
|
for (const producer of producers) {
|
|
await consume(producer.producerId)
|
|
}
|
|
}, { immediate: true })
|
|
})
|
|
|
|
socket.on('newProducer', async ({ producerId }) => {
|
|
await consume(producerId)
|
|
})
|
|
|
|
async function consume(producerId: number) {
|
|
const params = await socket.emitWithAck('consume', {
|
|
producerId,
|
|
transportId: recvTransport.id,
|
|
rtpCapabilities: device.rtpCapabilities,
|
|
})
|
|
|
|
if (params?.error) {
|
|
console.error('consume error:', params.error)
|
|
return
|
|
}
|
|
|
|
const consumer = await recvTransport.consume(params)
|
|
const stream = new MediaStream([consumer.track])
|
|
|
|
streams.value.push(stream)
|
|
triggerRef(streams)
|
|
}
|
|
|
|
async function loadDevice() {
|
|
device = new mediasoupClient.Device()
|
|
const rtpCapabilities = await socket.emitWithAck('getRtpCapabilities')
|
|
await device.load({ routerRtpCapabilities: rtpCapabilities })
|
|
}
|
|
|
|
async function createSendTransport() {
|
|
const params = await socket.emitWithAck('createTransport')
|
|
sendTransport = device.createSendTransport({
|
|
...params,
|
|
iceServers: [
|
|
...ICE_SERVERS,
|
|
...(params.iceServers ?? []),
|
|
],
|
|
})
|
|
|
|
sendTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
|
|
try {
|
|
await socket.emitWithAck('connectTransport', {
|
|
transportId: sendTransport.id,
|
|
dtlsParameters,
|
|
})
|
|
|
|
callback()
|
|
}
|
|
catch (err) {
|
|
errback(err)
|
|
}
|
|
})
|
|
|
|
sendTransport.on('produce', async ({ kind, rtpParameters }, callback, errback) => {
|
|
try {
|
|
const { producerId } = await socket.emitWithAck('produce', {
|
|
transportId: sendTransport.id,
|
|
kind,
|
|
rtpParameters,
|
|
})
|
|
callback({ id: producerId })
|
|
}
|
|
catch (err) {
|
|
errback(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
async function publishMic() {
|
|
const devices = await navigator.mediaDevices.enumerateDevices()
|
|
console.log(devices)
|
|
|
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
// audio: true,
|
|
audio: {
|
|
autoGainControl: false,
|
|
noiseSuppression: true,
|
|
echoCancellation: false,
|
|
latency: 0,
|
|
},
|
|
})
|
|
const track = stream.getAudioTracks()[0]
|
|
|
|
await sendTransport.produce({ track })
|
|
}
|
|
|
|
async function createRecvTransport() {
|
|
const params = await socket.emitWithAck('createTransport')
|
|
recvTransport = device.createRecvTransport({
|
|
...params,
|
|
iceServers: [
|
|
...ICE_SERVERS,
|
|
...(params.iceServers ?? []),
|
|
],
|
|
})
|
|
|
|
recvTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
|
|
try {
|
|
await socket.emitWithAck('connectTransport', {
|
|
transportId: recvTransport.id,
|
|
dtlsParameters,
|
|
})
|
|
|
|
callback()
|
|
}
|
|
catch (err) {
|
|
errback(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
(async () => {
|
|
if (initializing.value || connected.value)
|
|
return
|
|
|
|
initializing.value = true
|
|
connected.value = false
|
|
|
|
await loadDevice()
|
|
await createSendTransport()
|
|
await createRecvTransport()
|
|
await publishMic()
|
|
|
|
initializing.value = false
|
|
connected.value = true
|
|
})()
|
|
|
|
return {
|
|
connected,
|
|
streams,
|
|
}
|
|
})
|