Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: extract MP3 encoder plugin #2447

Merged
merged 6 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,29 @@ The dialog can be customized by passing own component to `Channel` component con
<Channel RecordingPermissionDeniedNotification={CustomComponent}>
```

## Custom encoding

By default, the recording is encoded into `audio/wav` format. In order to reduce the size and keep the inter-browser format compatibility, you can use an MP3 encoder that is based on [`lamejs` implementation](https://github.com/gideonstele/lamejs). Follow these steps to achieve the MP3 encoding capability.

1. The library `@breezystack/lamejs` has to be installed as this is a peer dependency to `stream-chat-react`.
MartinCupela marked this conversation as resolved.
Show resolved Hide resolved

```shell
npm install @breezystack/lamejs
```

```shell
yarn add @breezystack/lamejs
```

2. The MP3 encoder has to be imported separately as a plugin:

```tsx
import { MessageInput } from 'stream-chat-react';
import { encodeToMp3 } from 'stream-chat-react/mp3-encoder';

<MessageInput focus audioRecordingConfig={{ transcoderConfig: { encoder: encodeToMp3 } }} />;
```

## Audio recorder states

The `AudioRecorder` UI switches between the following states
Expand Down
48 changes: 48 additions & 0 deletions docusaurus/docs/React/release-guides/upgrade-to-v12.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,48 @@ title: Upgrade to v12
keywords: [migration guide, upgrade, v12, breaking changes]
---

## Audio recordings transcoding

Until now, the audio recordings were transcoded to `audio/mp3` format for inter-browser compatibility and size reduction. However, as of the v12, the MIME type `audio/wav` will be the default. The MP3 encoder use is opt-in from now on.

:::important
**Action required**<br/>

1. The library `@breezystack/lamejs` has to be installed as this is a peer dependency to `stream-chat-react`.
MartinCupela marked this conversation as resolved.
Show resolved Hide resolved

```shell
npm install @breezystack/lamejs
```

```shell
yarn add @breezystack/lamejs
```

2. The MP3 encoder has to be imported separately as a plugin:

```tsx
import { MessageInput } from 'stream-chat-react';
import { encodeToMp3 } from 'stream-chat-react/mp3-encoder';

<MessageInput focus audioRecordingConfig={{ transcoderConfig: { encoder: encodeToMp3 } }} />;
```

:::

## EmojiPickerIcon extraction to emojis plugin

The default `EmojiPickerIcon` has been moved to emojis plugin from which we already import `EmojiPicker` component.

:::important
**Action required**<br/>
In case you are importing `EmojiPickerIcon` in your code, make sure to adjust the import as follows:

```tsx
import { EmojiPickerIcon } from 'stream-chat-react/emojis';
```

:::

## Removal of duplicate uploads state in MessageInput

As of the version 12 of `stream-chat-react` the `MessageInputContext` will not expose the following state variables:
Expand Down Expand Up @@ -138,6 +180,12 @@ Until now, it was possible to import two stylesheets as follows:
import 'stream-chat-react/dist/css/v1/index.css';
```

Or

```
import 'stream-chat-react/dist/css/v2/index.css';
```

The legacy stylesheet has been removed from the SDK bundle, and therefore it is only possible to import one stylesheet from now on:

