react-native-audio-concat 0.2.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/AudioConcat.podspec +30 -0
- package/LICENSE +20 -0
- package/README.md +39 -0
- package/android/CMakeLists.txt +24 -0
- package/android/build.gradle +128 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/cpp-adapter.cpp +6 -0
- package/android/src/main/java/com/margelo/nitro/audioconcat/AudioConcat.kt +349 -0
- package/android/src/main/java/com/margelo/nitro/audioconcat/AudioConcatPackage.kt +22 -0
- package/ios/AudioConcat.swift +75 -0
- package/lib/module/AudioConcat.nitro.js +4 -0
- package/lib/module/AudioConcat.nitro.js.map +1 -0
- package/lib/module/index.js +33 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/AudioConcat.nitro.d.ts +16 -0
- package/lib/typescript/src/AudioConcat.nitro.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +28 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/nitro.json +17 -0
- package/nitrogen/generated/android/audioconcat+autolinking.cmake +82 -0
- package/nitrogen/generated/android/audioconcat+autolinking.gradle +27 -0
- package/nitrogen/generated/android/audioconcatOnLoad.cpp +44 -0
- package/nitrogen/generated/android/audioconcatOnLoad.hpp +25 -0
- package/nitrogen/generated/android/c++/JAudioData.hpp +53 -0
- package/nitrogen/generated/android/c++/JAudioDataOrSilence.cpp +26 -0
- package/nitrogen/generated/android/c++/JAudioDataOrSilence.hpp +72 -0
- package/nitrogen/generated/android/c++/JHybridAudioConcatSpec.cpp +77 -0
- package/nitrogen/generated/android/c++/JHybridAudioConcatSpec.hpp +64 -0
- package/nitrogen/generated/android/c++/JSilentData.hpp +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audioconcat/AudioData.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audioconcat/AudioDataOrSilence.kt +42 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audioconcat/HybridAudioConcatSpec.kt +52 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audioconcat/SilentData.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audioconcat/audioconcatOnLoad.kt +35 -0
- package/nitrogen/generated/ios/AudioConcat+autolinking.rb +60 -0
- package/nitrogen/generated/ios/AudioConcat-Swift-Cxx-Bridge.cpp +48 -0
- package/nitrogen/generated/ios/AudioConcat-Swift-Cxx-Bridge.hpp +160 -0
- package/nitrogen/generated/ios/AudioConcat-Swift-Cxx-Umbrella.hpp +53 -0
- package/nitrogen/generated/ios/AudioConcatAutolinking.mm +33 -0
- package/nitrogen/generated/ios/AudioConcatAutolinking.swift +25 -0
- package/nitrogen/generated/ios/c++/HybridAudioConcatSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridAudioConcatSpecSwift.hpp +81 -0
- package/nitrogen/generated/ios/swift/AudioData.swift +35 -0
- package/nitrogen/generated/ios/swift/AudioDataOrSilence.swift +18 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__string.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridAudioConcatSpec.swift +49 -0
- package/nitrogen/generated/ios/swift/HybridAudioConcatSpec_cxx.swift +142 -0
- package/nitrogen/generated/ios/swift/SilentData.swift +35 -0
- package/nitrogen/generated/shared/c++/AudioData.hpp +67 -0
- package/nitrogen/generated/shared/c++/HybridAudioConcatSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridAudioConcatSpec.hpp +70 -0
- package/nitrogen/generated/shared/c++/SilentData.hpp +67 -0
- package/package.json +168 -0
- package/src/AudioConcat.nitro.ts +19 -0
- package/src/index.tsx +38 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import AVFoundation
|
|
2
|
+
import NitroModules
|
|
3
|
+
|
|
4
|
+
class AudioConcat: HybridAudioConcatSpec {
|
|
5
|
+
public func concatAudioFiles(data: [AudioDataOrSilence], outputPath: String) throws -> Promise<String> {
|
|
6
|
+
return Promise.async { [weak self] in
|
|
7
|
+
guard !data.isEmpty else {
|
|
8
|
+
throw NSError(domain: "AwesomeLibrary", code: 1, userInfo: [NSLocalizedDescriptionKey: "Data array is empty"])
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let composition = AVMutableComposition()
|
|
12
|
+
guard let audioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) else {
|
|
13
|
+
throw NSError(domain: "AwesomeLibrary", code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to create audio track"])
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
var currentTime = CMTime.zero
|
|
17
|
+
|
|
18
|
+
for (index, item) in data.enumerated() {
|
|
19
|
+
switch item {
|
|
20
|
+
case .first(let audioData):
|
|
21
|
+
// Audio file
|
|
22
|
+
let filePath = audioData.filePath
|
|
23
|
+
let fileURL = URL(fileURLWithPath: filePath)
|
|
24
|
+
let asset = AVAsset(url: fileURL)
|
|
25
|
+
|
|
26
|
+
guard let sourceTrack = asset.tracks(withMediaType: .audio).first else {
|
|
27
|
+
throw NSError(domain: "AwesomeLibrary", code: 3, userInfo: [NSLocalizedDescriptionKey: "No audio track found in \(filePath)"])
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let duration = asset.duration
|
|
31
|
+
let timeRange = CMTimeRange(start: .zero, duration: duration)
|
|
32
|
+
|
|
33
|
+
try audioTrack.insertTimeRange(timeRange, of: sourceTrack, at: currentTime)
|
|
34
|
+
currentTime = CMTimeAdd(currentTime, duration)
|
|
35
|
+
|
|
36
|
+
case .second(let silentData):
|
|
37
|
+
// Silence
|
|
38
|
+
let durationMs = silentData.durationMs
|
|
39
|
+
let silenceDuration = CMTime(seconds: durationMs / 1000.0, preferredTimescale: 600)
|
|
40
|
+
|
|
41
|
+
// In AVMutableComposition, leaving a gap (not inserting anything)
|
|
42
|
+
// automatically creates silence
|
|
43
|
+
currentTime = CMTimeAdd(currentTime, silenceDuration)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let outputURL = URL(fileURLWithPath: outputPath)
|
|
48
|
+
|
|
49
|
+
// Remove existing file if present
|
|
50
|
+
try? FileManager.default.removeItem(at: outputURL)
|
|
51
|
+
|
|
52
|
+
guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) else {
|
|
53
|
+
throw NSError(domain: "AwesomeLibrary", code: 4, userInfo: [NSLocalizedDescriptionKey: "Failed to create export session"])
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
exportSession.outputURL = outputURL
|
|
57
|
+
exportSession.outputFileType = .m4a
|
|
58
|
+
|
|
59
|
+
return try await withCheckedThrowingContinuation { continuation in
|
|
60
|
+
exportSession.exportAsynchronously {
|
|
61
|
+
switch exportSession.status {
|
|
62
|
+
case .completed:
|
|
63
|
+
continuation.resume(returning: outputPath)
|
|
64
|
+
case .failed:
|
|
65
|
+
continuation.resume(throwing: exportSession.error ?? NSError(domain: "AwesomeLibrary", code: 5, userInfo: [NSLocalizedDescriptionKey: "Export failed"]))
|
|
66
|
+
case .cancelled:
|
|
67
|
+
continuation.resume(throwing: NSError(domain: "AwesomeLibrary", code: 6, userInfo: [NSLocalizedDescriptionKey: "Export cancelled"]))
|
|
68
|
+
default:
|
|
69
|
+
continuation.resume(throwing: NSError(domain: "AwesomeLibrary", code: 7, userInfo: [NSLocalizedDescriptionKey: "Unknown export status"]))
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["AudioConcat.nitro.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { NitroModules } from 'react-native-nitro-modules';
|
|
4
|
+
const AudioConcatHybridObject = NitroModules.createHybridObject('AudioConcat');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Concat audio files and silence periods into a single output file.
|
|
8
|
+
*
|
|
9
|
+
* @param data - Array of audio files and silence periods to merge.
|
|
10
|
+
* Each item can be either:
|
|
11
|
+
* - `{ filePath: string }` for an audio file
|
|
12
|
+
* - `{ durationMs: number }` for a silence period
|
|
13
|
+
* @param outputPath - Absolute path where the merged audio file will be saved (M4A format)
|
|
14
|
+
* @returns Promise that resolves with the output file path
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const data = [
|
|
19
|
+
* { filePath: '/path/to/audio1.m4a' },
|
|
20
|
+
* { durationMs: 500 }, // 500ms silence
|
|
21
|
+
* { filePath: '/path/to/audio2.m4a' },
|
|
22
|
+
* { durationMs: 1000 }, // 1 second silence
|
|
23
|
+
* { filePath: '/path/to/audio3.m4a' }
|
|
24
|
+
* ];
|
|
25
|
+
* const output = '/path/to/merged.m4a';
|
|
26
|
+
* const result = await concatAudioFiles(data, output);
|
|
27
|
+
* console.log('concat file:', result);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function concatAudioFiles(data, outputPath) {
|
|
31
|
+
return AudioConcatHybridObject.concatAudioFiles(data, outputPath);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NitroModules","AudioConcatHybridObject","createHybridObject","concatAudioFiles","data","outputPath"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,4BAA4B;AAGzD,MAAMC,uBAAuB,GAC3BD,YAAY,CAACE,kBAAkB,CAAc,aAAa,CAAC;;AAE7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,gBAAgBA,CAC9BC,IAA0B,EAC1BC,UAAkB,EACD;EACjB,OAAOJ,uBAAuB,CAACE,gBAAgB,CAACC,IAAI,EAAEC,UAAU,CAAC;AACnE","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HybridObject } from 'react-native-nitro-modules';
|
|
2
|
+
type SilentData = {
|
|
3
|
+
durationMs: number;
|
|
4
|
+
};
|
|
5
|
+
type AudioData = {
|
|
6
|
+
filePath: string;
|
|
7
|
+
};
|
|
8
|
+
export type AudioDataOrSilence = AudioData | SilentData;
|
|
9
|
+
export interface AudioConcat extends HybridObject<{
|
|
10
|
+
ios: 'swift';
|
|
11
|
+
android: 'kotlin';
|
|
12
|
+
}> {
|
|
13
|
+
concatAudioFiles(data: AudioDataOrSilence[], outputPath: string): Promise<string>;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=AudioConcat.nitro.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AudioConcat.nitro.d.ts","sourceRoot":"","sources":["../../../src/AudioConcat.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,KAAK,UAAU,GAAG;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,UAAU,CAAC;AAExD,MAAM,WAAW,WACf,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IACzD,gBAAgB,CACd,IAAI,EAAE,kBAAkB,EAAE,EAC1B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAAC;CACpB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AudioDataOrSilence } from './AudioConcat.nitro';
|
|
2
|
+
/**
|
|
3
|
+
* Concat audio files and silence periods into a single output file.
|
|
4
|
+
*
|
|
5
|
+
* @param data - Array of audio files and silence periods to merge.
|
|
6
|
+
* Each item can be either:
|
|
7
|
+
* - `{ filePath: string }` for an audio file
|
|
8
|
+
* - `{ durationMs: number }` for a silence period
|
|
9
|
+
* @param outputPath - Absolute path where the merged audio file will be saved (M4A format)
|
|
10
|
+
* @returns Promise that resolves with the output file path
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const data = [
|
|
15
|
+
* { filePath: '/path/to/audio1.m4a' },
|
|
16
|
+
* { durationMs: 500 }, // 500ms silence
|
|
17
|
+
* { filePath: '/path/to/audio2.m4a' },
|
|
18
|
+
* { durationMs: 1000 }, // 1 second silence
|
|
19
|
+
* { filePath: '/path/to/audio3.m4a' }
|
|
20
|
+
* ];
|
|
21
|
+
* const output = '/path/to/merged.m4a';
|
|
22
|
+
* const result = await concatAudioFiles(data, output);
|
|
23
|
+
* console.log('concat file:', result);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function concatAudioFiles(data: AudioDataOrSilence[], outputPath: string): Promise<string>;
|
|
27
|
+
export type { AudioDataOrSilence } from './AudioConcat.nitro';
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAK3E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,kBAAkB,EAAE,EAC1B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/nitro.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cxxNamespace": ["audioconcat"],
|
|
3
|
+
"ios": {
|
|
4
|
+
"iosModuleName": "AudioConcat"
|
|
5
|
+
},
|
|
6
|
+
"android": {
|
|
7
|
+
"androidNamespace": ["audioconcat"],
|
|
8
|
+
"androidCxxLibName": "audioconcat"
|
|
9
|
+
},
|
|
10
|
+
"autolinking": {
|
|
11
|
+
"AudioConcat": {
|
|
12
|
+
"swift": "AudioConcat",
|
|
13
|
+
"kotlin": "AudioConcat"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"ignorePaths": ["node_modules"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#
|
|
2
|
+
# audioconcat+autolinking.cmake
|
|
3
|
+
# This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
# https://github.com/mrousavy/nitro
|
|
5
|
+
# Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
# This is a CMake file that adds all files generated by Nitrogen
|
|
9
|
+
# to the current CMake project.
|
|
10
|
+
#
|
|
11
|
+
# To use it, add this to your CMakeLists.txt:
|
|
12
|
+
# ```cmake
|
|
13
|
+
# include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/audioconcat+autolinking.cmake)
|
|
14
|
+
# ```
|
|
15
|
+
|
|
16
|
+
# Define a flag to check if we are building properly
|
|
17
|
+
add_definitions(-DBUILDING_AUDIOCONCAT_WITH_GENERATED_CMAKE_PROJECT)
|
|
18
|
+
|
|
19
|
+
# Enable Raw Props parsing in react-native (for Nitro Views)
|
|
20
|
+
add_definitions(-DRN_SERIALIZABLE_STATE)
|
|
21
|
+
|
|
22
|
+
# Add all headers that were generated by Nitrogen
|
|
23
|
+
include_directories(
|
|
24
|
+
"../nitrogen/generated/shared/c++"
|
|
25
|
+
"../nitrogen/generated/android/c++"
|
|
26
|
+
"../nitrogen/generated/android/"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Add all .cpp sources that were generated by Nitrogen
|
|
30
|
+
target_sources(
|
|
31
|
+
# CMake project name (Android C++ library name)
|
|
32
|
+
audioconcat PRIVATE
|
|
33
|
+
# Autolinking Setup
|
|
34
|
+
../nitrogen/generated/android/audioconcatOnLoad.cpp
|
|
35
|
+
# Shared Nitrogen C++ sources
|
|
36
|
+
../nitrogen/generated/shared/c++/HybridAudioConcatSpec.cpp
|
|
37
|
+
# Android-specific Nitrogen C++ sources
|
|
38
|
+
../nitrogen/generated/android/c++/JHybridAudioConcatSpec.cpp
|
|
39
|
+
../nitrogen/generated/android/c++/JAudioDataOrSilence.cpp
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# From node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake
|
|
43
|
+
# Used in node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake
|
|
44
|
+
target_compile_definitions(
|
|
45
|
+
audioconcat PRIVATE
|
|
46
|
+
-DFOLLY_NO_CONFIG=1
|
|
47
|
+
-DFOLLY_HAVE_CLOCK_GETTIME=1
|
|
48
|
+
-DFOLLY_USE_LIBCPP=1
|
|
49
|
+
-DFOLLY_CFG_NO_COROUTINES=1
|
|
50
|
+
-DFOLLY_MOBILE=1
|
|
51
|
+
-DFOLLY_HAVE_RECVMMSG=1
|
|
52
|
+
-DFOLLY_HAVE_PTHREAD=1
|
|
53
|
+
# Once we target android-23 above, we can comment
|
|
54
|
+
# the following line. NDK uses GNU style stderror_r() after API 23.
|
|
55
|
+
-DFOLLY_HAVE_XSI_STRERROR_R=1
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Add all libraries required by the generated specs
|
|
59
|
+
find_package(fbjni REQUIRED) # <-- Used for communication between Java <-> C++
|
|
60
|
+
find_package(ReactAndroid REQUIRED) # <-- Used to set up React Native bindings (e.g. CallInvoker/TurboModule)
|
|
61
|
+
find_package(react-native-nitro-modules REQUIRED) # <-- Used to create all HybridObjects and use the Nitro core library
|
|
62
|
+
|
|
63
|
+
# Link all libraries together
|
|
64
|
+
target_link_libraries(
|
|
65
|
+
audioconcat
|
|
66
|
+
fbjni::fbjni # <-- Facebook C++ JNI helpers
|
|
67
|
+
ReactAndroid::jsi # <-- RN: JSI
|
|
68
|
+
react-native-nitro-modules::NitroModules # <-- NitroModules Core :)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Link react-native (different prefab between RN 0.75 and RN 0.76)
|
|
72
|
+
if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 76)
|
|
73
|
+
target_link_libraries(
|
|
74
|
+
audioconcat
|
|
75
|
+
ReactAndroid::reactnative # <-- RN: Native Modules umbrella prefab
|
|
76
|
+
)
|
|
77
|
+
else()
|
|
78
|
+
target_link_libraries(
|
|
79
|
+
audioconcat
|
|
80
|
+
ReactAndroid::react_nativemodule_core # <-- RN: TurboModules Core
|
|
81
|
+
)
|
|
82
|
+
endif()
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// audioconcat+autolinking.gradle
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
/// This is a Gradle file that adds all files generated by Nitrogen
|
|
9
|
+
/// to the current Gradle project.
|
|
10
|
+
///
|
|
11
|
+
/// To use it, add this to your build.gradle:
|
|
12
|
+
/// ```gradle
|
|
13
|
+
/// apply from: '../nitrogen/generated/android/audioconcat+autolinking.gradle'
|
|
14
|
+
/// ```
|
|
15
|
+
|
|
16
|
+
logger.warn("[NitroModules] 🔥 audioconcat is boosted by nitro!")
|
|
17
|
+
|
|
18
|
+
android {
|
|
19
|
+
sourceSets {
|
|
20
|
+
main {
|
|
21
|
+
java.srcDirs += [
|
|
22
|
+
// Nitrogen files
|
|
23
|
+
"${project.projectDir}/../nitrogen/generated/android/kotlin"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// audioconcatOnLoad.cpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#ifndef BUILDING_AUDIOCONCAT_WITH_GENERATED_CMAKE_PROJECT
|
|
9
|
+
#error audioconcatOnLoad.cpp is not being built with the autogenerated CMakeLists.txt project. Is a different CMakeLists.txt building this?
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
#include "audioconcatOnLoad.hpp"
|
|
13
|
+
|
|
14
|
+
#include <jni.h>
|
|
15
|
+
#include <fbjni/fbjni.h>
|
|
16
|
+
#include <NitroModules/HybridObjectRegistry.hpp>
|
|
17
|
+
|
|
18
|
+
#include "JHybridAudioConcatSpec.hpp"
|
|
19
|
+
#include <NitroModules/DefaultConstructableObject.hpp>
|
|
20
|
+
|
|
21
|
+
namespace margelo::nitro::audioconcat {
|
|
22
|
+
|
|
23
|
+
int initialize(JavaVM* vm) {
|
|
24
|
+
using namespace margelo::nitro;
|
|
25
|
+
using namespace margelo::nitro::audioconcat;
|
|
26
|
+
using namespace facebook;
|
|
27
|
+
|
|
28
|
+
return facebook::jni::initialize(vm, [] {
|
|
29
|
+
// Register native JNI methods
|
|
30
|
+
margelo::nitro::audioconcat::JHybridAudioConcatSpec::registerNatives();
|
|
31
|
+
|
|
32
|
+
// Register Nitro Hybrid Objects
|
|
33
|
+
HybridObjectRegistry::registerHybridObjectConstructor(
|
|
34
|
+
"AudioConcat",
|
|
35
|
+
[]() -> std::shared_ptr<HybridObject> {
|
|
36
|
+
static DefaultConstructableObject<JHybridAudioConcatSpec::javaobject> object("com/margelo/nitro/audioconcat/AudioConcat");
|
|
37
|
+
auto instance = object.create();
|
|
38
|
+
return instance->cthis()->shared();
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
} // namespace margelo::nitro::audioconcat
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// audioconcatOnLoad.hpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#include <jni.h>
|
|
9
|
+
#include <NitroModules/NitroDefines.hpp>
|
|
10
|
+
|
|
11
|
+
namespace margelo::nitro::audioconcat {
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Initializes the native (C++) part of audioconcat, and autolinks all Hybrid Objects.
|
|
15
|
+
* Call this in your `JNI_OnLoad` function (probably inside `cpp-adapter.cpp`).
|
|
16
|
+
* Example:
|
|
17
|
+
* ```cpp (cpp-adapter.cpp)
|
|
18
|
+
* JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
|
|
19
|
+
* return margelo::nitro::audioconcat::initialize(vm);
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
int initialize(JavaVM* vm);
|
|
24
|
+
|
|
25
|
+
} // namespace margelo::nitro::audioconcat
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// JAudioData.hpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <fbjni/fbjni.h>
|
|
11
|
+
#include "AudioData.hpp"
|
|
12
|
+
|
|
13
|
+
#include <string>
|
|
14
|
+
|
|
15
|
+
namespace margelo::nitro::audioconcat {
|
|
16
|
+
|
|
17
|
+
using namespace facebook;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The C++ JNI bridge between the C++ struct "AudioData" and the the Kotlin data class "AudioData".
|
|
21
|
+
*/
|
|
22
|
+
struct JAudioData final: public jni::JavaClass<JAudioData> {
|
|
23
|
+
public:
|
|
24
|
+
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/audioconcat/AudioData;";
|
|
25
|
+
|
|
26
|
+
public:
|
|
27
|
+
/**
|
|
28
|
+
* Convert this Java/Kotlin-based struct to the C++ struct AudioData by copying all values to C++.
|
|
29
|
+
*/
|
|
30
|
+
[[maybe_unused]]
|
|
31
|
+
[[nodiscard]]
|
|
32
|
+
AudioData toCpp() const {
|
|
33
|
+
static const auto clazz = javaClassStatic();
|
|
34
|
+
static const auto fieldFilePath = clazz->getField<jni::JString>("filePath");
|
|
35
|
+
jni::local_ref<jni::JString> filePath = this->getFieldValue(fieldFilePath);
|
|
36
|
+
return AudioData(
|
|
37
|
+
filePath->toStdString()
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public:
|
|
42
|
+
/**
|
|
43
|
+
* Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java.
|
|
44
|
+
*/
|
|
45
|
+
[[maybe_unused]]
|
|
46
|
+
static jni::local_ref<JAudioData::javaobject> fromCpp(const AudioData& value) {
|
|
47
|
+
return newInstance(
|
|
48
|
+
jni::make_jstring(value.filePath)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
} // namespace margelo::nitro::audioconcat
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// JAudioDataOrSilence.cpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#include "JAudioDataOrSilence.hpp"
|
|
9
|
+
|
|
10
|
+
namespace margelo::nitro::audioconcat {
|
|
11
|
+
/**
|
|
12
|
+
* Converts JAudioDataOrSilence to std::variant<AudioData, SilentData>
|
|
13
|
+
*/
|
|
14
|
+
std::variant<AudioData, SilentData> JAudioDataOrSilence::toCpp() const {
|
|
15
|
+
if (isInstanceOf(JAudioDataOrSilence_impl::First::javaClassStatic())) {
|
|
16
|
+
// It's a `AudioData`
|
|
17
|
+
auto jniValue = static_cast<const JAudioDataOrSilence_impl::First*>(this)->getValue();
|
|
18
|
+
return jniValue->toCpp();
|
|
19
|
+
} else if (isInstanceOf(JAudioDataOrSilence_impl::Second::javaClassStatic())) {
|
|
20
|
+
// It's a `SilentData`
|
|
21
|
+
auto jniValue = static_cast<const JAudioDataOrSilence_impl::Second*>(this)->getValue();
|
|
22
|
+
return jniValue->toCpp();
|
|
23
|
+
}
|
|
24
|
+
throw std::invalid_argument("Variant is unknown Kotlin instance!");
|
|
25
|
+
}
|
|
26
|
+
} // namespace margelo::nitro::audioconcat
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// JAudioDataOrSilence.hpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <fbjni/fbjni.h>
|
|
11
|
+
#include <variant>
|
|
12
|
+
|
|
13
|
+
#include "AudioData.hpp"
|
|
14
|
+
#include "SilentData.hpp"
|
|
15
|
+
#include <variant>
|
|
16
|
+
#include "JAudioData.hpp"
|
|
17
|
+
#include <string>
|
|
18
|
+
#include "JSilentData.hpp"
|
|
19
|
+
|
|
20
|
+
namespace margelo::nitro::audioconcat {
|
|
21
|
+
|
|
22
|
+
using namespace facebook;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The C++ JNI bridge between the C++ std::variant and the Java class "AudioDataOrSilence".
|
|
26
|
+
*/
|
|
27
|
+
class JAudioDataOrSilence: public jni::JavaClass<JAudioDataOrSilence> {
|
|
28
|
+
public:
|
|
29
|
+
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/audioconcat/AudioDataOrSilence;";
|
|
30
|
+
|
|
31
|
+
static jni::local_ref<JAudioDataOrSilence> create_0(jni::alias_ref<JAudioData> value) {
|
|
32
|
+
static const auto method = javaClassStatic()->getStaticMethod<JAudioDataOrSilence(jni::alias_ref<JAudioData>)>("create");
|
|
33
|
+
return method(javaClassStatic(), value);
|
|
34
|
+
}
|
|
35
|
+
static jni::local_ref<JAudioDataOrSilence> create_1(jni::alias_ref<JSilentData> value) {
|
|
36
|
+
static const auto method = javaClassStatic()->getStaticMethod<JAudioDataOrSilence(jni::alias_ref<JSilentData>)>("create");
|
|
37
|
+
return method(javaClassStatic(), value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static jni::local_ref<JAudioDataOrSilence> fromCpp(const std::variant<AudioData, SilentData>& variant) {
|
|
41
|
+
switch (variant.index()) {
|
|
42
|
+
case 0: return create_0(JAudioData::fromCpp(std::get<0>(variant)));
|
|
43
|
+
case 1: return create_1(JSilentData::fromCpp(std::get<1>(variant)));
|
|
44
|
+
default: throw std::invalid_argument("Variant holds unknown index! (" + std::to_string(variant.index()) + ")");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
[[nodiscard]] std::variant<AudioData, SilentData> toCpp() const;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
namespace JAudioDataOrSilence_impl {
|
|
52
|
+
class First: public jni::JavaClass<First, JAudioDataOrSilence> {
|
|
53
|
+
public:
|
|
54
|
+
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/audioconcat/AudioDataOrSilence$First;";
|
|
55
|
+
|
|
56
|
+
[[nodiscard]] jni::local_ref<JAudioData> getValue() const {
|
|
57
|
+
static const auto field = javaClassStatic()->getField<JAudioData>("value");
|
|
58
|
+
return getFieldValue(field);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
class Second: public jni::JavaClass<Second, JAudioDataOrSilence> {
|
|
63
|
+
public:
|
|
64
|
+
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/audioconcat/AudioDataOrSilence$Second;";
|
|
65
|
+
|
|
66
|
+
[[nodiscard]] jni::local_ref<JSilentData> getValue() const {
|
|
67
|
+
static const auto field = javaClassStatic()->getField<JSilentData>("value");
|
|
68
|
+
return getFieldValue(field);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
} // namespace JAudioDataOrSilence_impl
|
|
72
|
+
} // namespace margelo::nitro::audioconcat
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// JHybridAudioConcatSpec.cpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#include "JHybridAudioConcatSpec.hpp"
|
|
9
|
+
|
|
10
|
+
// Forward declaration of `AudioData` to properly resolve imports.
|
|
11
|
+
namespace margelo::nitro::audioconcat { struct AudioData; }
|
|
12
|
+
// Forward declaration of `SilentData` to properly resolve imports.
|
|
13
|
+
namespace margelo::nitro::audioconcat { struct SilentData; }
|
|
14
|
+
|
|
15
|
+
#include <string>
|
|
16
|
+
#include <NitroModules/Promise.hpp>
|
|
17
|
+
#include <NitroModules/JPromise.hpp>
|
|
18
|
+
#include "AudioData.hpp"
|
|
19
|
+
#include "SilentData.hpp"
|
|
20
|
+
#include <variant>
|
|
21
|
+
#include <vector>
|
|
22
|
+
#include "JAudioDataOrSilence.hpp"
|
|
23
|
+
#include "JAudioData.hpp"
|
|
24
|
+
#include "JSilentData.hpp"
|
|
25
|
+
|
|
26
|
+
namespace margelo::nitro::audioconcat {
|
|
27
|
+
|
|
28
|
+
jni::local_ref<JHybridAudioConcatSpec::jhybriddata> JHybridAudioConcatSpec::initHybrid(jni::alias_ref<jhybridobject> jThis) {
|
|
29
|
+
return makeCxxInstance(jThis);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
void JHybridAudioConcatSpec::registerNatives() {
|
|
33
|
+
registerHybrid({
|
|
34
|
+
makeNativeMethod("initHybrid", JHybridAudioConcatSpec::initHybrid),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
size_t JHybridAudioConcatSpec::getExternalMemorySize() noexcept {
|
|
39
|
+
static const auto method = javaClassStatic()->getMethod<jlong()>("getMemorySize");
|
|
40
|
+
return method(_javaPart);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void JHybridAudioConcatSpec::dispose() noexcept {
|
|
44
|
+
static const auto method = javaClassStatic()->getMethod<void()>("dispose");
|
|
45
|
+
method(_javaPart);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Properties
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
// Methods
|
|
52
|
+
std::shared_ptr<Promise<std::string>> JHybridAudioConcatSpec::concatAudioFiles(const std::vector<std::variant<AudioData, SilentData>>& data, const std::string& outputPath) {
|
|
53
|
+
static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(jni::alias_ref<jni::JArrayClass<JAudioDataOrSilence>> /* data */, jni::alias_ref<jni::JString> /* outputPath */)>("concatAudioFiles");
|
|
54
|
+
auto __result = method(_javaPart, [&]() {
|
|
55
|
+
size_t __size = data.size();
|
|
56
|
+
jni::local_ref<jni::JArrayClass<JAudioDataOrSilence>> __array = jni::JArrayClass<JAudioDataOrSilence>::newArray(__size);
|
|
57
|
+
for (size_t __i = 0; __i < __size; __i++) {
|
|
58
|
+
const auto& __element = data[__i];
|
|
59
|
+
__array->setElement(__i, *JAudioDataOrSilence::fromCpp(__element));
|
|
60
|
+
}
|
|
61
|
+
return __array;
|
|
62
|
+
}(), jni::make_jstring(outputPath));
|
|
63
|
+
return [&]() {
|
|
64
|
+
auto __promise = Promise<std::string>::create();
|
|
65
|
+
__result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
|
|
66
|
+
auto __result = jni::static_ref_cast<jni::JString>(__boxedResult);
|
|
67
|
+
__promise->resolve(__result->toStdString());
|
|
68
|
+
});
|
|
69
|
+
__result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
|
|
70
|
+
jni::JniException __jniError(__throwable);
|
|
71
|
+
__promise->reject(std::make_exception_ptr(__jniError));
|
|
72
|
+
});
|
|
73
|
+
return __promise;
|
|
74
|
+
}();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
} // namespace margelo::nitro::audioconcat
|