# react-media-recorder :o2: :video_camera: :microphone: :computer:

`react-media-recorder` is a fully typed react component with render prop, or a react hook, that can be used to:

- Record audio/video
- Record screen

using [MediaRecorder API](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder).

## Installation

```
npm i react-media-recorder
```

or

```
yarn add react-media-recorder
```

## Usage

```javascript
import { ReactMediaRecorder } from "react-media-recorder";

const RecordView = () => (
  <div>
    <ReactMediaRecorder
      video
      render={({ status, startRecording, stopRecording, mediaBlobUrl }) => (
        <div>
          <p>{status}</p>
          <button onClick={startRecording}>Start Recording</button>
          <button onClick={stopRecording}>Stop Recording</button>
          <video src={mediaBlobUrl} controls autoPlay loop />
        </div>
      )}
    />
  </div>
);
```

Since `react-media-recording` uses render prop, you can define what to render in the view. Just don't forget to wire the `startRecording`, `stopRecording` and `mediaBlobUrl` to your component.

## Usage with react hooks

```javascript
import { useReactMediaRecorder } from "react-media-recorder";

const RecordView = () => {
  const { status, startRecording, stopRecording, mediaBlobUrl } =
    useReactMediaRecorder({ video: true });

  return (
    <div>
      <p>{status}</p>
      <button onClick={startRecording}>Start Recording</button>
      <button onClick={stopRecording}>Stop Recording</button>
      <video src={mediaBlobUrl} controls autoPlay loop />
    </div>
  );
};
```

The hook receives an object as argument with the same ReactMediaRecorder options / props (except the `render` function).

### Options / Props

#### audio

Can be either a boolean value or a [MediaTrackConstraints](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints) object.

type: `boolean` or `object`
default: `true`

#### blobPropertyBag

[From MDN](https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob):
An optional `BlobPropertyBag` dictionary which may specify the following two attributes (for the `mediaBlob`):

- `type`, that represents the MIME type of the content of the array that will be put in the blob.
- `endings`, with a default value of "transparent", that specifies how strings containing the line ending character \n are to be written out. It is one of the two values: "native", meaning that line ending characters are changed to match host OS filesystem convention, or "transparent", meaning that endings are stored in the blob without change

type: `object`
default:
if `video` is enabled,

```
{
   type: "video/mp4"
}
```

if there's only `audio` is enabled,

```
{
  type: "audio/wav"
}
```

#### customMediaStream

A media stream object itself (optional)

#### mediaRecorderOptions

An optional options object that will be passed to `MediaRecorder`. Please note that if you specify the MIME type via either `audio` or `video` prop _and_ through this `mediaRecorderOptions`, the `mediaRecorderOptions` have higher precedence.

type: `object`
default: `{}`

#### onStart

A `function` that would get invoked when the MediaRecorder starts.

type: `function()`
default: `() => null`

#### onStop

A `function` that would get invoked when the MediaRecorder stops. It'll provide the blob and the blob url as its params.

type: `function(blobUrl: string, blob: Blob)`
default: `() => null`

#### stopStreamsOnStop

Whether to stop all streams on stop. By default, its `true`

#### render

A `function` which accepts an object containing fields: `status`, `startRecording`, `stopRecording` and`mediaBlob`. This function would return a react element/component.

type: `function`
default: `() => null`

#### screen

A `boolean` value. Lets you to record your current screen. Not all browsers would support this. Please [check here](https://caniuse.com/#search=getDisplayMedia) for the availability. Please note that at the moment, the MediaRecorder won't record two alike streams at a time, if you provide both `screen` and `video` prop, the **screen capturing will take precedence** than the video capturing. But, you can provide the `video` prop (_as the MediaTrackConstraints_) which will then utilized by screen capture (for example, `height`, `width` etc..)

#### video

Can be either a boolean value or a [MediaTrackConstraints](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints) object.

type: `boolean` or `object`
default: `false`

#### askPermissionOnMount

A boolean value. If set to `true`, will ask media permission on mounting.

type: `boolean`
default: `false`

#### preferCurrentTab

A boolean value. If set to `true`, the browser will offer the current tab as the most prominent capture source, i.e. as a separate "This Tab" option in the "Choose what to share" options presented to the user.

type: `boolean`
default: `false`

#### selfBrowserSurface

An enumerated value specifying whether the browser should allow the user to select the current tab for capture. Possible values are `include`, which hints that the browser should include the current tab in the choices offered for capture, and `exclude`, which hints that it should be excluded.

type: `undefined` | `'include'` | `'exclude'`;
default: `undefined`

### Props available in the `render` function

#### error

A string enum. Possible values:

- `media_aborted`
- `permission_denied`
- `no_specified_media_found`
- `media_in_use`
- `invalid_media_constraints`
- `no_constraints`
- `recorder_error`

#### status

A string `enum`. Possible values:

- `media_aborted`
- `permission_denied`
- `no_specified_media_found`
- `media_in_use`
- `invalid_media_constraints`
- `no_constraints`
- `recorder_error`
- `idle`
- `acquiring_media`
- `recording`
- `stopping`
- `stopped`

#### startRecording

A `function`, which starts recording when invoked.

#### pauseRecording

A `function`, which pauses the recording when invoked.

#### resumeRecording

A `function`, which resumes the recording when invoked.

#### stopRecording

A `function`, which stops recording when invoked.

#### muteAudio

A `function`, which mutes the audio tracks when invoked.

#### unmuteAudio

A `function` which unmutes the audio tracks when invoked.

#### mediaBlobUrl

A `blob` url that can be wired to an `<audio />`, `<video />` or an `<a />` element.

#### clearBlobUrl

A `function` which clears the existing generated blob url (if any) and resets the workflow to its initial `idle` state.

#### isMuted

A boolean prop that tells whether the audio is muted or not.

#### previewStream

If you want to create a live-preview of the video to the user, you can use this _stream_ and attach it to a `<video />` element. Please note that this is a **muted stream**. This is by design to get rid of internal microphone feedbacks on machines like laptop.

For example:

```tsx
const VideoPreview = ({ stream }: { stream: MediaStream | null }) => {
  const videoRef = useRef<HTMLVideoElement>(null);

  useEffect(() => {
    if (videoRef.current && stream) {
      videoRef.current.srcObject = stream;
    }
  }, [stream]);
  if (!stream) {
    return null;
  }
  return <video ref={videoRef} width={500} height={500} autoPlay controls />;
};

const App = () => (
  <ReactMediaRecorder
    video
    render={({ previewStream }) => {
      return <VideoPreview stream={previewStream} />;
    }}
  />
);
```

#### previewAudioStream

If you want access to the live audio stream for use in sound visualisations, you can use this _stream_ as your audio source and extract data from it using the [AudioContext](https://developer.mozilla.org/en-US/docs/Web/API/AudioContext) and [AnalyzerNode](https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode) features of the Web Audio API. Some javascript examples of how to do this can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Visualizations_with_Web_Audio_API).

## Contributing

Feel free to submit a PR if you found a bug (I might've missed many! :grinning:) or if you want to enhance it further.

Thanks!. Happy Recording!
