UNPKG

@orbisk/vue-use-media-recorder

Version:
113 lines (112 loc) 3.19 kB
import { computedWithControl, useSupported } from "@vueuse/core"; import { tryOnScopeDispose } from "@vueuse/shared"; import { defu } from "defu"; import { computed, ref, shallowRef, toValue } from "vue"; const defaultOptions = { constraints: { audio: false, video: false }, mediaRecorderOptions: {}, onStart: () => { }, onPause: () => { }, onResume: () => { }, onStop: () => { }, onError: () => { } }; export function useMediaRecorder(options = {}) { const data = ref([]); const mediaRecorder = shallowRef(); const stream = shallowRef(); const isMimeTypeSupported = computed(() => { return toValue(options.mediaRecorderOptions)?.mimeType ? MediaRecorder.isTypeSupported(toValue(options.mediaRecorderOptions)?.mimeType ?? "") : true; }); const isSupported = useSupported(() => { return !!navigator?.mediaDevices?.getUserMedia && isMimeTypeSupported.value; }); const state = computedWithControl(() => mediaRecorder.value, () => { return mediaRecorder.value?.state; }); const mimeType = computedWithControl(() => mediaRecorder.value, () => { return mediaRecorder.value?.mimeType; }); const { mediaRecorderOptions, constraints } = defu(options, defaultOptions); const setupMediaRecorder = (newMediaRecorder) => { newMediaRecorder.ondataavailable = (e) => { mimeType.trigger(); data.value.push(e.data); }; newMediaRecorder.onstop = (...args) => { stream.value?.getTracks().forEach((t) => t.stop()); state.trigger(); mimeType.trigger(); options.onStop?.(...args); }; newMediaRecorder.onpause = (...args) => { state.trigger(); mimeType.trigger(); options.onPause?.(...args); }; newMediaRecorder.onresume = (...args) => { state.trigger(); mimeType.trigger(); options.onResume?.(...args); }; newMediaRecorder.onstart = (...args) => { state.trigger(); mimeType.trigger(); options.onStart?.(...args); }; newMediaRecorder.onerror = (...args) => { state.trigger(); mimeType.trigger(); options.onError?.(...args); }; }; const start = async (timeslice = void 0) => { if (state.value === "recording") return; data.value = []; stream.value = await navigator.mediaDevices.getUserMedia(toValue(constraints)); const mr = new MediaRecorder(stream.value, toValue(mediaRecorderOptions)); setupMediaRecorder(mr); mediaRecorder.value = mr; mediaRecorder.value?.start(timeslice); }; const stop = () => { if (!state.value || state.value === "inactive") return; mediaRecorder.value?.stop(); }; const pause = () => { if (state.value !== "recording") return; mediaRecorder.value?.pause(); }; const resume = () => { if (state.value !== "paused") return; mediaRecorder.value?.resume(); }; tryOnScopeDispose(() => { mediaRecorder.value?.stop(); }); return { start, pause, resume, stop, data, stream, state, isSupported, isMimeTypeSupported, mimeType: computed(() => mimeType.value), mediaRecorder: computed(() => mediaRecorder.value) }; }