Files
seojng-tv/composables/useScreenShare.ts
T
ysj7705andCursor 47a7a717ec
CI / Type-check & Build (push) Successful in 10m31s
CI / Build & Push image (push) Successful in 13m5s
raise screen share quality and stop the grid from overflowing
Screen share was capped by WebRTC's default ~2.5 Mbps and by window
capture resolution, and fixed aspect-video cards forced the page to
scroll. Adds minimal [sejong-rtc] logs to diagnose ICE failures.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 16:39:04 +09:00

79 lines
2.5 KiB
TypeScript

import { rtcLog, rtcWarn } from '~/utils/rtcLog'
export function useScreenShare() {
const localStream = ref<MediaStream | null>(null)
const streamId = ref<string | null>(null)
const error = ref<string | null>(null)
const settings = ref<MediaTrackSettings | null>(null)
const isSharing = computed(() => Boolean(localStream.value))
async function startShare(clientId: string) {
error.value = null
try {
const stream = await navigator.mediaDevices.getDisplayMedia({
video: {
width: { ideal: 1920, max: 1920 },
height: { ideal: 1080, max: 1080 },
frameRate: { ideal: 60, max: 60 },
// Monitor capture reaches full 1080p; window capture is capped by the window size.
// @ts-expect-error displaySurface is supported in Chromium
displaySurface: 'monitor',
},
audio: {
// @ts-expect-error Chromium system audio options
echoCancellation: false,
noiseSuppression: false,
autoGainControl: false,
},
})
localStream.value = stream
streamId.value = `${clientId}-${Date.now()}`
const videoTrack = stream.getVideoTracks()[0]
if (videoTrack) {
// Games favour framerate over per-frame sharpness.
videoTrack.contentHint = 'motion'
try {
await videoTrack.applyConstraints({
width: { ideal: 1920 },
height: { ideal: 1080 },
frameRate: { ideal: 60 },
})
} catch (e) {
rtcWarn('applyConstraints failed', String(e))
}
settings.value = videoTrack.getSettings()
rtcLog('capture:settings', settings.value)
if ((settings.value.height || 0) < 1080) {
rtcWarn(
'capture below 1080p — pick a full monitor (window capture is limited to the window size)',
{ width: settings.value.width, height: settings.value.height },
)
}
videoTrack.addEventListener('ended', () => {
stopShare()
})
}
return { stream, streamId: streamId.value }
} catch (e) {
error.value = e instanceof Error ? e.message : 'Screen share failed'
throw e
}
}
function stopShare() {
localStream.value?.getTracks().forEach((t) => t.stop())
localStream.value = null
streamId.value = null
settings.value = null
}
onBeforeUnmount(() => {
stopShare()
})
return { localStream, streamId, settings, isSharing, error, startShare, stopShare }
}