Skip to content

Commit

Permalink
fix: extend async audio modules with overridable options
Browse files Browse the repository at this point in the history
  • Loading branch information
isekovanic committed Dec 20, 2024
1 parent 909f79a commit 9397f3d
Show file tree
Hide file tree
Showing 9 changed files with 539 additions and 388 deletions.
26 changes: 0 additions & 26 deletions examples/ExpoMessaging/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1881,14 +1881,6 @@
find-up "^5.0.0"
js-yaml "^4.1.0"

"@gorhom/bottom-sheet@^4.6.4":
version "4.6.4"
resolved "https://registry.yarnpkg.com/@gorhom/bottom-sheet/-/bottom-sheet-4.6.4.tgz#387d0f0f21e3470eb8575498cb81ce96f5108e79"
integrity sha512-0itLMblLBvepE065w3a60S030c2rNUsGshPC7wbWDm31VyqoaU2xjzh/ojH62YIJOcobBr5QoC30IxBBKDGovQ==
dependencies:
"@gorhom/portal" "1.0.14"
invariant "^2.2.4"

"@gorhom/bottom-sheet@^5.0.6":
version "5.0.6"
resolved "https://registry.yarnpkg.com/@gorhom/bottom-sheet/-/bottom-sheet-5.0.6.tgz#f20736502399c7bcf8c73ea09e6b571dc07fe0eb"
Expand Down Expand Up @@ -7034,24 +7026,6 @@ [email protected], stream-buffers@~2.2.0:
version "0.0.0"
uid ""

[email protected]:
version "5.44.1"
resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-5.44.1.tgz#0c4629ba01390574dabb963e2e805eb38602d2d4"
integrity sha512-cJqfsogmiTwK93kpPQhwaOl+whkH05JFl4k501r0VJbm6xlzv5eVb3NZfi6bX1z2xrILYHC5BFabM0RsX/xL/Q==
dependencies:
"@gorhom/bottom-sheet" "^4.6.4"
dayjs "1.10.5"
emoji-regex "^10.3.0"
i18next "^21.6.14"
intl-pluralrules "^2.0.1"
linkifyjs "^4.1.1"
lodash-es "4.17.21"
mime-types "^2.1.34"
path "0.12.7"
react-native-markdown-package "1.8.2"
react-native-url-polyfill "^1.3.0"
stream-chat "8.46.0"

