Skip to content

Commit

Permalink
feature(adds proper WAV codec support): (#97)
Browse files Browse the repository at this point in the history
* feature(adds proper WAV codec support):
- uses the extendable media recorder to allow use of WAV and author mime types
- fixes type issues where audio and video tags required undefined rather than null
- fixes issue where if mediaRecorderOptions are supplied the recorder stops recording after first audio blob recording

* linter issues

* removes yarn lock and updates version number
  • Loading branch information
PipesNBottles authored May 14, 2022
1 parent a906bad commit c6c8a35
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 66 deletions.
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-media-recorder",
"version": "1.6.5",
"version": "1.6.6",
"description": "A React component based on MediaRecorder() API to record audio/video streams",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -38,5 +38,9 @@
"jsmin": "^1.0.1",
"typescript": "^4.4.3"
},
"types": "./lib/index.d.ts"
"types": "./lib/index.d.ts",
"dependencies": {
"extendable-media-recorder": "^6.6.5",
"extendable-media-recorder-wav-encoder": "^7.0.68"
}
}
55 changes: 32 additions & 23 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { register, MediaRecorder as ExtendableMediaRecorder, IMediaRecorder } from "extendable-media-recorder";
import { ReactElement, useCallback, useEffect, useRef, useState } from "react";
import { connect } from 'extendable-media-recorder-wav-encoder';