```
Expand Down
6 changes: 4 additions & 2 deletions docusaurus/react-docusaurus-dontent-docs.plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ module.exports = {
[
'@docusaurus/plugin-content-docs',
{
lastVersion: 'current',
lastVersion: '11.x.x',
versions: {
current: {
label: 'v12',
banner: 'unreleased',
label: 'v12 (rc)',
path: 'v12',
},
'11.x.x': {
label: 'v11',
Expand Down
20 changes: 15 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@
"default": "./dist/index.js"
},
"./emojis": {
"types": "./dist/components/Emojis/index.d.ts",
"require": "./dist/components/Emojis/index.cjs.js",
"import": "./dist/components/Emojis/index.js",
"default": "./dist/components/Emojis/index.js"
"types": "./dist/plugins/Emojis/index.d.ts",
"require": "./dist/plugins/Emojis/index.cjs.js",
"import": "./dist/plugins/Emojis/index.js",
"default": "./dist/plugins/Emojis/index.js"
},
"./mp3-encoder": {
"types": "./dist/plugins/encoders/mp3.d.ts",
"require": "./dist/plugins/encoders/mp3.cjs.js",
"import": "./dist/plugins/encoders/mp3.js",
"default": "./dist/plugins/encoders/mp3.js"
},
"./dist/css/*": {
"default": "./dist/css/*"
Expand Down Expand Up @@ -60,7 +66,6 @@
],
"dependencies": {
"@braintree/sanitize-url": "^6.0.4",
"@breezystack/lamejs": "^1.2.7",
"@popperjs/core": "^2.11.5",
"@react-aria/focus": "^3",
"clsx": "^2.0.0",
Expand Down Expand Up @@ -98,6 +103,7 @@
"mml-react": "^0.4.7"
},
"peerDependencies": {
"@breezystack/lamejs": "^1.2.7",
"@emoji-mart/data": "^1.1.0",
"@emoji-mart/react": "^1.1.0",
"emoji-mart": "^5.4.0",
Expand All @@ -106,6 +112,9 @@
"stream-chat": "^8.33.1"
},
"peerDependenciesMeta": {
"@breezystack/lamejs": {
"optional": true
},
"emoji-mart": {
"optional": true
},
Expand All @@ -131,6 +140,7 @@
"@babel/preset-env": "^7.12.7",
"@babel/preset-react": "^7.23.3",
"@babel/preset-typescript": "^7.12.7",
"@breezystack/lamejs": "^1.2.7",
"@commitlint/cli": "^18.4.3",
"@commitlint/config-conventional": "^18.4.3",
"@emoji-mart/data": "^1.1.2",
Expand Down
6 changes: 3 additions & 3 deletions scripts/bundle.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import * as esbuild from 'esbuild';
const __dirname = dirname(fileURLToPath(import.meta.url));

const sdkEntrypoint = resolve(__dirname, '../src/index.ts');
const emojiEntrypoint = resolve(__dirname, '../src/components/Emojis/index.ts');
const emojiEntrypoint = resolve(__dirname, '../src/plugins/Emojis/index.ts');
const mp3EncoderEntrypoint = resolve(__dirname, '../src/plugins/encoders/mp3.ts');
const outDir = resolve(__dirname, '../dist');

// Those dependencies are distributed as ES modules, and cannot be externalized
// in our CJS bundle. We convert them to CJS and bundle them instead.
const bundledDeps = [
'@breezystack/lamejs',
'hast-util-find-and-replace',
'unist-builder',
'unist-util-visit',
Expand All @@ -32,7 +32,7 @@ const deps = Object.keys({
const external = deps.filter((dep) => !bundledDeps.includes(dep));

const cjsBundleConfig = {
entryPoints: [sdkEntrypoint, emojiEntrypoint],
entryPoints: [sdkEntrypoint, emojiEntrypoint, mp3EncoderEntrypoint],
bundle: true,
format: 'cjs',
platform: 'node',
Expand Down
1 change: 0 additions & 1 deletion src/components/Emojis/index.ts

This file was deleted.

23 changes: 6 additions & 17 deletions src/components/MediaRecorder/classes/MediaRecorderController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from './AmplitudeRecorder';
import { BrowserPermission } from './BrowserPermission';
import { BehaviorSubject, Subject } from '../observable';
import { transcode } from '../transcode';
import { transcode, TranscoderConfig } from '../transcode';
import { resampleWaveformData } from '../../Attachment';
import {
createFileFromBlobs,
Expand All @@ -30,8 +30,6 @@ const RECORDED_MIME_TYPE_BY_BROWSER = {
},
} as const;

export const POSSIBLE_TRANSCODING_MIME_TYPES = ['audio/wav', 'audio/mp3'] as const;

export const DEFAULT_MEDIA_RECORDER_CONFIG: MediaRecorderConfig = {
mimeType: isSafari()
? RECORDED_MIME_TYPE_BY_BROWSER.audio.safari
Expand All @@ -40,7 +38,6 @@ export const DEFAULT_MEDIA_RECORDER_CONFIG: MediaRecorderConfig = {

export const DEFAULT_AUDIO_TRANSCODER_CONFIG: TranscoderConfig = {
sampleRate: 16000,
targetMimeType: 'audio/mp3',
} as const;

const disposeOfMediaStream = (stream?: MediaStream) => {
Expand All @@ -53,15 +50,6 @@ const disposeOfMediaStream = (stream?: MediaStream) => {

const logError = (e?: Error) => e && console.error('[MEDIA RECORDER ERROR]', e);

type SupportedTranscodeMimeTypes = typeof POSSIBLE_TRANSCODING_MIME_TYPES[number];

export type TranscoderConfig = {
// defaults to 16000Hz
sampleRate: number;
// Defaults to audio/mp3;
targetMimeType: SupportedTranscodeMimeTypes;
};

type MediaRecorderConfig = Omit<MediaRecorderOptions, 'mimeType'> &
Required<Pick<MediaRecorderOptions, 'mimeType'>>;

Expand All @@ -71,8 +59,12 @@ export type AudioRecorderConfig = {
transcoderConfig: TranscoderConfig;
};

type PartialValues<T> = { [P in keyof T]?: Partial<T[P]> };

export type CustomAudioRecordingConfig = PartialValues<AudioRecorderConfig>;

export type AudioRecorderOptions = {
config?: Partial<AudioRecorderConfig>;
config?: CustomAudioRecordingConfig;
generateRecordingTitle?: (mimeType: string) => string;
t?: TranslationContextValue['t'];
};
Expand Down Expand Up @@ -135,9 +127,6 @@ export class MediaRecorderController<
{ ...config?.transcoderConfig },
DEFAULT_AUDIO_TRANSCODER_CONFIG,
);
if (!POSSIBLE_TRANSCODING_MIME_TYPES.includes(this.transcoderConfig.targetMimeType)) {
this.transcoderConfig.targetMimeType = DEFAULT_AUDIO_TRANSCODER_CONFIG.targetMimeType;
}

const mediaType = getRecordedMediaTypeFromMimeType(this.mediaRecorderConfig.mimeType);
if (!mediaType) {
Expand Down
Loading
Loading