react-native-audio-concat 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/android/src/main/java/com/audioconcat/AudioConcatModule.kt +43 -0
- package/ios/AudioConcat.mm +60 -0
- package/lib/module/NativeAudioConcat.js.map +1 -1
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeAudioConcat.d.ts +1 -0
- package/lib/typescript/src/NativeAudioConcat.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeAudioConcat.ts +1 -0
- package/src/index.tsx +7 -0
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@ Concatenate audio files and silence periods into a single audio file for React N
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- ✅ Concat multiple audio files with silence periods
|
|
8
|
+
- ✅ Convert audio files to M4A format with AAC encoding
|
|
8
9
|
- ✅ Support for iOS and Android
|
|
9
10
|
- ✅ Output in M4A format
|
|
10
11
|
|
|
@@ -26,6 +27,8 @@ No additional steps required.
|
|
|
26
27
|
|
|
27
28
|
## Usage
|
|
28
29
|
|
|
30
|
+
### Concatenate Audio Files
|
|
31
|
+
|
|
29
32
|
```typescript
|
|
30
33
|
import { concatAudioFiles } from 'react-native-audio-concat';
|
|
31
34
|
|
|
@@ -48,6 +51,22 @@ try {
|
|
|
48
51
|
}
|
|
49
52
|
```
|
|
50
53
|
|
|
54
|
+
### Convert Audio to M4A
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { convertToM4a } from 'react-native-audio-concat';
|
|
58
|
+
|
|
59
|
+
const inputPath = '/path/to/audio.mp3';
|
|
60
|
+
const outputPath = '/path/to/output.m4a';
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const result = await convertToM4a(inputPath, outputPath);
|
|
64
|
+
console.log('Converted to M4A:', result);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('Conversion failed:', error);
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
51
70
|
## API
|
|
52
71
|
|
|
53
72
|
### `concatAudioFiles(data, outputPath)`
|
|
@@ -65,6 +84,24 @@ Concatenates audio files and silence periods into a single output file.
|
|
|
65
84
|
|
|
66
85
|
- `Promise<string>` - Resolves with the output file path
|
|
67
86
|
|
|
87
|
+
### `convertToM4a(inputPath, outputPath)`
|
|
88
|
+
|
|
89
|
+
Converts an audio file to M4A format with AAC encoding.
|
|
90
|
+
|
|
91
|
+
**Parameters:**
|
|
92
|
+
|
|
93
|
+
- `inputPath`: `string` - Absolute path to the input audio file (supports MP3, WAV, FLAC, OGG, M4A, and other common formats)
|
|
94
|
+
- `outputPath`: `string` - Absolute path where the M4A file will be saved
|
|
95
|
+
|
|
96
|
+
**Returns:**
|
|
97
|
+
|
|
98
|
+
- `Promise<string>` - Resolves with the output file path
|
|
99
|
+
|
|
100
|
+
**Notes:**
|
|
101
|
+
|
|
102
|
+
- On Android: Uses FFmpeg with AAC codec at 128kbps bitrate
|
|
103
|
+
- On iOS: Uses AVFoundation's native M4A export preset
|
|
104
|
+
|
|
68
105
|
## Example
|
|
69
106
|
|
|
70
107
|
Check out the [example app](example/) for a complete working example.
|
|
@@ -115,6 +115,49 @@ class AudioConcatModule(reactContext: ReactApplicationContext) :
|
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
override fun convertToM4a(inputPath: String, outputPath: String, promise: Promise) {
|
|
119
|
+
try {
|
|
120
|
+
// Check if input file exists
|
|
121
|
+
val inputFile = File(inputPath)
|
|
122
|
+
if (!inputFile.exists()) {
|
|
123
|
+
promise.reject("INPUT_NOT_FOUND", "Input file does not exist: $inputPath")
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
Log.d("AudioConcat", "Converting to M4A: $inputPath")
|
|
128
|
+
Log.d("AudioConcat", "Output: $outputPath")
|
|
129
|
+
|
|
130
|
+
// Delete existing output file
|
|
131
|
+
val outputFile = File(outputPath)
|
|
132
|
+
if (outputFile.exists()) {
|
|
133
|
+
outputFile.delete()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Build FFmpeg command for M4A conversion with AAC codec
|
|
137
|
+
val command = "-y -i \"$inputPath\" -c:a aac -b:a 128k -f mp4 \"$outputPath\" -loglevel level+error"
|
|
138
|
+
Log.d("AudioConcat", "FFmpeg command: $command")
|
|
139
|
+
|
|
140
|
+
// Execute FFmpeg command
|
|
141
|
+
FFmpegKit.executeAsync(command) { session ->
|
|
142
|
+
val returnCode = session.returnCode
|
|
143
|
+
if (ReturnCode.isSuccess(returnCode)) {
|
|
144
|
+
Log.d("AudioConcat", "Successfully converted to M4A: $outputPath")
|
|
145
|
+
promise.resolve(outputPath)
|
|
146
|
+
} else {
|
|
147
|
+
val output = session.output
|
|
148
|
+
val error = session.failStackTrace
|
|
149
|
+
Log.e("AudioConcat", "FFmpeg failed: $output")
|
|
150
|
+
Log.e("AudioConcat", "Error: $error")
|
|
151
|
+
promise.reject("FFMPEG_ERROR", "FFmpeg conversion failed: $output", Exception(error))
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
} catch (e: Exception) {
|
|
156
|
+
Log.e("AudioConcat", "Error converting to M4A: ${e.message}", e)
|
|
157
|
+
promise.reject("CONVERSION_ERROR", e.message, e)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
118
161
|
companion object {
|
|
119
162
|
const val NAME = "AudioConcat"
|
|
120
163
|
}
|
package/ios/AudioConcat.mm
CHANGED
|
@@ -90,6 +90,66 @@
|
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
- (void)convertToM4a:(NSString *)inputPath
|
|
94
|
+
outputPath:(NSString *)outputPath
|
|
95
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
96
|
+
reject:(RCTPromiseRejectBlock)reject
|
|
97
|
+
{
|
|
98
|
+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
99
|
+
@try {
|
|
100
|
+
NSURL *inputURL = [NSURL fileURLWithPath:inputPath];
|
|
101
|
+
|
|
102
|
+
// Check if input file exists
|
|
103
|
+
if (![[NSFileManager defaultManager] fileExistsAtPath:inputPath]) {
|
|
104
|
+
reject(@"ERR_INPUT_NOT_FOUND", [NSString stringWithFormat:@"Input file does not exist: %@", inputPath], nil);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Load the input audio file
|
|
109
|
+
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
|
|
110
|
+
NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeAudio];
|
|
111
|
+
|
|
112
|
+
if (tracks.count == 0) {
|
|
113
|
+
reject(@"ERR_NO_AUDIO_TRACK", [NSString stringWithFormat:@"No audio track found in file: %@", inputPath], nil);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Setup output URL
|
|
118
|
+
NSURL *outputURL = [NSURL fileURLWithPath:outputPath];
|
|
119
|
+
|
|
120
|
+
// Remove existing file if it exists
|
|
121
|
+
[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
|
|
122
|
+
|
|
123
|
+
// Create export session
|
|
124
|
+
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset
|
|
125
|
+
presetName:AVAssetExportPresetAppleM4A];
|
|
126
|
+
exportSession.outputURL = outputURL;
|
|
127
|
+
exportSession.outputFileType = AVFileTypeAppleM4A;
|
|
128
|
+
|
|
129
|
+
// Start export
|
|
130
|
+
[exportSession exportAsynchronouslyWithCompletionHandler:^{
|
|
131
|
+
switch (exportSession.status) {
|
|
132
|
+
case AVAssetExportSessionStatusCompleted:
|
|
133
|
+
resolve(outputPath);
|
|
134
|
+
break;
|
|
135
|
+
case AVAssetExportSessionStatusFailed:
|
|
136
|
+
reject(@"ERR_CONVERSION_FAILED", exportSession.error.localizedDescription, exportSession.error);
|
|
137
|
+
break;
|
|
138
|
+
case AVAssetExportSessionStatusCancelled:
|
|
139
|
+
reject(@"ERR_CONVERSION_CANCELLED", @"Conversion was cancelled", nil);
|
|
140
|
+
break;
|
|
141
|
+
default:
|
|
142
|
+
reject(@"ERR_CONVERSION_UNKNOWN", @"Unknown conversion error", nil);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}];
|
|
146
|
+
|
|
147
|
+
} @catch (NSException *exception) {
|
|
148
|
+
reject(@"ERR_EXCEPTION", exception.reason, nil);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
93
153
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
94
154
|
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
95
155
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeAudioConcat.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAA0B,cAAc;
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeAudioConcat.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAA0B,cAAc;AAYpE,eAAeA,mBAAmB,CAACC,YAAY,CAAO,aAAa,CAAC","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -4,4 +4,7 @@ import AudioConcat from "./NativeAudioConcat.js";
|
|
|
4
4
|
export function concatAudioFiles(data, outputPath) {
|
|
5
5
|
return AudioConcat.concatAudioFiles(data, outputPath);
|
|
6
6
|
}
|
|
7
|
+
export function convertToM4a(inputPath, outputPath) {
|
|
8
|
+
return AudioConcat.convertToM4a(inputPath, outputPath);
|
|
9
|
+
}
|
|
7
10
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["AudioConcat","concatAudioFiles","data","outputPath"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,WAAW,MAAM,wBAAqB;AAI7C,OAAO,SAASC,gBAAgBA,CAC9BC,IAA0D,EAC1DC,UAAkB,EACD;EACjB,OAAOH,WAAW,CAACC,gBAAgB,CAACC,IAAI,EAAEC,UAAU,CAAC;AACvD","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["AudioConcat","concatAudioFiles","data","outputPath","convertToM4a","inputPath"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,WAAW,MAAM,wBAAqB;AAI7C,OAAO,SAASC,gBAAgBA,CAC9BC,IAA0D,EAC1DC,UAAkB,EACD;EACjB,OAAOH,WAAW,CAACC,gBAAgB,CAACC,IAAI,EAAEC,UAAU,CAAC;AACvD;AAEA,OAAO,SAASC,YAAYA,CAC1BC,SAAiB,EACjBF,UAAkB,EACD;EACjB,OAAOH,WAAW,CAACI,YAAY,CAACC,SAAS,EAAEF,UAAU,CAAC;AACxD","ignoreList":[]}
|
|
@@ -6,6 +6,7 @@ export type AudioDataOrSilence = {
|
|
|
6
6
|
};
|
|
7
7
|
export interface Spec extends TurboModule {
|
|
8
8
|
concatAudioFiles(data: AudioDataOrSilence[], outputPath: string): Promise<string>;
|
|
9
|
+
convertToM4a(inputPath: string, outputPath: string): Promise<string>;
|
|
9
10
|
}
|
|
10
11
|
declare const _default: Spec;
|
|
11
12
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeAudioConcat.d.ts","sourceRoot":"","sources":["../../../src/NativeAudioConcat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,MAAM,kBAAkB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,gBAAgB,CACd,IAAI,EAAE,kBAAkB,EAAE,EAC1B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"NativeAudioConcat.d.ts","sourceRoot":"","sources":["../../../src/NativeAudioConcat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,MAAM,kBAAkB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,gBAAgB,CACd,IAAI,EAAE,kBAAkB,EAAE,EAC1B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACtE;;AAED,wBAAqE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1D,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAEjB"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1D,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAEjB"}
|
package/package.json
CHANGED
package/src/NativeAudioConcat.ts
CHANGED
|
@@ -7,6 +7,7 @@ export interface Spec extends TurboModule {
|
|
|
7
7
|
data: AudioDataOrSilence[],
|
|
8
8
|
outputPath: string
|
|
9
9
|
): Promise<string>;
|
|
10
|
+
convertToM4a(inputPath: string, outputPath: string): Promise<string>;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export default TurboModuleRegistry.getEnforcing<Spec>('AudioConcat');
|
package/src/index.tsx
CHANGED
|
@@ -8,3 +8,10 @@ export function concatAudioFiles(
|
|
|
8
8
|
): Promise<string> {
|
|
9
9
|
return AudioConcat.concatAudioFiles(data, outputPath);
|
|
10
10
|
}
|
|
11
|
+
|
|
12
|
+
export function convertToM4a(
|
|
13
|
+
inputPath: string,
|
|
14
|
+
outputPath: string
|
|
15
|
+
): Promise<string> {
|
|
16
|
+
return AudioConcat.convertToM4a(inputPath, outputPath);
|
|
17
|
+
}
|