"stream-chat-react-native-core@link:../../package":
version "0.0.0"
uid ""
Expand Down
2 changes: 2 additions & 0 deletions package/expo-package/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
getPhotos,
iOS14RefreshGallerySelection,
oniOS14GalleryLibrarySelectionChange,
overrideAudioRecordingConfiguration,
pickDocument,
pickImage,
saveFile,
Expand All @@ -31,6 +32,7 @@ registerNativeHandlers({
getPhotos,
iOS14RefreshGallerySelection,
oniOS14GalleryLibrarySelectionChange,
overrideAudioRecordingConfiguration,
pickDocument,
pickImage,
saveFile,
Expand Down
270 changes: 38 additions & 232 deletions package/expo-package/src/optionalDependencies/Audio.ts
Original file line number Diff line number Diff line change
@@ -1,216 +1,13 @@
import { AudioComponent, RecordingObject } from './AudioVideo';

export enum AndroidOutputFormat {
DEFAULT = 0,
THREE_GPP = 1,
MPEG_4 = 2,
AMR_NB = 3,
AMR_WB = 4,
AAC_ADIF = 5,
AAC_ADTS = 6,
RTP_AVP = 7,
MPEG2TS = 8,
WEBM = 9,
}

// @docsMissing
export enum AndroidAudioEncoder {
DEFAULT = 0,
AMR_NB = 1,
AMR_WB = 2,
AAC = 3,
HE_AAC = 4,
AAC_ELD = 5,
}

export enum IOSOutputFormat {
LINEARPCM = 'lpcm',
AC3 = 'ac-3',
'60958AC3' = 'cac3',
APPLEIMA4 = 'ima4',
MPEG4AAC = 'aac ',
MPEG4CELP = 'celp',
MPEG4HVXC = 'hvxc',
MPEG4TWINVQ = 'twvq',
MACE3 = 'MAC3',
MACE6 = 'MAC6',
ULAW = 'ulaw',
ALAW = 'alaw',
QDESIGN = 'QDMC',
QDESIGN2 = 'QDM2',
QUALCOMM = 'Qclp',
MPEGLAYER1 = '.mp1',
MPEGLAYER2 = '.mp2',
MPEGLAYER3 = '.mp3',
APPLELOSSLESS = 'alac',
MPEG4AAC_HE = 'aach',
MPEG4AAC_LD = 'aacl',
MPEG4AAC_ELD = 'aace',
MPEG4AAC_ELD_SBR = 'aacf',
MPEG4AAC_ELD_V2 = 'aacg',
MPEG4AAC_HE_V2 = 'aacp',
MPEG4AAC_SPATIAL = 'aacs',
AMR = 'samr',
AMR_WB = 'sawb',
AUDIBLE = 'AUDB',
ILBC = 'ilbc',
DVIINTELIMA = 0x6d730011,
MICROSOFTGSM = 0x6d730031,
AES3 = 'aes3',
ENHANCEDAC3 = 'ec-3',
}

export enum IOSAudioQuality {
MIN = 0,
LOW = 0x20,
MEDIUM = 0x40,
HIGH = 0x60,
MAX = 0x7f,
}
import {
AndroidAudioEncoder,
AndroidOutputFormat,
ExpoAudioRecordingConfiguration as AudioRecordingConfiguration,
IOSAudioQuality,
IOSOutputFormat,
ExpoRecordingOptions as RecordingOptions,
} from 'stream-chat-react-native-core';

export type RecordingOptionsAndroid = {
/**
* The desired audio encoder. See the [`AndroidAudioEncoder`](#androidaudioencoder) enum for all valid values.
*/
audioEncoder: AndroidAudioEncoder | number;
/**
* The desired file extension. Example valid values are `.3gp` and `.m4a`.
* For more information, see the [Android docs](https://developer.android.com/guide/topics/media/media-formats)
* for supported output formats.
*/
extension: string;
/**
* The desired file format. See the [`AndroidOutputFormat`](#androidoutputformat) enum for all valid values.
*/
outputFormat: AndroidOutputFormat | number;
/**
* The desired bit rate.
*
* Note that `prepareToRecordAsync()` may perform additional checks on the parameter to make sure whether the specified
* bit rate is applicable, and sometimes the passed bitRate will be clipped internally to ensure the audio recording
* can proceed smoothly based on the capabilities of the platform.
*
* @example `128000`
*/
bitRate?: number;
/**
* The desired maximum file size in bytes, after which the recording will stop (but `stopAndUnloadAsync()` must still
* be called after this point).
*
* @example `65536`
*/
maxFileSize?: number;
/**
* The desired number of channels.
*
* Note that `prepareToRecordAsync()` may perform additional checks on the parameter to make sure whether the specified
* number of audio channels are applicable.
*
* @example `1`, `2`
*/
numberOfChannels?: number;
/**
* The desired sample rate.
*
* Note that the sampling rate depends on the format for the audio recording, as well as the capabilities of the platform.
* For instance, the sampling rate supported by AAC audio coding standard ranges from 8 to 96 kHz,
* the sampling rate supported by AMRNB is 8kHz, and the sampling rate supported by AMRWB is 16kHz.
* Please consult with the related audio coding standard for the supported audio sampling rate.
*
* @example 44100
*/
sampleRate?: number;
};

export type RecordingOptionsIOS = {
/**
* The desired audio quality. See the [`IOSAudioQuality`](#iosaudioquality) enum for all valid values.
*/
audioQuality: IOSAudioQuality | number;
/**
* The desired bit rate.
*
* @example `128000`
*/
bitRate: number;
/**
* The desired file extension.
*
* @example `'.caf'`
*/
extension: string;
/**
* The desired number of channels.
*
* @example `1`, `2`
*/
numberOfChannels: number;
/**
* The desired sample rate.
*
* @example `44100`
*/
sampleRate: number;
/**
* The desired bit depth hint.
*
* @example `16`
*/
bitDepthHint?: number;
/**
* The desired bit rate strategy. See the next section for an enumeration of all valid values of `bitRateStrategy`.
*/
bitRateStrategy?: number;
/**
* The desired PCM bit depth.
*
* @example `16`
*/
linearPCMBitDepth?: number;
/**
* A boolean describing if the PCM data should be formatted in big endian.
*/
linearPCMIsBigEndian?: boolean;
/**
* A boolean describing if the PCM data should be encoded in floating point or integral values.
*/
linearPCMIsFloat?: boolean;
/**
* The desired file format. See the [`IOSOutputFormat`](#iosoutputformat) enum for all valid values.
*/
outputFormat?: string | IOSOutputFormat | number;
};

// @docsMissing
export type RecordingOptionsWeb = {
bitsPerSecond?: number;
mimeType?: string;
};

export type RecordingOptions = {
/**
* Recording options for the Android platform.
*/
android: RecordingOptionsAndroid;
/**
* Recording options for the iOS platform.
*/
ios: RecordingOptionsIOS;
/**
* Recording options for the Web platform.
*/
web: RecordingOptionsWeb;
/**
* A boolean that determines whether audio level information will be part of the status object under the "metering" key.
*/
isMeteringEnabled?: boolean;
/**
* A boolean that hints to keep the audio active after `prepareToRecordAsync` completes.
* Setting this value can improve the speed at which the recording starts. Only set this value to `true` when you call `startAsync`
* immediately after `prepareToRecordAsync`. This value is automatically set when using `Audio.recording.createAsync()`.
*/
keepAudioActiveHint?: boolean;
};
import { AudioComponent, RecordingObject } from './AudioVideo';

const sleep = (ms: number) =>
new Promise<void>((resolve) => {
Expand All @@ -221,6 +18,29 @@ const sleep = (ms: number) =>

class _Audio {
recording: typeof RecordingObject | null = null;
audioRecordingConfiguration: AudioRecordingConfiguration = {
mode: {
allowsRecordingIOS: true,
playsInSilentModeIOS: true,
},
options: {
android: {
audioEncoder: AndroidAudioEncoder.AAC,
extension: '.aac',
outputFormat: AndroidOutputFormat.AAC_ADTS,
},
ios: {
audioQuality: IOSAudioQuality.HIGH,
bitRate: 128000,
extension: '.aac',
numberOfChannels: 2,
outputFormat: IOSOutputFormat.MPEG4AAC,
sampleRate: 44100,
},
isMeteringEnabled: true,
web: {},
},
};

startRecording = async (recordingOptions: RecordingOptions, onRecordingStatusUpdate) => {
try {
Expand All @@ -242,28 +62,10 @@ class _Audio {
if (!permissionsGranted) {
throw new Error('Missing audio recording permission.');
}
await AudioComponent.setAudioModeAsync({
allowsRecordingIOS: true,
playsInSilentModeIOS: true,
});
const androidOptions = {
audioEncoder: AndroidAudioEncoder.AAC,
extension: '.aac',
outputFormat: AndroidOutputFormat.AAC_ADTS,
};
const iosOptions = {
audioQuality: IOSAudioQuality.HIGH,
bitRate: 128000,
extension: '.aac',
numberOfChannels: 2,
outputFormat: IOSOutputFormat.MPEG4AAC,
sampleRate: 44100,
};
await AudioComponent.setAudioModeAsync(this.audioRecordingConfiguration.mode);
const options = {
...recordingOptions,
android: androidOptions,
ios: iosOptions,
web: {},
...this.audioRecordingConfiguration.options,
};

// This is a band-aid fix for this (still unresolved) issue on Expo's side:
Expand Down Expand Up @@ -303,4 +105,8 @@ class _Audio {
};
}

export const overrideAudioRecordingConfiguration = (
audioRecordingConfiguration: AudioRecordingConfiguration,
) => audioRecordingConfiguration;

export const Audio = AudioComponent ? new _Audio() : null;
18 changes: 9 additions & 9 deletions package/expo-package/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1439,10 +1439,10 @@
find-up "^5.0.0"
js-yaml "^4.1.0"

"@gorhom/bottom-sheet@^4.6.4":
version "4.6.4"
resolved "https://registry.yarnpkg.com/@gorhom/bottom-sheet/-/bottom-sheet-4.6.4.tgz#387d0f0f21e3470eb8575498cb81ce96f5108e79"
integrity sha512-0itLMblLBvepE065w3a60S030c2rNUsGshPC7wbWDm31VyqoaU2xjzh/ojH62YIJOcobBr5QoC30IxBBKDGovQ==
"@gorhom/bottom-sheet@^5.0.6":
version "5.0.6"
resolved "https://registry.yarnpkg.com/@gorhom/bottom-sheet/-/bottom-sheet-5.0.6.tgz#f20736502399c7bcf8c73ea09e6b571dc07fe0eb"
integrity sha512-SI/AhPvgRfnCWN6/+wbE6TXwRE4X8F2fLyE4L/0bRwgE34Zenq585qLT139uEcfCIyovC2swC3ICqQpkmWEcFA==
dependencies:
"@gorhom/portal" "1.0.14"
invariant "^2.2.4"
Expand Down Expand Up @@ -5113,12 +5113,12 @@ [email protected], stream-buffers@~2.2.0:
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==

stream-chat-react-native-core@5.44.2:
version "5.44.2"
resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-5.44.2.tgz#7195084d87a6ab1c4c45d7017278b06c08bf755d"
integrity sha512-WEYDzftNSQRIzn40J3JGXbX4iuDrb0wWegpLIFm4AVmzSDrR93PEr1wkdonoFK7RlO9XslVPXzDxKbZyWQ5gmA==
stream-chat-react-native-core@6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.0.0.tgz#77798c7082877572ef70223e1f799d22f0c78fe7"
integrity sha512-3cFao8iL2MjP7nhVRAl1vi526FbPlqUj4BHnYQ7sUNe+xb4z/HCEL6fKFh8kIfK5MEAacOQO4juPPQktoIf7zg==
dependencies:
"@gorhom/bottom-sheet" "^4.6.4"
"@gorhom/bottom-sheet" "^5.0.6"
dayjs "1.10.5"
emoji-regex "^10.3.0"
i18next "^21.6.14"
Expand Down
Loading

0 comments on commit 9397f3d

Please sign in to comment.