# Voice Recording Attachment

> **Info:** This is release candidate documentation for **Stream Chat React SDK v15**. For the latest stable version, see the [latest version (v14)](https://getstream.io/chat/docs/sdk/react/).

`VoiceRecording` renders an attachment of type `voiceRecording`. In a message it renders `VoiceRecordingPlayer`, which plays the recording; when `Attachment` gets `isQuoted`, it renders `QuotedVoiceRecording`, a short summary. [Voice recordings and audio playback](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/voice-recordings-and-audio-playback/) explains recording, sending and playback.

## Best practices

- Replace it through the `VoiceRecording` prop of `Attachment`, and register that `Attachment` as the `Attachment` override. `VoiceRecording` has no override key of its own.
- Render the player inside `Channel`, `Thread` or `WithAudioPlayback`. Outside them there is no audio player to use, and it renders nothing.
- Render it inside a message. The player is identified by the message and the file, so two messages with the same file get separate players.
- Read the recording's metadata under `custom`, as the table below shows.
- Make small visual changes with CSS before replacing the components.

## Attachment payload

| Field                  | Type       | What the SDK does with it                                                                                              |
| ---------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------- |
| `type`                 | `string`   | Always `"voiceRecording"`. `isVoiceRecordingAttachment()` from `stream-chat` checks it.                                |
| `asset_url`            | `string`   | The file the player plays. While the upload runs, the player plays the local file.                                     |
| `title`                | `string`   | The audio player's `title`. Recordings made in the composer are named `audio_recording_<date>.<extension>`.            |
| `custom.duration`      | `number`   | The length in seconds. The player counts it down as the time left.                                                     |
| `custom.file_size`     | `number`   | The size in bytes, shown when there is no duration.                                                                    |
| `custom.mime_type`     | `string`   | The file type. The player checks that the browser can play it, and `QuotedVoiceRecording` picks its file icon from it. |
| `custom.waveform_data` | `number[]` | Amplitudes between 0 and 1, drawn as the waveform.                                                                     |

In `stream-chat`, the type is `VoiceRecordingAttachment`.

## VoiceRecordingPlayer

The player shows, from start to end:

- a play button;
- the time left, which is the whole length before playback starts. While the recording uploads, the upload progress shows instead, and without a duration, the file size;
- the waveform, `WaveProgressBar`. Clicking or dragging on it seeks, and the bars before the position are highlighted;
- the speed button, `PlaybackRateButton`, which shows the speed, such as `x1`, and moves to the next one on each click, back to the first after the last. It's disabled when the browser can't play the file type.

![A voice recording paused after seeking](https://getstream.io/docs-assets/images/82973191cf53.png)

| Prop            | Type         | Default       | Description                                                                     |
| --------------- | ------------ | ------------- | ------------------------------------------------------------------------------- |
| `attachment`    | `Attachment` | required      | The voice recording.                                                            |
| `playbackRates` | `number[]`   | `[1, 1.5, 2]` | The speeds the speed button moves through. The first one is the starting speed. |

### QuotedVoiceRecording

It shows the length, or the file size when there is no duration, and a file icon for the type. It has no player.

| Prop         | Type         | Default  | Description          |
| ------------ | ------------ | -------- | -------------------- |
| `attachment` | `Attachment` | required | The voice recording. |

The SDK's own quoted message doesn't render attachments. When the quoted message has no text, it shows "Voice message" and the length, from the translation key `messageComposer.quotedMessagePreview.voiceMessage.label`.

![A reply quoting a voice message](https://getstream.io/docs-assets/images/8b36bd39d67c.png)

### VoiceRecording

| Prop         | Type         | Default  | Description                                           |
| ------------ | ------------ | -------- | ----------------------------------------------------- |
| `attachment` | `Attachment` | required | The voice recording.                                  |
| `isQuoted`   | `boolean`    | `false`  | Renders `QuotedVoiceRecording` instead of the player. |

## UI fallbacks

| Missing                | What shows instead                                                                                                                                                                                     |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `custom.duration`      | The file size, in the player and in `QuotedVoiceRecording`.                                                                                                                                            |
| `custom.waveform_data` | No waveform. The player keeps its play and speed buttons.                                                                                                                                              |
| `title`                | The translation of `common.voiceMessage.label`, "Voice message", becomes the audio player's `title`. The default player doesn't display the title; a player bar built on `useActiveAudioPlayer()` can. |

![A voice recording without waveform data](https://getstream.io/docs-assets/images/5e71959e17d5.png)

![A voice recording showing its file size instead of its length](https://getstream.io/docs-assets/images/9b0b14f50879.png)

To change the fallback title, translate `common.voiceMessage.label`; see [Localization](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/localization/).

## Default components customization

Wrap `Attachment`, pass it your own `VoiceRecording`, and register the wrapper as the `Attachment` override. This one keeps the default player with two speeds:

```tsx
import type { AttachmentProps, VoiceRecordingProps } from "stream-chat-react";
import {
  Attachment,
  QuotedVoiceRecording,
  VoiceRecordingPlayer,
} from "stream-chat-react";

const playbackRates = [1, 2];

const TwoSpeedVoiceRecording = ({
  attachment,
  isQuoted,
}: VoiceRecordingProps) =>
  isQuoted ? (
    <QuotedVoiceRecording attachment={attachment} />
  ) : (
    <VoiceRecordingPlayer
      attachment={attachment}
      playbackRates={playbackRates}
    />
  );

// Register as the Attachment override: <WithComponents overrides={{ Attachment: TwoSpeedAttachment }}>
export const TwoSpeedAttachment = (props: AttachmentProps) => (
  <Attachment {...props} VoiceRecording={TwoSpeedVoiceRecording} />
);
```

For a player of your own, build it on `useAudioPlayer()`, as [A player of your own](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/voice-recordings-and-audio-playback/#a-player-of-your-own) shows. The SDK's parts are exported for it: `PlayButton`, `WaveProgressBar`, `PlaybackRateButton`, `DurationDisplay` and `FileSizeIndicator`.

## Related hooks

| Hook                                   | Returns                                                                                                                               |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `useAudioPlayer(options)`              | the audio player for a `src` and a `requester`, from the nearest `Channel`, `Thread` or `WithAudioPlayback`; `undefined` outside them |
| `useActiveAudioPlayer()`               | the player that started playing most recently, if any                                                                                 |
| `useAttachmentUploadState(attachment)` | the attachment's upload state, which the player uses to show the progress                                                             |

[Playback](https://getstream.io/chat/docs/sdk/react/v15/features/rich-content/voice-recordings-and-audio-playback/#playback) explains the audio players and their state.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v15/component-reference/voice-recording/voice-recording-attachment/](https://getstream.io/chat/docs/sdk/react/v15/component-reference/voice-recording/voice-recording-attachment/).