From 709d0018e0896be071179ee7066603750018625f Mon Sep 17 00:00:00 2001 From: Alessio Emireni Date: Fri, 30 Jun 2023 11:13:16 +0200 Subject: [PATCH] fix compilation error and add setAllowHapticsAndSystemSoundsDuringRecording options --- README.md | 47 +++++++++++++++-------------- index.d.ts | 18 +++++++---- index.js | 64 ++++++++++++++++++++++++---------------- ios/RNSoundLevelModule.m | 9 ++++-- 4 files changed, 82 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index ba9481c..b114cf9 100644 --- a/README.md +++ b/README.md @@ -9,20 +9,21 @@ Install the npm package and link it to your project: npm i react-native-sound-level --save ``` -On *iOS* you need to add a usage description to `Info.plist`: +On _iOS_ you need to add a usage description to `Info.plist`: ``` NSMicrophoneUsageDescription This sample uses the microphone to analyze sound level. ``` -On *Android* you need to add a permission to `AndroidManifest.xml`: +On _Android_ you need to add a permission to `AndroidManifest.xml`: ``` ``` ### Manual installation on iOS + ``` In XCode, in the project navigator: @@ -37,64 +38,66 @@ In XCode, in the project navigator, select your project. ``` ### Installation on Ubuntu + 1. Add to package.json: `"desktopExternalModules": [ "node_modules/react-native-sound-level/desktop" ]` 2. You may need to make QT's multimedia library accessible for linker -`sudo ln -s $YOUR_QT_DIR/5.9.1/gcc_64/lib/libQt5Multimedia.so /usr/local/lib/libQt5Multimedia.so` - + `sudo ln -s $YOUR_QT_DIR/5.9.1/gcc_64/lib/libQt5Multimedia.so /usr/local/lib/libQt5Multimedia.so` ### React Native 0.60+ + To make it run correctly on iOS you may need the following: + 1. Add `pod 'react-native-sound-level', :podspec => '../node_modules/react-native-sound-level/RNSoundLevel.podspec'` to your `ios/Podfile` file. 2. Unlink the library if linked before (`react-native unlink react-native-sound-level`). 3. Run `pod install` from within your project `ios` directory - ### Usage 1. Request permission to access microphone, handle the UI by yourself. -You may use [react-native-permissions](https://www.npmjs.com/package/react-native-permissions) package or simply -[PermissionsAndroid](https://reactnative.dev/docs/permissionsandroid) module. + You may use [react-native-permissions](https://www.npmjs.com/package/react-native-permissions) package or simply + [PermissionsAndroid](https://reactnative.dev/docs/permissionsandroid) module. 2. Configure the monitor and start it. 3. Makes sense to stop it when not used. ```ts -import RNSoundLevel from 'react-native-sound-level' +import RNSoundLevel from "react-native-sound-level"; -const MONITOR_INTERVAL = 250 // in ms +const MONITOR_INTERVAL = 250; // in ms const requestPermission = async () => { // request permission to access microphone // ... if (success) { // start monitoring - RNSoundLevel.start() - + RNSoundLevel.start(); + // you may also specify a monitor interval (default is 250ms) - RNSoundLevel.start(MONITOR_INTERVAL) - + RNSoundLevel.start(MONITOR_INTERVAL); + // or add even more options RNSoundLevel.start({ monitorInterval: MONITOR_INTERVAL, samplingRate: 16000, // default is 22050 - }) + allowHapticsAndSystemSoundsDuringRecording: true, // Allow Haptic and System sound during recording. Default is false + }); } -} +}; useEffect(() => { RNSoundLevel.onNewFrame = (data) => { // see "Returned data" section below - console.log('Sound level info', data) - } - + console.log("Sound level info", data); + }; + return () => { // don't forget to stop it - RNSoundLevel.stop() - } -}, []) - + RNSoundLevel.stop(); + }; +}, []); ``` ### Returned data + ``` { "id", // frame number diff --git a/index.d.ts b/index.d.ts index 0c90704..b30ec77 100644 --- a/index.d.ts +++ b/index.d.ts @@ -14,21 +14,27 @@ export type SoundLevelResult = { * @description raw level value, OS-depended */ rawValue: number; -} +}; export type SoundLevelMonitorConfig = { - monitoringInterval?: number - samplingRate?: number -} + monitoringInterval?: number; + samplingRate?: number; +}; + +export type SoundLevelConfigiOS = { + allowHapticsAndSystemSoundsDuringRecording?: boolean; +}; + +export type SoundLevelConfig = SoundLevelMonitorConfig & SoundLevelConfigiOS; export type SoundLevelType = { /** * @description monitoringInterval is not supported for desktop yet */ - start: (config?: number | SoundLevelMonitorConfig) => void; + start: (config?: number | SoundLevelConfig) => void; stop: () => void; onNewFrame: (result: SoundLevelResult) => void; -} +}; declare const SoundLevel: SoundLevelType; diff --git a/index.js b/index.js index 8d62ec7..86226f3 100644 --- a/index.js +++ b/index.js @@ -1,62 +1,74 @@ -'use strict' +"use strict"; -import { NativeModules, NativeAppEventEmitter, Platform } from 'react-native' +import { NativeModules, NativeAppEventEmitter, Platform } from "react-native"; var SoundLevelModule = - Platform.OS === 'desktop' + Platform.OS === "desktop" ? NativeModules.RNSoundLevel - : NativeModules.RNSoundLevelModule + : NativeModules.RNSoundLevelModule; var SoundLevel = { timer: null, start: function (_monitorConfig = 250) { const monitorConfig = { - monitorInterval: 250, - samplingRate: 22050, - } + monitorInterval: _monitorConfig?.monitorInterval ?? 250, + samplingRate: _monitorConfig?.samplingRate ?? 22050, + allowHapticsAndSystemSoundsDuringRecording: + _monitorConfig?.allowHapticsAndSystemSoundsDuringRecording ?? false, + }; - if (typeof _monitorConfig === 'number') { - monitorConfig.monitorInterval = _monitorConfig + if (typeof _monitorConfig === "number") { + monitorConfig.monitorInterval = _monitorConfig; } if (this.frameSubscription) { - this.frameSubscription.remove() + this.frameSubscription.remove(); } - if (Platform.OS === 'desktop') { + if (Platform.OS === "desktop") { this.timer = setInterval(async () => { if (this.onNewFrame) { - const frame = await SoundLevelModule.measure() - this.onNewFrame(JSON.parse(frame)) + const frame = await SoundLevelModule.measure(); + this.onNewFrame(JSON.parse(frame)); } - }, monitorConfig.monitorInterval) + }, monitorConfig.monitorInterval); } else { this.frameSubscription = NativeAppEventEmitter.addListener( - 'frame', - data => { + "frame", + (data) => { if (this.onNewFrame) { - this.onNewFrame(data) + this.onNewFrame(data); } } - ) + ); } - // Monitoring interval not supported for Android yet. Feel free to add and do a pull request. :) - return Platform.OS !== 'desktop' ? SoundLevelModule.start(monitorConfig.monitorInterval, monitorConfig.samplingRate) : SoundLevelModule.start() + return Platform.OS === "ios" + ? SoundLevelModule.start( + monitorConfig.monitorInterval, + monitorConfig.samplingRate, + monitorConfig.allowHapticsAndSystemSoundsDuringRecording + ) + : Platform.OS === "android" + ? SoundLevelModule.start( + monitorConfig.monitorInterval, + monitorConfig.samplingRate + ) + : SoundLevelModule.start(); }, stop: function () { if (this.frameSubscription) { - this.frameSubscription.remove() + this.frameSubscription.remove(); } if (this.timer) { - clearInterval(this.timer) + clearInterval(this.timer); } - return SoundLevelModule.stop() - } -} + return SoundLevelModule.stop(); + }, +}; -module.exports = SoundLevel +module.exports = SoundLevel; diff --git a/ios/RNSoundLevelModule.m b/ios/RNSoundLevelModule.m index c48631d..f881f88 100644 --- a/ios/RNSoundLevelModule.m +++ b/ios/RNSoundLevelModule.m @@ -62,7 +62,7 @@ - (void)startProgressTimer:(int)monitorInterval { [_progressUpdateTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; } -RCT_EXPORT_METHOD(start:(int)monitorInterval samplingRate:(float)sampleRate) +RCT_EXPORT_METHOD(start:(int)monitorInterval samplingRate:(float)sampleRate allowHapticsAndSystemSoundsDuringRecording:(BOOL)allow) { NSLog(@"Start Monitoring"); _prevProgressUpdateTime = nil; @@ -72,7 +72,7 @@ - (void)startProgressTimer:(int)monitorInterval { [NSNumber numberWithInt:AVAudioQualityLow], AVEncoderAudioQualityKey, [NSNumber numberWithInt:kAudioFormatMPEG4AAC], AVFormatIDKey, [NSNumber numberWithInt:1], AVNumberOfChannelsKey, - [NSNumber numberWithFloat:samplingRate], AVSampleRateKey, + [NSNumber numberWithFloat:sampleRate], AVSampleRateKey, nil]; NSError *error = nil; @@ -98,6 +98,11 @@ - (void)startProgressTimer:(int)monitorInterval { _audioRecorder.meteringEnabled = YES; [self startProgressTimer:monitorInterval]; + // Allow Haptic and System sound during recording + // https://developer.apple.com/documentation/avfaudio/avaudiosession/3240575-allowhapticsandsystemsoundsdurin?language=objc + if (@available(iOS 13.0, *)) { + [_recordSession setAllowHapticsAndSystemSoundsDuringRecording:allow error:nil]; + } [_recordSession setActive:YES error:nil]; [_audioRecorder record]; }