react-native-audio-api 0.9.0-nightly-96a5bcd-20251007 → 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/android/src/main/cpp/audioapi/android/core/{utils/AudioDecoder.cpp → AudioDecoder.cpp} +75 -79
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +43 -99
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +101 -1
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +3 -0
- package/common/cpp/audioapi/core/AudioContext.cpp +2 -0
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +35 -0
- package/common/cpp/audioapi/core/BaseAudioContext.h +12 -4
- package/common/cpp/audioapi/core/OfflineAudioContext.cpp +2 -0
- package/common/cpp/audioapi/core/utils/AudioDecoder.h +90 -36
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +282 -241
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.h +19 -57
- package/common/cpp/test/CMakeLists.txt +1 -1
- package/ios/audioapi/ios/core/AudioDecoder.mm +156 -0
- package/lib/commonjs/api.js +1 -14
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/core/BaseAudioContext.js +18 -11
- package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
- package/lib/module/api.js +1 -2
- package/lib/module/api.js.map +1 -1
- package/lib/module/core/BaseAudioContext.js +18 -11
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/typescript/api.d.ts +1 -3
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/core/BaseAudioContext.d.ts +6 -3
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/interfaces.d.ts +3 -6
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/api.ts +0 -5
- package/src/core/BaseAudioContext.ts +29 -26
- package/src/interfaces.ts +6 -18
- package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +0 -107
- package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.h +0 -28
- package/common/cpp/audioapi/core/types/AudioFormat.h +0 -16
- package/ios/audioapi/ios/core/utils/AudioDecoder.mm +0 -160
- package/lib/commonjs/core/AudioDecoder.js +0 -48
- package/lib/commonjs/core/AudioDecoder.js.map +0 -1
- package/lib/module/core/AudioDecoder.js +0 -42
- package/lib/module/core/AudioDecoder.js.map +0 -1
- package/lib/typescript/core/AudioDecoder.d.ts +0 -4
- package/lib/typescript/core/AudioDecoder.d.ts.map +0 -1
- package/src/core/AudioDecoder.ts +0 -78
package/android/src/main/cpp/audioapi/android/core/{utils/AudioDecoder.cpp → AudioDecoder.cpp}
RENAMED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#include <audioapi/core/sources/AudioBuffer.h>
|
|
2
1
|
#include <audioapi/core/utils/AudioDecoder.h>
|
|
3
2
|
#include <audioapi/dsp/VectorMath.h>
|
|
4
3
|
#include <audioapi/libs/base64/base64.h>
|
|
@@ -6,28 +5,28 @@
|
|
|
6
5
|
#include <audioapi/utils/AudioBus.h>
|
|
7
6
|
|
|
8
7
|
#define MINIAUDIO_IMPLEMENTATION
|
|
9
|
-
#include <audioapi/libs/miniaudio/decoders/libopus/miniaudio_libopus.h>
|
|
10
|
-
#include <audioapi/libs/miniaudio/decoders/libvorbis/miniaudio_libvorbis.h>
|
|
11
8
|
#include <audioapi/libs/miniaudio/miniaudio.h>
|
|
12
9
|
|
|
13
10
|
#ifndef AUDIO_API_TEST_SUITE
|
|
14
11
|
#include <android/log.h>
|
|
15
12
|
#include <audioapi/libs/ffmpeg/FFmpegDecoding.h>
|
|
16
13
|
#endif
|
|
14
|
+
#include <audioapi/libs/miniaudio/decoders/libopus/miniaudio_libopus.h>
|
|
15
|
+
#include <audioapi/libs/miniaudio/decoders/libvorbis/miniaudio_libvorbis.h>
|
|
17
16
|
|
|
18
17
|
namespace audioapi {
|
|
19
18
|
|
|
20
19
|
// Decoding audio in fixed-size chunks because total frame count can't be
|
|
21
20
|
// determined in advance. Note: ma_decoder_get_length_in_pcm_frames() always
|
|
22
21
|
// returns 0 for Vorbis decoders.
|
|
23
|
-
std::vector<
|
|
22
|
+
std::vector<int16_t> AudioDecoder::readAllPcmFrames(
|
|
24
23
|
ma_decoder &decoder,
|
|
25
|
-
int
|
|
26
|
-
|
|
27
|
-
std::vector<
|
|
28
|
-
|
|
24
|
+
int numChannels,
|
|
25
|
+
ma_uint64 &outFramesRead) {
|
|
26
|
+
std::vector<int16_t> buffer;
|
|
27
|
+
std::vector<int16_t> temp(CHUNK_SIZE * numChannels);
|
|
28
|
+
outFramesRead = 0;
|
|
29
29
|
|
|
30
|
-
#ifndef AUDIO_API_TEST_SUITE
|
|
31
30
|
while (true) {
|
|
32
31
|
ma_uint64 tempFramesDecoded = 0;
|
|
33
32
|
ma_decoder_read_pcm_frames(
|
|
@@ -39,46 +38,38 @@ std::vector<float> AudioDecoder::readAllPcmFrames(
|
|
|
39
38
|
buffer.insert(
|
|
40
39
|
buffer.end(),
|
|
41
40
|
temp.data(),
|
|
42
|
-
temp.data() + tempFramesDecoded *
|
|
41
|
+
temp.data() + tempFramesDecoded * numChannels);
|
|
43
42
|
outFramesRead += tempFramesDecoded;
|
|
44
43
|
}
|
|
45
44
|
|
|
46
|
-
if (outFramesRead == 0) {
|
|
47
|
-
__android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode");
|
|
48
|
-
}
|
|
49
|
-
#endif
|
|
50
45
|
return buffer;
|
|
51
46
|
}
|
|
52
47
|
|
|
53
|
-
std::shared_ptr<
|
|
54
|
-
const std::vector<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
auto outputFrames = buffer.size() / outputChannels;
|
|
62
|
-
auto audioBus = std::make_shared<AudioBus>(
|
|
63
|
-
outputFrames, outputChannels, outputSampleRate);
|
|
48
|
+
std::shared_ptr<AudioBus> AudioDecoder::makeAudioBusFromInt16Buffer(
|
|
49
|
+
const std::vector<int16_t> &buffer,
|
|
50
|
+
int numChannels,
|
|
51
|
+
float sampleRate) {
|
|
52
|
+
auto outputFrames = buffer.size() / numChannels;
|
|
53
|
+
auto audioBus =
|
|
54
|
+
std::make_shared<AudioBus>(outputFrames, numChannels, sampleRate);
|
|
64
55
|
|
|
65
|
-
for (int ch = 0; ch <
|
|
56
|
+
for (int ch = 0; ch < numChannels; ++ch) {
|
|
66
57
|
auto channelData = audioBus->getChannel(ch)->getData();
|
|
67
58
|
for (int i = 0; i < outputFrames; ++i) {
|
|
68
|
-
channelData[i] = buffer[i *
|
|
59
|
+
channelData[i] = int16ToFloat(buffer[i * numChannels + ch]);
|
|
69
60
|
}
|
|
70
61
|
}
|
|
71
|
-
return
|
|
62
|
+
return audioBus;
|
|
72
63
|
}
|
|
73
64
|
|
|
74
|
-
std::shared_ptr<
|
|
75
|
-
const std::string &path
|
|
76
|
-
float sampleRate) {
|
|
65
|
+
std::shared_ptr<AudioBus> AudioDecoder::decodeWithFilePath(
|
|
66
|
+
const std::string &path) const {
|
|
77
67
|
#ifndef AUDIO_API_TEST_SUITE
|
|
68
|
+
std::vector<int16_t> buffer;
|
|
78
69
|
if (AudioDecoder::pathHasExtension(path, {".mp4", ".m4a", ".aac"})) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (buffer
|
|
70
|
+
buffer = ffmpegdecoding::decodeWithFilePath(
|
|
71
|
+
path, numChannels_, static_cast<int>(sampleRate_));
|
|
72
|
+
if (buffer.empty()) {
|
|
82
73
|
__android_log_print(
|
|
83
74
|
ANDROID_LOG_ERROR,
|
|
84
75
|
"AudioDecoder",
|
|
@@ -86,11 +77,11 @@ std::shared_ptr<AudioBuffer> AudioDecoder::decodeWithFilePath(
|
|
|
86
77
|
path.c_str());
|
|
87
78
|
return nullptr;
|
|
88
79
|
}
|
|
89
|
-
return buffer;
|
|
80
|
+
return makeAudioBusFromInt16Buffer(buffer, numChannels_, sampleRate_);
|
|
90
81
|
}
|
|
91
82
|
ma_decoder decoder;
|
|
92
|
-
ma_decoder_config config =
|
|
93
|
-
|
|
83
|
+
ma_decoder_config config = ma_decoder_config_init(
|
|
84
|
+
ma_format_s16, numChannels_, static_cast<int>(sampleRate_));
|
|
94
85
|
ma_decoding_backend_vtable *customBackends[] = {
|
|
95
86
|
ma_decoding_backend_libvorbis, ma_decoding_backend_libopus};
|
|
96
87
|
|
|
@@ -108,38 +99,41 @@ std::shared_ptr<AudioBuffer> AudioDecoder::decodeWithFilePath(
|
|
|
108
99
|
return nullptr;
|
|
109
100
|
}
|
|
110
101
|
|
|
111
|
-
|
|
112
|
-
|
|
102
|
+
ma_uint64 framesRead = 0;
|
|
103
|
+
buffer = readAllPcmFrames(decoder, numChannels_, framesRead);
|
|
104
|
+
if (framesRead == 0) {
|
|
105
|
+
__android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode");
|
|
106
|
+
ma_decoder_uninit(&decoder);
|
|
107
|
+
return nullptr;
|
|
108
|
+
}
|
|
113
109
|
|
|
114
|
-
std::vector<float> buffer = readAllPcmFrames(decoder, outputChannels);
|
|
115
110
|
ma_decoder_uninit(&decoder);
|
|
116
|
-
return
|
|
117
|
-
buffer, outputSampleRate, outputChannels);
|
|
111
|
+
return makeAudioBusFromInt16Buffer(buffer, numChannels_, sampleRate_);
|
|
118
112
|
#else
|
|
119
113
|
return nullptr;
|
|
120
114
|
#endif
|
|
121
115
|
}
|
|
122
116
|
|
|
123
|
-
std::shared_ptr<
|
|
117
|
+
std::shared_ptr<AudioBus> AudioDecoder::decodeWithMemoryBlock(
|
|
124
118
|
const void *data,
|
|
125
|
-
size_t size
|
|
126
|
-
float sampleRate) {
|
|
119
|
+
size_t size) const {
|
|
127
120
|
#ifndef AUDIO_API_TEST_SUITE
|
|
121
|
+
std::vector<int16_t> buffer;
|
|
128
122
|
const AudioFormat format = AudioDecoder::detectAudioFormat(data, size);
|
|
129
123
|
if (format == AudioFormat::MP4 || format == AudioFormat::M4A ||
|
|
130
124
|
format == AudioFormat::AAC) {
|
|
131
|
-
|
|
132
|
-
data, size,
|
|
133
|
-
if (buffer
|
|
125
|
+
buffer = ffmpegdecoding::decodeWithMemoryBlock(
|
|
126
|
+
data, size, numChannels_, sampleRate_);
|
|
127
|
+
if (buffer.empty()) {
|
|
134
128
|
__android_log_print(
|
|
135
129
|
ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode with FFmpeg");
|
|
136
130
|
return nullptr;
|
|
137
131
|
}
|
|
138
|
-
return buffer;
|
|
132
|
+
return makeAudioBusFromInt16Buffer(buffer, numChannels_, sampleRate_);
|
|
139
133
|
}
|
|
140
134
|
ma_decoder decoder;
|
|
141
|
-
ma_decoder_config config =
|
|
142
|
-
|
|
135
|
+
ma_decoder_config config = ma_decoder_config_init(
|
|
136
|
+
ma_format_s16, numChannels_, static_cast<int>(sampleRate_));
|
|
143
137
|
|
|
144
138
|
ma_decoding_backend_vtable *customBackends[] = {
|
|
145
139
|
ma_decoding_backend_libvorbis, ma_decoding_backend_libopus};
|
|
@@ -157,48 +151,50 @@ std::shared_ptr<AudioBuffer> AudioDecoder::decodeWithMemoryBlock(
|
|
|
157
151
|
return nullptr;
|
|
158
152
|
}
|
|
159
153
|
|
|
160
|
-
|
|
161
|
-
|
|
154
|
+
ma_uint64 framesRead = 0;
|
|
155
|
+
buffer = readAllPcmFrames(decoder, numChannels_, framesRead);
|
|
156
|
+
if (framesRead == 0) {
|
|
157
|
+
__android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode");
|
|
158
|
+
ma_decoder_uninit(&decoder);
|
|
159
|
+
return nullptr;
|
|
160
|
+
}
|
|
162
161
|
|
|
163
|
-
std::vector<float> buffer = readAllPcmFrames(decoder, outputChannels);
|
|
164
162
|
ma_decoder_uninit(&decoder);
|
|
165
|
-
return
|
|
166
|
-
buffer, outputSampleRate, outputChannels);
|
|
163
|
+
return makeAudioBusFromInt16Buffer(buffer, numChannels_, sampleRate_);
|
|
167
164
|
#else
|
|
168
165
|
return nullptr;
|
|
169
166
|
#endif
|
|
170
167
|
}
|
|
171
168
|
|
|
172
|
-
std::shared_ptr<
|
|
169
|
+
std::shared_ptr<AudioBus> AudioDecoder::decodeWithPCMInBase64(
|
|
173
170
|
const std::string &data,
|
|
174
|
-
float
|
|
175
|
-
int inputChannelCount,
|
|
176
|
-
bool interleaved) {
|
|
171
|
+
float playbackSpeed) const {
|
|
177
172
|
auto decodedData = base64_decode(data, false);
|
|
173
|
+
|
|
178
174
|
const auto uint8Data = reinterpret_cast<uint8_t *>(decodedData.data());
|
|
179
|
-
size_t
|
|
180
|
-
decodedData.size() / (inputChannelCount * sizeof(int16_t));
|
|
175
|
+
size_t framesDecoded = decodedData.size() / 2;
|
|
181
176
|
|
|
182
|
-
|
|
183
|
-
|
|
177
|
+
std::vector<int16_t> buffer(framesDecoded);
|
|
178
|
+
for (size_t i = 0; i < framesDecoded; ++i) {
|
|
179
|
+
buffer[i] =
|
|
180
|
+
static_cast<int16_t>((uint8Data[i * 2 + 1] << 8) | uint8Data[i * 2]);
|
|
181
|
+
}
|
|
184
182
|
|
|
185
|
-
|
|
186
|
-
|
|
183
|
+
changePlaybackSpeedIfNeeded(buffer, framesDecoded, 1, playbackSpeed);
|
|
184
|
+
auto outputFrames = buffer.size();
|
|
187
185
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
channelData[i] = uint8ToFloat(uint8Data[offset], uint8Data[offset + 1]);
|
|
199
|
-
}
|
|
186
|
+
auto audioBus =
|
|
187
|
+
std::make_shared<AudioBus>(outputFrames, numChannels_, sampleRate_);
|
|
188
|
+
auto leftChannelData = audioBus->getChannel(0)->getData();
|
|
189
|
+
auto rightChannelData = audioBus->getChannel(1)->getData();
|
|
190
|
+
|
|
191
|
+
for (size_t i = 0; i < outputFrames; ++i) {
|
|
192
|
+
auto sample = int16ToFloat(buffer[i]);
|
|
193
|
+
leftChannelData[i] = sample;
|
|
194
|
+
rightChannelData[i] = sample;
|
|
200
195
|
}
|
|
201
|
-
|
|
196
|
+
|
|
197
|
+
return audioBus;
|
|
202
198
|
}
|
|
203
199
|
|
|
204
200
|
} // namespace audioapi
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
-
#include <audioapi/
|
|
4
|
-
#include <audioapi/HostObjects/OfflineAudioContextHostObject.h>
|
|
5
|
-
#include <audioapi/HostObjects/inputs/AudioRecorderHostObject.h>
|
|
6
|
-
#include <audioapi/HostObjects/utils/AudioDecoderHostObject.h>
|
|
3
|
+
#include <audioapi/jsi/JsiPromise.h>
|
|
7
4
|
#include <audioapi/core/AudioContext.h>
|
|
8
5
|
#include <audioapi/core/OfflineAudioContext.h>
|
|
9
6
|
#include <audioapi/core/inputs/AudioRecorder.h>
|
|
10
|
-
#include <audioapi/
|
|
7
|
+
#include <audioapi/HostObjects/AudioContextHostObject.h>
|
|
8
|
+
#include <audioapi/HostObjects/OfflineAudioContextHostObject.h>
|
|
9
|
+
#include <audioapi/HostObjects/inputs/AudioRecorderHostObject.h>
|
|
11
10
|
|
|
12
|
-
#include <audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.h>
|
|
13
11
|
#include <audioapi/events/AudioEventHandlerRegistry.h>
|
|
12
|
+
#include <audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.h>
|
|
14
13
|
|
|
15
14
|
#include <audioapi/core/utils/worklets/SafeIncludes.h>
|
|
16
15
|
|
|
@@ -23,46 +22,29 @@ using namespace facebook;
|
|
|
23
22
|
class AudioAPIModuleInstaller {
|
|
24
23
|
public:
|
|
25
24
|
static void injectJSIBindings(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
auto createAudioContext = getCreateAudioContextFunction(
|
|
32
|
-
|
|
33
|
-
auto
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
jsiRuntime->global().setProperty(
|
|
41
|
-
*jsiRuntime, "createAudioContext", createAudioContext);
|
|
42
|
-
jsiRuntime->global().setProperty(
|
|
43
|
-
*jsiRuntime, "createAudioRecorder", createAudioRecorder);
|
|
44
|
-
jsiRuntime->global().setProperty(
|
|
45
|
-
*jsiRuntime, "createOfflineAudioContext", createOfflineAudioContext);
|
|
46
|
-
jsiRuntime->global().setProperty(
|
|
47
|
-
*jsiRuntime, "createAudioDecoder", createAudioDecoder);
|
|
48
|
-
|
|
49
|
-
auto audioEventHandlerRegistryHostObject =
|
|
50
|
-
std::make_shared<AudioEventHandlerRegistryHostObject>(
|
|
51
|
-
audioEventHandlerRegistry);
|
|
52
|
-
jsiRuntime->global().setProperty(
|
|
53
|
-
*jsiRuntime,
|
|
54
|
-
"AudioEventEmitter",
|
|
55
|
-
jsi::Object::createFromHostObject(
|
|
56
|
-
*jsiRuntime, audioEventHandlerRegistryHostObject));
|
|
25
|
+
jsi::Runtime *jsiRuntime,
|
|
26
|
+
const std::shared_ptr<react::CallInvoker> &jsCallInvoker,
|
|
27
|
+
const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry,
|
|
28
|
+
std::shared_ptr<worklets::WorkletRuntime> uiRuntime = nullptr) {
|
|
29
|
+
|
|
30
|
+
auto createAudioContext = getCreateAudioContextFunction(jsiRuntime, jsCallInvoker, audioEventHandlerRegistry, uiRuntime);
|
|
31
|
+
auto createAudioRecorder = getCreateAudioRecorderFunction(jsiRuntime, audioEventHandlerRegistry);
|
|
32
|
+
auto createOfflineAudioContext = getCreateOfflineAudioContextFunction(jsiRuntime, jsCallInvoker, audioEventHandlerRegistry, uiRuntime);
|
|
33
|
+
|
|
34
|
+
jsiRuntime->global().setProperty(*jsiRuntime, "createAudioContext", createAudioContext);
|
|
35
|
+
jsiRuntime->global().setProperty(*jsiRuntime, "createAudioRecorder", createAudioRecorder);
|
|
36
|
+
jsiRuntime->global().setProperty(*jsiRuntime, "createOfflineAudioContext", createOfflineAudioContext);
|
|
37
|
+
|
|
38
|
+
auto audioEventHandlerRegistryHostObject = std::make_shared<AudioEventHandlerRegistryHostObject>(audioEventHandlerRegistry);
|
|
39
|
+
jsiRuntime->global().setProperty(*jsiRuntime, "AudioEventEmitter", jsi::Object::createFromHostObject(*jsiRuntime, audioEventHandlerRegistryHostObject));
|
|
57
40
|
}
|
|
58
41
|
|
|
59
42
|
private:
|
|
60
43
|
static jsi::Function getCreateAudioContextFunction(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const std::weak_ptr<worklets::WorkletRuntime> &uiRuntime) {
|
|
44
|
+
jsi::Runtime *jsiRuntime,
|
|
45
|
+
const std::shared_ptr<react::CallInvoker> &jsCallInvoker,
|
|
46
|
+
const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry,
|
|
47
|
+
const std::weak_ptr<worklets::WorkletRuntime> &uiRuntime) {
|
|
66
48
|
return jsi::Function::createFromHostFunction(
|
|
67
49
|
*jsiRuntime,
|
|
68
50
|
jsi::PropNameID::forAscii(*jsiRuntime, "createAudioContext"),
|
|
@@ -85,14 +67,9 @@ class AudioAPIModuleInstaller {
|
|
|
85
67
|
auto runtimeRegistry = RuntimeRegistry{};
|
|
86
68
|
#endif
|
|
87
69
|
|
|
88
|
-
audioContext = std::make_shared<AudioContext>(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
audioEventHandlerRegistry,
|
|
92
|
-
runtimeRegistry);
|
|
93
|
-
auto audioContextHostObject =
|
|
94
|
-
std::make_shared<AudioContextHostObject>(
|
|
95
|
-
audioContext, &runtime, jsCallInvoker);
|
|
70
|
+
audioContext = std::make_shared<AudioContext>(sampleRate, initSuspended, audioEventHandlerRegistry, runtimeRegistry);
|
|
71
|
+
auto audioContextHostObject = std::make_shared<AudioContextHostObject>(
|
|
72
|
+
audioContext, &runtime, jsCallInvoker);
|
|
96
73
|
|
|
97
74
|
return jsi::Object::createFromHostObject(
|
|
98
75
|
runtime, audioContextHostObject);
|
|
@@ -100,11 +77,10 @@ class AudioAPIModuleInstaller {
|
|
|
100
77
|
}
|
|
101
78
|
|
|
102
79
|
static jsi::Function getCreateOfflineAudioContextFunction(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const std::weak_ptr<worklets::WorkletRuntime> &uiRuntime) {
|
|
80
|
+
jsi::Runtime *jsiRuntime,
|
|
81
|
+
const std::shared_ptr<react::CallInvoker> &jsCallInvoker,
|
|
82
|
+
const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry,
|
|
83
|
+
const std::weak_ptr<worklets::WorkletRuntime> &uiRuntime) {
|
|
108
84
|
return jsi::Function::createFromHostFunction(
|
|
109
85
|
*jsiRuntime,
|
|
110
86
|
jsi::PropNameID::forAscii(*jsiRuntime, "createOfflineAudioContext"),
|
|
@@ -114,9 +90,9 @@ class AudioAPIModuleInstaller {
|
|
|
114
90
|
const jsi::Value &thisValue,
|
|
115
91
|
const jsi::Value *args,
|
|
116
92
|
size_t count) -> jsi::Value {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
93
|
+
auto numberOfChannels = static_cast<int>(args[0].getNumber());
|
|
94
|
+
auto length = static_cast<size_t>(args[1].getNumber());
|
|
95
|
+
auto sampleRate = static_cast<float>(args[2].getNumber());
|
|
120
96
|
|
|
121
97
|
#if RN_AUDIO_API_ENABLE_WORKLETS
|
|
122
98
|
auto runtimeRegistry = RuntimeRegistry{
|
|
@@ -127,15 +103,9 @@ class AudioAPIModuleInstaller {
|
|
|
127
103
|
auto runtimeRegistry = RuntimeRegistry{};
|
|
128
104
|
#endif
|
|
129
105
|
|
|
130
|
-
auto offlineAudioContext = std::make_shared<OfflineAudioContext>(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
sampleRate,
|
|
134
|
-
audioEventHandlerRegistry,
|
|
135
|
-
runtimeRegistry);
|
|
136
|
-
auto audioContextHostObject =
|
|
137
|
-
std::make_shared<OfflineAudioContextHostObject>(
|
|
138
|
-
offlineAudioContext, &runtime, jsCallInvoker);
|
|
106
|
+
auto offlineAudioContext = std::make_shared<OfflineAudioContext>(numberOfChannels, length, sampleRate, audioEventHandlerRegistry, runtimeRegistry);
|
|
107
|
+
auto audioContextHostObject = std::make_shared<OfflineAudioContextHostObject>(
|
|
108
|
+
offlineAudioContext, &runtime, jsCallInvoker);
|
|
139
109
|
|
|
140
110
|
return jsi::Object::createFromHostObject(
|
|
141
111
|
runtime, audioContextHostObject);
|
|
@@ -143,9 +113,8 @@ class AudioAPIModuleInstaller {
|
|
|
143
113
|
}
|
|
144
114
|
|
|
145
115
|
static jsi::Function getCreateAudioRecorderFunction(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
&audioEventHandlerRegistry) {
|
|
116
|
+
jsi::Runtime *jsiRuntime,
|
|
117
|
+
const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry) {
|
|
149
118
|
return jsi::Function::createFromHostFunction(
|
|
150
119
|
*jsiRuntime,
|
|
151
120
|
jsi::PropNameID::forAscii(*jsiRuntime, "createAudioRecorder"),
|
|
@@ -157,37 +126,12 @@ class AudioAPIModuleInstaller {
|
|
|
157
126
|
size_t count) -> jsi::Value {
|
|
158
127
|
auto options = args[0].getObject(runtime);
|
|
159
128
|
|
|
160
|
-
auto sampleRate = static_cast<float>(
|
|
161
|
-
|
|
162
|
-
auto bufferLength = static_cast<int>(
|
|
163
|
-
options.getProperty(runtime, "bufferLengthInSamples")
|
|
164
|
-
.getNumber());
|
|
129
|
+
auto sampleRate = static_cast<float>(options.getProperty(runtime, "sampleRate").getNumber());
|
|
130
|
+
auto bufferLength = static_cast<int>(options.getProperty(runtime, "bufferLengthInSamples").getNumber());
|
|
165
131
|
|
|
166
|
-
auto audioRecorderHostObject =
|
|
167
|
-
std::make_shared<AudioRecorderHostObject>(
|
|
168
|
-
audioEventHandlerRegistry, sampleRate, bufferLength);
|
|
132
|
+
auto audioRecorderHostObject = std::make_shared<AudioRecorderHostObject>(audioEventHandlerRegistry, sampleRate, bufferLength);
|
|
169
133
|
|
|
170
|
-
return jsi::Object::createFromHostObject(
|
|
171
|
-
runtime, audioRecorderHostObject);
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
static jsi::Function getCreateAudioDecoderFunction(
|
|
176
|
-
jsi::Runtime *jsiRuntime,
|
|
177
|
-
const std::shared_ptr<react::CallInvoker> &jsCallInvoker) {
|
|
178
|
-
return jsi::Function::createFromHostFunction(
|
|
179
|
-
*jsiRuntime,
|
|
180
|
-
jsi::PropNameID::forAscii(*jsiRuntime, "createAudioDecoder"),
|
|
181
|
-
0,
|
|
182
|
-
[jsCallInvoker](
|
|
183
|
-
jsi::Runtime &runtime,
|
|
184
|
-
const jsi::Value &thisValue,
|
|
185
|
-
const jsi::Value *args,
|
|
186
|
-
size_t count) -> jsi::Value {
|
|
187
|
-
auto audioDecoderHostObject =
|
|
188
|
-
std::make_shared<AudioDecoderHostObject>(&runtime, jsCallInvoker);
|
|
189
|
-
return jsi::Object::createFromHostObject(
|
|
190
|
-
runtime, audioDecoderHostObject);
|
|
134
|
+
return jsi::Object::createFromHostObject(runtime, audioRecorderHostObject);
|
|
191
135
|
});
|
|
192
136
|
}
|
|
193
137
|
};
|
|
@@ -49,7 +49,11 @@ BaseAudioContextHostObject::BaseAudioContextHostObject(
|
|
|
49
49
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createBufferQueueSource),
|
|
50
50
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createBuffer),
|
|
51
51
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createPeriodicWave),
|
|
52
|
-
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createAnalyser)
|
|
52
|
+
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createAnalyser),
|
|
53
|
+
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, decodeAudioData),
|
|
54
|
+
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, decodeAudioDataSource),
|
|
55
|
+
JSI_EXPORT_FUNCTION(
|
|
56
|
+
BaseAudioContextHostObject, decodePCMAudioDataInBase64));
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
JSI_PROPERTY_GETTER_IMPL(BaseAudioContextHostObject, destination) {
|
|
@@ -262,4 +266,100 @@ JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createAnalyser) {
|
|
|
262
266
|
auto analyserHostObject = std::make_shared<AnalyserNodeHostObject>(analyser);
|
|
263
267
|
return jsi::Object::createFromHostObject(runtime, analyserHostObject);
|
|
264
268
|
}
|
|
269
|
+
|
|
270
|
+
JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, decodeAudioDataSource) {
|
|
271
|
+
auto sourcePath = args[0].getString(runtime).utf8(runtime);
|
|
272
|
+
|
|
273
|
+
auto promise = promiseVendor_->createPromise(
|
|
274
|
+
[this, sourcePath](std::shared_ptr<Promise> promise) {
|
|
275
|
+
std::thread([this, sourcePath, promise = std::move(promise)]() {
|
|
276
|
+
auto results = context_->decodeAudioDataSource(sourcePath);
|
|
277
|
+
|
|
278
|
+
if (!results) {
|
|
279
|
+
promise->reject("Failed to decode audio data source.");
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
auto audioBufferHostObject =
|
|
284
|
+
std::make_shared<AudioBufferHostObject>(results);
|
|
285
|
+
|
|
286
|
+
promise->resolve([audioBufferHostObject = std::move(
|
|
287
|
+
audioBufferHostObject)](jsi::Runtime &runtime) {
|
|
288
|
+
auto jsiObject = jsi::Object::createFromHostObject(
|
|
289
|
+
runtime, audioBufferHostObject);
|
|
290
|
+
jsiObject.setExternalMemoryPressure(
|
|
291
|
+
runtime, audioBufferHostObject->getSizeInBytes());
|
|
292
|
+
return jsiObject;
|
|
293
|
+
});
|
|
294
|
+
}).detach();
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
return promise;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, decodeAudioData) {
|
|
301
|
+
auto arrayBuffer = args[0]
|
|
302
|
+
.getObject(runtime)
|
|
303
|
+
.getPropertyAsObject(runtime, "buffer")
|
|
304
|
+
.getArrayBuffer(runtime);
|
|
305
|
+
auto data = arrayBuffer.data(runtime);
|
|
306
|
+
auto size = static_cast<int>(arrayBuffer.size(runtime));
|
|
307
|
+
|
|
308
|
+
auto promise = promiseVendor_->createPromise(
|
|
309
|
+
[this, data, size](std::shared_ptr<Promise> promise) {
|
|
310
|
+
std::thread([this, data, size, promise = std::move(promise)]() {
|
|
311
|
+
auto results = context_->decodeAudioData(data, size);
|
|
312
|
+
|
|
313
|
+
if (!results) {
|
|
314
|
+
promise->reject("Failed to decode audio data source.");
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
auto audioBufferHostObject =
|
|
319
|
+
std::make_shared<AudioBufferHostObject>(results);
|
|
320
|
+
|
|
321
|
+
promise->resolve([audioBufferHostObject = std::move(
|
|
322
|
+
audioBufferHostObject)](jsi::Runtime &runtime) {
|
|
323
|
+
auto jsiObject = jsi::Object::createFromHostObject(
|
|
324
|
+
runtime, audioBufferHostObject);
|
|
325
|
+
jsiObject.setExternalMemoryPressure(
|
|
326
|
+
runtime, audioBufferHostObject->getSizeInBytes());
|
|
327
|
+
return jsiObject;
|
|
328
|
+
});
|
|
329
|
+
}).detach();
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
return promise;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, decodePCMAudioDataInBase64) {
|
|
336
|
+
auto b64 = args[0].getString(runtime).utf8(runtime);
|
|
337
|
+
auto playbackSpeed = static_cast<float>(args[1].getNumber());
|
|
338
|
+
|
|
339
|
+
auto promise = promiseVendor_->createPromise(
|
|
340
|
+
[this, b64, playbackSpeed](std::shared_ptr<Promise> promise) {
|
|
341
|
+
std::thread([this, b64, playbackSpeed, promise = std::move(promise)]() {
|
|
342
|
+
auto results = context_->decodeWithPCMInBase64(b64, playbackSpeed);
|
|
343
|
+
|
|
344
|
+
if (!results) {
|
|
345
|
+
promise->reject("Failed to decode audio data source.");
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
auto audioBufferHostObject =
|
|
350
|
+
std::make_shared<AudioBufferHostObject>(results);
|
|
351
|
+
|
|
352
|
+
promise->resolve([audioBufferHostObject = std::move(
|
|
353
|
+
audioBufferHostObject)](jsi::Runtime &runtime) {
|
|
354
|
+
auto jsiObject = jsi::Object::createFromHostObject(
|
|
355
|
+
runtime, audioBufferHostObject);
|
|
356
|
+
jsiObject.setExternalMemoryPressure(
|
|
357
|
+
runtime, audioBufferHostObject->getSizeInBytes());
|
|
358
|
+
return jsiObject;
|
|
359
|
+
});
|
|
360
|
+
}).detach();
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
return promise;
|
|
364
|
+
}
|
|
265
365
|
} // namespace audioapi
|
|
@@ -41,6 +41,9 @@ class BaseAudioContextHostObject : public JsiHostObject {
|
|
|
41
41
|
JSI_HOST_FUNCTION_DECL(createBuffer);
|
|
42
42
|
JSI_HOST_FUNCTION_DECL(createPeriodicWave);
|
|
43
43
|
JSI_HOST_FUNCTION_DECL(createAnalyser);
|
|
44
|
+
JSI_HOST_FUNCTION_DECL(decodeAudioDataSource);
|
|
45
|
+
JSI_HOST_FUNCTION_DECL(decodeAudioData);
|
|
46
|
+
JSI_HOST_FUNCTION_DECL(decodePCMAudioDataInBase64);
|
|
44
47
|
|
|
45
48
|
std::shared_ptr<BaseAudioContext> context_;
|
|
46
49
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
#include <audioapi/core/AudioContext.h>
|
|
8
8
|
#include <audioapi/core/destinations/AudioDestinationNode.h>
|
|
9
|
+
#include <audioapi/core/utils/AudioDecoder.h>
|
|
9
10
|
#include <audioapi/core/utils/AudioNodeManager.h>
|
|
10
11
|
|
|
11
12
|
namespace audioapi {
|
|
@@ -25,6 +26,7 @@ AudioContext::AudioContext(
|
|
|
25
26
|
#endif
|
|
26
27
|
|
|
27
28
|
sampleRate_ = sampleRate;
|
|
29
|
+
audioDecoder_ = std::make_shared<AudioDecoder>(sampleRate);
|
|
28
30
|
|
|
29
31
|
if (initSuspended) {
|
|
30
32
|
playerHasBeenStarted_ = false;
|
|
@@ -176,6 +176,41 @@ std::shared_ptr<AnalyserNode> BaseAudioContext::createAnalyser() {
|
|
|
176
176
|
return analyser;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(
|
|
180
|
+
const std::string &path) {
|
|
181
|
+
auto audioBus = audioDecoder_->decodeWithFilePath(path);
|
|
182
|
+
|
|
183
|
+
if (!audioBus) {
|
|
184
|
+
return nullptr;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return std::make_shared<AudioBuffer>(audioBus);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioData(
|
|
191
|
+
const void *data,
|
|
192
|
+
size_t size) {
|
|
193
|
+
auto audioBus = audioDecoder_->decodeWithMemoryBlock(data, size);
|
|
194
|
+
|
|
195
|
+
if (!audioBus) {
|
|
196
|
+
return nullptr;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return std::make_shared<AudioBuffer>(audioBus);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeWithPCMInBase64(
|
|
203
|
+
const std::string &data,
|
|
204
|
+
float playbackSpeed) {
|
|
205
|
+
auto audioBus = audioDecoder_->decodeWithPCMInBase64(data, playbackSpeed);
|
|
206
|
+
|
|
207
|
+
if (!audioBus) {
|
|
208
|
+
return nullptr;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return std::make_shared<AudioBuffer>(audioBus);
|
|
212
|
+
}
|
|
213
|
+
|
|
179
214
|
AudioNodeManager *BaseAudioContext::getNodeManager() {
|
|
180
215
|
return nodeManager_.get();
|
|
181
216
|
}
|