Skip to content
Open
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
47 changes: 25 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`:

```
<key>NSMicrophoneUsageDescription</key>
<string>This sample uses the microphone to analyze sound level.</string>
```

On *Android* you need to add a permission to `AndroidManifest.xml`:
On _Android_ you need to add a permission to `AndroidManifest.xml`:

```
<uses-permission android:name="android.permission.RECORD_AUDIO" />
```

### Manual installation on iOS

```
In XCode, in the project navigator:

Expand All @@ -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
Expand Down
18 changes: 12 additions & 6 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
64 changes: 38 additions & 26 deletions index.js
Original file line number Diff line number Diff line change
@@ -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;
9 changes: 7 additions & 2 deletions ios/RNSoundLevelModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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];
}
Expand Down