Skip to content

Commit 1c445de

Browse files
authored
fix: determine audio recording format with MediaRecorder.isTypeSupported not userAgent (#2639)
1 parent 881e4b8 commit 1c445de

File tree

4 files changed

+37
-20
lines changed

4 files changed

+37
-20
lines changed

src/components/MediaRecorder/classes/MediaRecorderController.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,18 @@ import {
1717
} from '../../ReactFileUtilities';
1818
import { TranslationContextValue } from '../../../context';
1919
import { defaultTranslatorFunction } from '../../../i18n';
20-
import { isSafari } from '../../../utils/browsers';
2120
import { mergeDeepUndefined } from '../../../utils/mergeDeep';
2221

2322
import type { LocalVoiceRecordingAttachment } from '../../MessageInput';
2423
import type { DefaultStreamChatGenerics } from '../../../types';
2524

26-
const RECORDED_MIME_TYPE_BY_BROWSER = {
25+
export const RECORDED_MIME_TYPE_BY_BROWSER = {
2726
audio: {
2827
others: 'audio/webm',
2928
safari: 'audio/mp4;codecs=mp4a.40.2',
3029
},
3130
} as const;
3231

33-
export const DEFAULT_MEDIA_RECORDER_CONFIG: MediaRecorderConfig = {
34-
mimeType: isSafari()
35-
? RECORDED_MIME_TYPE_BY_BROWSER.audio.safari
36-
: RECORDED_MIME_TYPE_BY_BROWSER.audio.others,
37-
} as const;
38-
3932
export const DEFAULT_AUDIO_TRANSCODER_CONFIG: TranscoderConfig = {
4033
sampleRate: 16000,
4134
} as const;
@@ -120,7 +113,11 @@ export class MediaRecorderController<
120113

121114
this.mediaRecorderConfig = mergeDeepUndefined(
122115
{ ...config?.mediaRecorderConfig },
123-
DEFAULT_MEDIA_RECORDER_CONFIG,
116+
{
117+
mimeType: MediaRecorder.isTypeSupported('audio/webm')
118+
? RECORDED_MIME_TYPE_BY_BROWSER.audio.others
119+
: RECORDED_MIME_TYPE_BY_BROWSER.audio.safari,
120+
},
124121
);
125122

126123
this.transcoderConfig = mergeDeepUndefined(

src/components/MediaRecorder/classes/__tests__/MediaRecorderController.test.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import * as transcoder from '../../transcode';
33
import * as wavTranscoder from '../../transcode/wav';
44
import {
55
DEFAULT_AUDIO_TRANSCODER_CONFIG,
6-
DEFAULT_MEDIA_RECORDER_CONFIG,
76
MediaRecorderController,
87
MediaRecordingState,
8+
RECORDED_MIME_TYPE_BY_BROWSER,
99
RecordingAttachmentType,
1010
} from '../MediaRecorderController';
1111
import {
@@ -92,10 +92,27 @@ describe('MediaRecorderController', () => {
9292
});
9393
afterEach(jest.clearAllMocks);
9494

95-
it('provides defaults on initiation', () => {
95+
it('provides defaults on initiation (non-Safari)', () => {
9696
const controller = new MediaRecorderController();
9797
expect(controller.mediaRecorderConfig).toStrictEqual(
98-
expect.objectContaining(DEFAULT_MEDIA_RECORDER_CONFIG),
98+
expect.objectContaining({ mimeType: RECORDED_MIME_TYPE_BY_BROWSER.audio.others }),
99+
);
100+
expect(controller.transcoderConfig).toStrictEqual(
101+
expect.objectContaining(DEFAULT_AUDIO_TRANSCODER_CONFIG),
102+
);
103+
expect(controller.amplitudeRecorderConfig).toStrictEqual(
104+
expect.objectContaining(DEFAULT_AMPLITUDE_RECORDER_CONFIG),
105+
);
106+
expect(controller.t).toStrictEqual(defaultTranslatorFunction);
107+
expect(controller.mediaType).toStrictEqual('audio');
108+
expect(controller.customGenerateRecordingTitle).toBeUndefined();
109+
});
110+
111+
it('provides defaults on initiation (Safari)', () => {
112+
MediaRecorder.isTypeSupported.mockReturnValueOnce(false);
113+
const controller = new MediaRecorderController();
114+
expect(controller.mediaRecorderConfig).toStrictEqual(
115+
expect.objectContaining({ mimeType: RECORDED_MIME_TYPE_BY_BROWSER.audio.safari }),
99116
);
100117
expect(controller.transcoderConfig).toStrictEqual(
101118
expect.objectContaining(DEFAULT_AUDIO_TRANSCODER_CONFIG),
@@ -151,7 +168,7 @@ describe('MediaRecorderController', () => {
151168
const controller = new MediaRecorderController({ generateRecordingTitle });
152169
expect(controller.customGenerateRecordingTitle).toStrictEqual(generateRecordingTitle);
153170
expect(controller.mediaRecorderConfig).toStrictEqual(
154-
expect.objectContaining(DEFAULT_MEDIA_RECORDER_CONFIG),
171+
expect.objectContaining({ mimeType: RECORDED_MIME_TYPE_BY_BROWSER.audio.others }),
155172
);
156173
expect(controller.transcoderConfig).toStrictEqual(
157174
expect.objectContaining(DEFAULT_AUDIO_TRANSCODER_CONFIG),

src/components/MediaRecorder/hooks/__tests__/useMediaRecorder.test.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { TranslationProvider } from '../../../../context';
22
import { renderHook } from '@testing-library/react';
33
import React from 'react';
44
import { useMediaRecorder } from '../useMediaRecorder';
5-
import { EventEmitterMock } from '../../../../mock-builders/browser';
5+
import { EventEmitterMock, MediaRecorderMock } from '../../../../mock-builders/browser';
66
import { act } from '@testing-library/react';
77
import { DEFAULT_AMPLITUDE_RECORDER_CONFIG } from '../../classes/AmplitudeRecorder';
88
import { DEFAULT_AUDIO_TRANSCODER_CONFIG } from '../../classes';
99
import { generateVoiceRecordingAttachment } from '../../../../mock-builders';
1010

11+
window.MediaRecorder = MediaRecorderMock;
12+
1113
const handleSubmit = jest.fn();
1214
const uploadAttachment = jest.fn();
1315

@@ -27,8 +29,8 @@ const render = async (params = {}) => {
2729
<TranslationProvider value={translationContext}>{children}</TranslationProvider>
2830
);
2931
let result;
30-
await act(() => {
31-
result = renderHook(() => useMediaRecorder({ enabled: true, ...params }), {
32+
await act(async () => {
33+
result = await renderHook(() => useMediaRecorder({ enabled: true, ...params }), {
3234
wrapper,
3335
});
3436
});

src/mock-builders/browser/MediaRecorder.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import { EventEmitterMock } from './EventEmitter';
33
export class MediaRecorderMock extends EventEmitterMock {
44
constructor() {
55
super();
6+
this.start = jest.fn();
7+
this.pause = jest.fn();
8+
this.resume = jest.fn();
9+
this.stop = jest.fn();
610
}
711

8-
start = jest.fn();
9-
pause = jest.fn();
10-
resume = jest.fn();
11-
stop = jest.fn();
12+
static isTypeSupported = jest.fn().mockReturnValue(true);
1213
}

0 commit comments

Comments
 (0)