export type ReactMediaRecorderRenderProps = {
error: string;
Expand All @@ -8,7 +10,7 @@ export type ReactMediaRecorderRenderProps = {
pauseRecording: () => void;
resumeRecording: () => void;
stopRecording: () => void;
mediaBlobUrl: null | string;
mediaBlobUrl: undefined | string;
status: StatusMessages;
isAudioMuted: boolean;
previewStream: MediaStream | null;
Expand All @@ -23,7 +25,7 @@ export type ReactMediaRecorderHookProps = {
onStop?: (blobUrl: string, blob: Blob) => void;
onStart?: () => void;
blobPropertyBag?: BlobPropertyBag;
mediaRecorderOptions?: MediaRecorderOptions | null;
mediaRecorderOptions?: MediaRecorderOptions | undefined;
customMediaStream?: MediaStream | null;
stopStreamsOnStop?: boolean;
askPermissionOnMount?: boolean;
Expand Down Expand Up @@ -66,19 +68,26 @@ export function useReactMediaRecorder({
onStart = () => null,
blobPropertyBag,
screen = false,
mediaRecorderOptions = null,
mediaRecorderOptions = undefined,
customMediaStream = null,
stopStreamsOnStop = true,
askPermissionOnMount = false,
}: ReactMediaRecorderHookProps): ReactMediaRecorderRenderProps {
const mediaRecorder = useRef<MediaRecorder | null>(null);
const mediaRecorder = useRef<IMediaRecorder | null >(null);
const mediaChunks = useRef<Blob[]>([]);
const mediaStream = useRef<MediaStream | null>(null);
const [status, setStatus] = useState<StatusMessages>("idle");
const [isAudioMuted, setIsAudioMuted] = useState<boolean>(false);
const [mediaBlobUrl, setMediaBlobUrl] = useState<string | null>(null);
const [mediaBlobUrl, setMediaBlobUrl] = useState<string | undefined>(undefined);
const [error, setError] = useState<keyof typeof RecorderErrors>("NONE");

useEffect(() => {
const setup = async () => {
await register(await connect());
};
setup();
}, []);

const getMediaStream = useCallback(async () => {
setStatus("acquiring_media");
const requiredMedia: MediaStreamConstraints = {
Expand All @@ -89,7 +98,6 @@ export function useReactMediaRecorder({
if (customMediaStream) {
mediaStream.current = customMediaStream;
} else if (screen) {
//@ts-ignore
const stream = (await window.navigator.mediaDevices.getDisplayMedia({
video: video || true,
})) as MediaStream;
Expand All @@ -108,7 +116,7 @@ export function useReactMediaRecorder({
mediaStream.current = stream;
} else {
const stream = await window.navigator.mediaDevices.getUserMedia(
requiredMedia
requiredMedia,
);
mediaStream.current = stream;
}
Expand All @@ -125,9 +133,8 @@ export function useReactMediaRecorder({
}

if (screen) {
//@ts-ignore
if (!window.navigator.mediaDevices.getDisplayMedia) {
throw new Error("This browser doesn't support screen capturing");
throw new Error("This browser doesn\'t support screen capturing");
}
}

Expand All @@ -136,14 +143,14 @@ export function useReactMediaRecorder({
navigator.mediaDevices.getSupportedConstraints();
const unSupportedConstraints = Object.keys(mediaType).filter(
(constraint) =>
!(supportedMediaConstraints as { [key: string]: any })[constraint]
!(supportedMediaConstraints as { [key: string]: any })[constraint],
);

if (unSupportedConstraints.length > 0) {
console.error(
`The constraints ${unSupportedConstraints.join(
","
)} doesn't support on this browser. Please check your ReactMediaRecorder component.`
",",
)} doesn't support on this browser. Please check your ReactMediaRecorder component.`,
);
}
};
Expand All @@ -158,7 +165,7 @@ export function useReactMediaRecorder({
if (mediaRecorderOptions && mediaRecorderOptions.mimeType) {
if (!MediaRecorder.isTypeSupported(mediaRecorderOptions.mimeType)) {
console.error(
`The specified MIME type you supplied for MediaRecorder doesn't support this browser`
`The specified MIME type you supplied for MediaRecorder doesn't support this browser`,
);
}
}
Expand All @@ -170,7 +177,7 @@ export function useReactMediaRecorder({
return () => {
if (mediaStream.current) {
const tracks = mediaStream.current.getTracks();
tracks.forEach((track) => track.stop());
tracks.forEach((track) => track.clone().stop());
}
};
}, [
Expand Down Expand Up @@ -201,7 +208,9 @@ export function useReactMediaRecorder({
if (!mediaStream.current.active) {
return;
}
mediaRecorder.current = new MediaRecorder(mediaStream.current, mediaRecorderOptions || undefined);
mediaRecorder.current = new ExtendableMediaRecorder(
mediaStream.current, mediaRecorderOptions || undefined,
);
mediaRecorder.current.ondataavailable = onRecordingActive;
mediaRecorder.current.onstop = onRecordingStop;
mediaRecorder.current.onstart = onRecordingStart;
Expand All @@ -226,7 +235,7 @@ export function useReactMediaRecorder({
const [chunk] = mediaChunks.current;
const blobProperty: BlobPropertyBag = Object.assign(
{ type: chunk.type },
blobPropertyBag || (video ? { type: "video/mp4" } : { type: "audio/wav" })
blobPropertyBag || (video ? { type: "video/mp4" } : { type: "audio/wav" }),
);
const blob = new Blob(mediaChunks.current, blobProperty);
const url = URL.createObjectURL(blob);
Expand Down Expand Up @@ -282,17 +291,17 @@ export function useReactMediaRecorder({
mediaBlobUrl,
status,
isAudioMuted,
previewStream: mediaStream.current
? new MediaStream(mediaStream.current.getVideoTracks())
: null,
previewAudioStream: mediaStream.current
? new MediaStream(mediaStream.current.getAudioTracks())
: null,
previewStream: mediaStream.current ?
new MediaStream(mediaStream.current.getVideoTracks()) :
null,
previewAudioStream: mediaStream.current ?
new MediaStream(mediaStream.current.getAudioTracks()) :
null,
clearBlobUrl: () => {
if (mediaBlobUrl) {
URL.revokeObjectURL(mediaBlobUrl);
}
setMediaBlobUrl(null);
setMediaBlobUrl(undefined);
setStatus("idle");
},
};
Expand Down
41 changes: 0 additions & 41 deletions yarn.lock

This file was deleted.

0 comments on commit c6c8a35

Please sign in to comment.