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
55 changes: 50 additions & 5 deletions ios/AudioRecorder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ public class AudioRecorder: NSObject, AVAudioRecorderDelegate{
var audioUrl: URL?
var recordedDuration: CMTime = CMTime.zero
private var timer: Timer?
var updateFrequency = UpdateFrequency.medium
var updateFrequency = UpdateFrequency.medium
private var isRecordingActive = false

private func createAudioRecordPath(fileNameFormat: String?) -> URL? {
let format = DateFormatter()
Expand Down Expand Up @@ -65,11 +66,20 @@ public class AudioRecorder: NSObject, AVAudioRecorderDelegate{
reject(Constants.audioWaveforms, "Failed to initialise file URL", nil)
return
}

NotificationCenter.default.addObserver(
self,
selector: #selector(handleInterruption),
name: AVAudioSession.interruptionNotification,
object: AVAudioSession.sharedInstance()
)

audioRecorder = try AVAudioRecorder(url: newPath, settings: settings as [String : Any])
audioRecorder?.delegate = self
audioRecorder?.isMeteringEnabled = true
audioRecorder?.record()
startListening()
isRecordingActive = true
startListening()
resolve(true)
} catch let error as NSError {
print(error.localizedDescription)
Expand Down Expand Up @@ -97,7 +107,9 @@ public class AudioRecorder: NSObject, AVAudioRecorderDelegate{
}

public func stopRecording(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) -> Void {
stopListening()
stopListening()
isRecordingActive = false
NotificationCenter.default.removeObserver(self, name: AVAudioSession.interruptionNotification, object: nil)
audioRecorder?.stop()
if(audioUrl != nil) {
let asset = AVURLAsset(url: audioUrl!)
Expand All @@ -122,14 +134,26 @@ public class AudioRecorder: NSObject, AVAudioRecorderDelegate{
}

public func pauseRecording(_ resolve: RCTPromiseResolveBlock) -> Void {
audioRecorder?.pause()
pauseActiveRecording()
resolve(true)
}

public func resumeRecording(_ resolve: RCTPromiseResolveBlock) -> Void {
audioRecorder?.record()
resumeActiveRecording()
resolve(true)
}

private func pauseActiveRecording() {
audioRecorder?.pause()
isRecordingActive = false
stopListening()
}

private func resumeActiveRecording() {
audioRecorder?.record()
isRecordingActive = true
startListening()
}

func getDecibelLevel() -> Float {
audioRecorder?.updateMeters()
Expand Down Expand Up @@ -203,5 +227,26 @@ public class AudioRecorder: NSObject, AVAudioRecorderDelegate{
return Int(kAudioFormatMPEG4AAC)
}
}

@objc private func handleInterruption(notification: Notification) {
guard let userInfo = notification.userInfo,
let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
return
}

switch type {
case .began:
if isRecordingActive {
pauseActiveRecording()
EventEmitter.sharedInstance.dispatch(
name: Constants.onDidFinishRecordingAudio,
body: ["finishType": RecorderFinishType.pause.rawValue]
)
}
@unknown default:
break
}
}
}

2 changes: 1 addition & 1 deletion ios/EventEmitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class EventEmitter {

/// All Events which must be support by React Native.
lazy var allEvents: [String] = {
var allEventNames: [String] = ["onDidFinishPlayingAudio", "onCurrentDuration", "onCurrentExtractedWaveformData", "onCurrentRecordingWaveformData"]
var allEventNames: [String] = ["onDidFinishPlayingAudio", "onCurrentDuration", "onCurrentExtractedWaveformData", "onCurrentRecordingWaveformData", "onDidFinishRecordingAudio"]

// Append all events here

Expand Down
10 changes: 8 additions & 2 deletions ios/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ struct Constants {
static let preparePlayer = "preparePlayer"
static let onCurrentDuration = "onCurrentDuration"
static let currentDuration = "currentDuration"
static let currentDecibel = "currentDecibel"
static let currentDecibel = "currentDecibel"
static let playerKey = "playerKey"
static let stopAllPlayers = "stopAllPlayers"
static let stopAllWaveFormExtractors = "stopAllWaveFormExtractors"
Expand All @@ -66,7 +66,8 @@ struct Constants {
static let extractWaveformData = "extractWaveformData"
static let noOfSamples = "noOfSamples"
static let onCurrentExtractedWaveformData = "onCurrentExtractedWaveformData"
static let onCurrentRecordingWaveformData = "onCurrentRecordingWaveformData"
static let onCurrentRecordingWaveformData = "onCurrentRecordingWaveformData"
static let onDidFinishRecordingAudio = "onDidFinishRecordingAudio"
static let waveformData = "waveformData"
static let onExtractionProgressUpdate = "onExtractionProgressUpdate"
static let useLegacyNormalization = "useLegacyNormalization"
Expand All @@ -80,6 +81,11 @@ enum FinishMode : Int{
case stop = 2
}

enum RecorderFinishType : Int{
case pause = 0
case resume = 1
}

//Note: If you are making change here, please make sure to make change in Android and React Native side as well other wise there will be mismatch in value
//Use same values in Android and React native side as well
enum UpdateFrequency : Double {
Expand Down
12 changes: 12 additions & 0 deletions src/components/Waveform/Waveform.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
playbackSpeedThreshold,
PlayerState,
RecorderState,
RecorderFinishType,
UpdateFrequency,
} from '../../constants';
import {
Expand Down Expand Up @@ -96,6 +97,7 @@ export const Waveform = forwardRef<IWaveformRef, IWaveform>((props, ref) => {
onCurrentDuration,
onDidFinishPlayingAudio,
onCurrentRecordingWaveformData,
onDidFinishRecordingAudio,
setPlaybackSpeed,
markPlayerAsUnmounted,
} = useAudioPlayer();
Expand Down Expand Up @@ -524,10 +526,20 @@ export const Waveform = forwardRef<IWaveformRef, IWaveform>((props, ref) => {
}
}
);

const traceRecordingFinish = onDidFinishRecordingAudio(data => {
if (data.finishType === RecorderFinishType.pause) {
setRecorderState(RecorderState.paused);
} else if (data.finishType === RecorderFinishType.resume) {
setRecorderState(RecorderState.recording);
}
});

return () => {
tracePlayerState.remove();
tracePlaybackValue.remove();
traceRecorderWaveformValue.remove();
traceRecordingFinish.remove();
markPlayerAsUnmounted();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down
6 changes: 6 additions & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export enum NativeEvents {
onCurrentDuration = 'onCurrentDuration',
onCurrentExtractedWaveformData = 'onCurrentExtractedWaveformData',
onCurrentRecordingWaveformData = 'onCurrentRecordingWaveformData',
onDidFinishRecordingAudio = 'onDidFinishRecordingAudio',
}

export enum PermissionStatus {
Expand All @@ -34,6 +35,11 @@ export enum RecorderState {
stopped = 'stopped',
}

export enum RecorderFinishType {
pause = 0,
resume = 1,
}

//Note: If you are making change here, please make sure to make change in iOS and Android side as well other wise there will be mismatch in value
//Use same values in iOS and Android side as well
export enum UpdateFrequency {
Expand Down
9 changes: 9 additions & 0 deletions src/hooks/useAudioPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ export const useAudioPlayer = () => {
result => callback(result)
);

const onDidFinishRecordingAudio = (
callback: (result: { finishType: number }) => void
) =>
audioPlayerEmitter.addListener(
NativeEvents.onDidFinishRecordingAudio,
result => callback(result)
);

const setPlaybackSpeed = (args: ISetPlaybackSpeed) =>
AudioWaveform.setPlaybackSpeed(args);

Expand All @@ -100,6 +108,7 @@ export const useAudioPlayer = () => {
onCurrentExtractedWaveformData,
getDuration,
onCurrentRecordingWaveformData,
onDidFinishRecordingAudio,
setPlaybackSpeed,
markPlayerAsUnmounted,
stopAllWaveFormExtractors,
Expand Down