Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assign default file extension based on audio format #615

Merged
merged 2 commits into from
Jun 17, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,13 @@ class RNAudioRecorderPlayerModule(private val reactContext: ReactApplicationCont
promise.reject("No permission granted.", "Try again after adding permission.")
return
}
audioFileURL = if (((path == "DEFAULT"))) "${reactContext.cacheDir}/$defaultFileName" else path

var outputFormat = if (audioSet != null && audioSet.hasKey("OutputFormatAndroid"))
audioSet.getInt("OutputFormatAndroid")
else
MediaRecorder.OutputFormat.MPEG_4

audioFileURL = if (((path == "DEFAULT"))) "${reactContext.cacheDir}/sound.${defaultFileExtensions.get(outputFormat)}" else path
_meteringEnabled = meteringEnabled

if (mediaRecorder == null) {
Expand All @@ -69,14 +75,14 @@ class RNAudioRecorderPlayerModule(private val reactContext: ReactApplicationCont

if (audioSet != null) {
mediaRecorder!!.setAudioSource(if (audioSet.hasKey("AudioSourceAndroid")) audioSet.getInt("AudioSourceAndroid") else MediaRecorder.AudioSource.MIC)
mediaRecorder!!.setOutputFormat(if (audioSet.hasKey("OutputFormatAndroid")) audioSet.getInt("OutputFormatAndroid") else MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder!!.setOutputFormat(outputFormat)
mediaRecorder!!.setAudioEncoder(if (audioSet.hasKey("AudioEncoderAndroid")) audioSet.getInt("AudioEncoderAndroid") else MediaRecorder.AudioEncoder.AAC)
mediaRecorder!!.setAudioSamplingRate(if (audioSet.hasKey("AudioSamplingRateAndroid")) audioSet.getInt("AudioSamplingRateAndroid") else 48000)
mediaRecorder!!.setAudioEncodingBitRate(if (audioSet.hasKey("AudioEncodingBitRateAndroid")) audioSet.getInt("AudioEncodingBitRateAndroid") else 128000)
mediaRecorder!!.setAudioChannels(if (audioSet.hasKey("AudioChannelsAndroid")) audioSet.getInt("AudioChannelsAndroid") else 2)
} else {
mediaRecorder!!.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder!!.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder!!.setOutputFormat(outputFormat)
mediaRecorder!!.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mediaRecorder!!.setAudioEncodingBitRate(128000)
mediaRecorder!!.setAudioSamplingRate(48000)
Expand Down Expand Up @@ -381,5 +387,19 @@ class RNAudioRecorderPlayerModule(private val reactContext: ReactApplicationCont
companion object {
private var tag = "RNAudioRecorderPlayer"
private var defaultFileName = "sound.mp4"
private var defaultFileExtensions = listOf(
"mp4", // DEFAULT = 0
"3gp", // THREE_GPP
"mp4", // MPEG_4
"amr", // AMR_NB
"amr", // AMR_WB
"aac", // AAC_ADIF
"aac", // AAC_ADTS
"rtp", // OUTPUT_FORMAT_RTP_AVP
"ts", // MPEG_2_TSMPEG_2_TS
"webm",// WEBM
"xxx", // UNUSED
"ogg", // OGG
)
}
}
3 changes: 3 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export enum OutputFormatAndroidType {
OUTPUT_FORMAT_RTP_AVP,
MPEG_2_TS,
WEBM,
UNUSED,
OGG,
}

export enum AudioEncoderAndroidType {
Expand All @@ -44,6 +46,7 @@ export enum AudioEncoderAndroidType {
HE_AAC,
AAC_ELD,
VORBIS,
OPUS,
}

export enum AVEncodingOption {
Expand Down
138 changes: 98 additions & 40 deletions ios/RNAudioRecorderPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -184,55 +184,26 @@ class RNAudioRecorderPlayer: RCTEventEmitter, AVAudioRecorderDelegate {
let avLPCMIsFloatKey = audioSets["AVLinearPCMIsFloatKeyIOS"] as? Bool
let avLPCMIsNonInterleaved = audioSets["AVLinearPCMIsNonInterleavedIOS"] as? Bool

var avFormat: Int? = nil
var avMode: AVAudioSession.Mode = AVAudioSession.Mode.default
var sampleRate = audioSets["AVSampleRateKeyIOS"] as? Int
var numberOfChannel = audioSets["AVNumberOfChannelsKeyIOS"] as? Int
var audioQuality = audioSets["AVEncoderAudioQualityKeyIOS"] as? Int
var bitRate = audioSets["AVEncoderBitRateKeyIOS"] as? Int

setAudioFileURL(path: path)

if (sampleRate == nil) {
sampleRate = 44100;
}

if (encoding == nil) {
avFormat = Int(kAudioFormatAppleLossless)
guard let avFormat: AudioFormatID = avFormat(fromString: encoding) else {
return reject("RNAudioPlayerRecorder", "Audio format not available", nil)
}

if (path == "DEFAULT") {
let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
let fileExt = fileExtension(forAudioFormat: avFormat)
audioFileURL = cachesDirectory.appendingPathComponent("sound." + fileExt)
} else {
if (encoding == "lpcm") {
avFormat = Int(kAudioFormatAppleIMA4)
} else if (encoding == "ima4") {
avFormat = Int(kAudioFormatAppleIMA4)
} else if (encoding == "aac") {
avFormat = Int(kAudioFormatMPEG4AAC)
} else if (encoding == "MAC3") {
avFormat = Int(kAudioFormatMACE3)
} else if (encoding == "MAC6") {
avFormat = Int(kAudioFormatMACE6)
} else if (encoding == "ulaw") {
avFormat = Int(kAudioFormatULaw)
} else if (encoding == "alaw") {
avFormat = Int(kAudioFormatALaw)
} else if (encoding == "mp1") {
avFormat = Int(kAudioFormatMPEGLayer1)
} else if (encoding == "mp2") {
avFormat = Int(kAudioFormatMPEGLayer2)
} else if (encoding == "mp4") {
avFormat = Int(kAudioFormatMPEG4AAC)
} else if (encoding == "alac") {
avFormat = Int(kAudioFormatAppleLossless)
} else if (encoding == "amr") {
avFormat = Int(kAudioFormatAMR)
} else if (encoding == "flac") {
if #available(iOS 11.0, *) {
avFormat = Int(kAudioFormatFLAC)
}
} else if (encoding == "opus") {
avFormat = Int(kAudioFormatOpus)
} else if (encoding == "wav") {
avFormat = Int(kAudioFormatLinearPCM)
}
setAudioFileURL(path: path)
}

if (mode == "measurement") {
Expand Down Expand Up @@ -273,14 +244,14 @@ class RNAudioRecorderPlayer: RCTEventEmitter, AVAudioRecorderDelegate {
func startRecording() {
let settings = [
AVSampleRateKey: sampleRate!,
AVFormatIDKey: avFormat!,
AVFormatIDKey: avFormat,
AVNumberOfChannelsKey: numberOfChannel!,
AVEncoderAudioQualityKey: audioQuality!,
AVLinearPCMBitDepthKey: avLPCMBitDepth ?? AVLinearPCMBitDepthKey.count,
AVLinearPCMIsBigEndianKey: avLPCMIsBigEndian ?? true,
AVLinearPCMIsFloatKey: avLPCMIsFloatKey ?? false,
AVLinearPCMIsNonInterleaved: avLPCMIsNonInterleaved ?? false,
AVEncoderBitRateKey: bitRate!
AVEncoderBitRateKey: bitRate!
] as [String : Any]

do {
Expand Down Expand Up @@ -493,4 +464,91 @@ class RNAudioRecorderPlayer: RCTEventEmitter, AVAudioRecorderDelegate {
audioPlayer.volume = volume
resolve(volume)
}
private func avFormat(fromString encoding: String?) -> AudioFormatID? {
if (encoding == nil) {
return kAudioFormatAppleLossless
} else {
if (encoding == "lpcm") {
return kAudioFormatAppleIMA4
} else if (encoding == "ima4") {
return kAudioFormatAppleIMA4
} else if (encoding == "aac") {
return kAudioFormatMPEG4AAC
} else if (encoding == "MAC3") {
return kAudioFormatMACE3
} else if (encoding == "MAC6") {
return kAudioFormatMACE6
} else if (encoding == "ulaw") {
return kAudioFormatULaw
} else if (encoding == "alaw") {
return kAudioFormatALaw
} else if (encoding == "mp1") {
return kAudioFormatMPEGLayer1
} else if (encoding == "mp2") {
return kAudioFormatMPEGLayer2
} else if (encoding == "mp4") {
return kAudioFormatMPEG4AAC
} else if (encoding == "alac") {
return kAudioFormatAppleLossless
} else if (encoding == "amr") {
return kAudioFormatAMR
} else if (encoding == "flac") {
if #available(iOS 11.0, *) {
return kAudioFormatFLAC
}
} else if (encoding == "opus") {
return kAudioFormatOpus
} else if (encoding == "wav") {
return kAudioFormatLinearPCM
}
}
return nil;
}

private func fileExtension(forAudioFormat format: AudioFormatID) -> String {
switch format {
case kAudioFormatOpus:
return "ogg"
case kAudioFormatLinearPCM:
return "wav"
case kAudioFormatAC3, kAudioFormat60958AC3:
return "ac3"
case kAudioFormatAppleIMA4:
return "caf"
case kAudioFormatMPEG4AAC, kAudioFormatMPEG4CELP, kAudioFormatMPEG4HVXC, kAudioFormatMPEG4TwinVQ, kAudioFormatMPEG4AAC_HE, kAudioFormatMPEG4AAC_LD, kAudioFormatMPEG4AAC_ELD, kAudioFormatMPEG4AAC_ELD_SBR, kAudioFormatMPEG4AAC_ELD_V2, kAudioFormatMPEG4AAC_HE_V2, kAudioFormatMPEG4AAC_Spatial:
return "m4a"
case kAudioFormatMACE3, kAudioFormatMACE6:
return "caf"
case kAudioFormatULaw, kAudioFormatALaw:
return "wav"
case kAudioFormatQDesign, kAudioFormatQDesign2:
return "mov"
case kAudioFormatQUALCOMM:
return "qcp"
case kAudioFormatMPEGLayer1:
return "mp1"
case kAudioFormatMPEGLayer2:
return "mp2"
case kAudioFormatMPEGLayer3:
return "mp3"
case kAudioFormatMIDIStream:
return "mid"
case kAudioFormatAppleLossless:
return "m4a"
case kAudioFormatAMR:
return "amr"
case kAudioFormatAMR_WB:
return "awb"
case kAudioFormatAudible:
return "aa"
case kAudioFormatiLBC:
return "ilbc"
case kAudioFormatDVIIntelIMA, kAudioFormatMicrosoftGSM:
return "wav"
default:
// Generic file extension for types that don't have a natural
// file extension
return "audio"
}
}
}
Loading