Skip to content

Instantly share code, notes, and snippets.

@armstrongnate
Created September 4, 2024 20:49
Show Gist options
  • Save armstrongnate/bbb217981e89dea0b28c8134b8b0dd64 to your computer and use it in GitHub Desktop.
Save armstrongnate/bbb217981e89dea0b28c8134b8b0dd64 to your computer and use it in GitHub Desktop.
Media recording in safari
'use client'
import { wrapStreamInMediaRecorder } from '@/lib/client/video'
import { Button } from '@/ui/Molecule/Button'
import { useCallback, useEffect, useRef, useState } from 'react'
export default function Interviewer() {
const [recording, setRecording] = useState(false)
function start() {
setRecording(true)
}
if (!recording) {
return <Button onClick={start}>Start Recording</Button>
}
return <Recorder />
}
function Recorder() {
const [stream, setStream] = useState<MediaStream | null>(null)
const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null)
const [finalBlob, setFinalBlob] = useState<Blob | null>(null)
const chunksRef = useRef<Blob[]>([])
useEffect(() => {
if (stream) return
let didCancel = false
async function getUserMedia() {
try {
console.log('getting user media')
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true })
if (!didCancel) {
setStream(stream)
}
} catch (err) {
console.error(err)
}
}
function cancel() {
didCancel = true
if (stream) {
stream.getTracks().forEach((track) => track.stop())
}
}
getUserMedia()
return cancel
}, [stream])
useEffect(() => {
if (!stream) {
return
}
const mediaRecorder = wrapStreamInMediaRecorder(stream)
mediaRecorder.ondataavailable = (e) => {
chunksRef.current.push(e.data)
}
mediaRecorder.start()
setMediaRecorder(mediaRecorder)
}, [stream])
const stop = useCallback(() => {
if (!mediaRecorder) {
return
}
mediaRecorder.onstop = () => {
console.log('recording stopped')
const blob = new Blob(chunksRef.current, { type: mediaRecorder.mimeType })
setFinalBlob(blob)
}
mediaRecorder.stop()
}, [mediaRecorder])
if (!stream) {
return <div>Initializing...</div>
}
if (finalBlob) {
return <Playback blob={finalBlob} />
}
return <Button onClick={stop}>Stop Recording</Button>
}
function Playback({ blob }: { blob: Blob }) {
const videoUrl = URL.createObjectURL(blob)
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
return (
<video controls>
<source src={videoUrl} />
Your browser does not support the video tag.
</video>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment