react-native-audio-api 0.12.1 → 0.12.2
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 +8 -3
- package/RNAudioAPI.podspec +0 -2
- package/android/src/main/cpp/audioapi/CMakeLists.txt +8 -2
- package/android/src/main/cpp/audioapi/android/AudioAPIModule.cpp +7 -29
- package/android/src/main/cpp/audioapi/android/JniEventPayloadParser.cpp +83 -0
- package/android/src/main/cpp/audioapi/android/JniEventPayloadParser.h +14 -0
- package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +4 -3
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +1 -0
- package/android/src/main/cpp/audioapi/android/core/utils/AndroidRecorderCallback.cpp +37 -21
- package/android/src/main/cpp/audioapi/android/core/utils/AndroidRecorderCallback.h +1 -1
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +21 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp +26 -4
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.h +1 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioFileSourceNodeHostObject.cpp +2 -2
- package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +3 -3
- package/common/cpp/audioapi/HostObjects/utils/AudioFileUtilsHostObject.cpp +60 -0
- package/common/cpp/audioapi/HostObjects/utils/AudioFileUtilsHostObject.h +24 -0
- package/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h +2 -2
- package/common/cpp/audioapi/core/OfflineAudioContext.cpp +0 -1
- package/common/cpp/audioapi/core/OfflineAudioContext.h +0 -1
- package/common/cpp/audioapi/core/effects/ConvolverNode.cpp +4 -10
- package/common/cpp/audioapi/core/effects/ConvolverNode.h +0 -4
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +13 -11
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +5 -9
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +47 -139
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +11 -8
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +29 -114
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +6 -8
- package/common/cpp/audioapi/core/sources/AudioFileSourceNode.cpp +9 -11
- package/common/cpp/audioapi/core/sources/AudioFileSourceNode.h +1 -1
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +2 -2
- package/common/cpp/audioapi/core/types/AudioFormat.h +3 -1
- package/common/cpp/audioapi/core/utils/AudioDecoder.cpp +120 -91
- package/common/cpp/audioapi/core/utils/AudioDecoder.h +24 -101
- package/common/cpp/audioapi/core/utils/AudioFileConcatenator.cpp +862 -0
- package/common/cpp/audioapi/core/utils/AudioFileConcatenator.h +164 -0
- package/common/cpp/audioapi/core/utils/AudioFileWriter.cpp +2 -4
- package/common/cpp/audioapi/core/utils/AudioRecorderCallback.cpp +7 -12
- package/common/cpp/audioapi/core/utils/AudioRecorderCallback.h +2 -0
- package/common/cpp/audioapi/core/utils/buffer/BufferProcessingDirection.h +6 -0
- package/common/cpp/audioapi/core/utils/buffer/BufferProcessorBase.cpp +110 -0
- package/common/cpp/audioapi/core/utils/buffer/BufferProcessorBase.h +75 -0
- package/common/cpp/audioapi/core/utils/buffer/QueueBufferProcessor.cpp +129 -0
- package/common/cpp/audioapi/core/utils/buffer/QueueBufferProcessor.h +55 -0
- package/common/cpp/audioapi/core/utils/buffer/SingleBufferProcessor.cpp +95 -0
- package/common/cpp/audioapi/core/utils/buffer/SingleBufferProcessor.h +52 -0
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +65 -157
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +52 -33
- package/common/cpp/audioapi/events/AudioEventPayload.h +87 -0
- package/common/cpp/audioapi/events/IAudioEventHandlerRegistry.h +12 -12
- package/common/cpp/audioapi/libs/decoding/IncrementalAudioDecoder.h +12 -10
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +152 -78
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.h +6 -6
- package/common/cpp/audioapi/libs/miniaudio/MiniAudioDecoding.cpp +34 -20
- package/common/cpp/audioapi/libs/miniaudio/MiniAudioDecoding.h +4 -4
- package/common/cpp/audioapi/utils/AudioArray.hpp +6 -1
- package/common/cpp/audioapi/utils/CrossThreadEventScheduler.hpp +1 -1
- package/common/cpp/audioapi/utils/TaskOffloader.hpp +3 -5
- package/ios/audioapi/ios/AudioAPIModule.h +2 -1
- package/ios/audioapi/ios/AudioAPIModule.mm +4 -25
- package/ios/audioapi/ios/core/IOSAudioPlayer.h +16 -2
- package/ios/audioapi/ios/core/IOSAudioPlayer.mm +90 -24
- package/ios/audioapi/ios/core/IOSAudioRecorder.mm +1 -1
- package/ios/audioapi/ios/core/utils/IOSRecorderCallback.mm +64 -20
- package/ios/audioapi/ios/system/AudioSessionManager.mm +18 -7
- package/ios/audioapi/ios/system/SystemNotificationManager.mm +22 -22
- package/ios/audioapi/ios/system/notification/PlaybackNotification.mm +10 -13
- package/lib/commonjs/AudioAPIModule/AudioAPIModule.js +1 -1
- package/lib/commonjs/AudioAPIModule/AudioAPIModule.js.map +1 -1
- package/lib/commonjs/api.js +8 -0
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/api.web.js +5 -0
- package/lib/commonjs/api.web.js.map +1 -1
- package/lib/commonjs/core/AudioFileUtils.js +35 -0
- package/lib/commonjs/core/AudioFileUtils.js.map +1 -0
- package/lib/commonjs/mock/index.js +15 -1
- package/lib/commonjs/mock/index.js.map +1 -1
- package/lib/module/AudioAPIModule/AudioAPIModule.js +1 -1
- package/lib/module/AudioAPIModule/AudioAPIModule.js.map +1 -1
- package/lib/module/api.js +1 -0
- package/lib/module/api.js.map +1 -1
- package/lib/module/api.web.js +3 -0
- package/lib/module/api.web.js.map +1 -1
- package/lib/module/core/AudioFileUtils.js +31 -0
- package/lib/module/core/AudioFileUtils.js.map +1 -0
- package/lib/module/mock/index.js +14 -1
- package/lib/module/mock/index.js.map +1 -1
- package/lib/typescript/AudioAPIModule/AudioAPIModule.d.ts.map +1 -1
- package/lib/typescript/api.d.ts +1 -0
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/api.web.d.ts +1 -0
- package/lib/typescript/api.web.d.ts.map +1 -1
- package/lib/typescript/core/AudioFileUtils.d.ts +2 -0
- package/lib/typescript/core/AudioFileUtils.d.ts.map +1 -0
- package/lib/typescript/interfaces.d.ts +3 -0
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/mock/index.d.ts +3 -1
- package/lib/typescript/mock/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/scripts/download-prebuilt-binaries.sh +34 -1
- package/src/AudioAPIModule/AudioAPIModule.ts +1 -0
- package/src/AudioAPIModule/globals.d.ts +3 -0
- package/src/api.ts +1 -0
- package/src/api.web.ts +7 -0
- package/src/core/AudioFileUtils.ts +49 -0
- package/src/interfaces.ts +7 -0
- package/src/mock/index.ts +29 -0
|
@@ -10,8 +10,6 @@
|
|
|
10
10
|
#include <algorithm>
|
|
11
11
|
#include <cassert>
|
|
12
12
|
#include <memory>
|
|
13
|
-
#include <string>
|
|
14
|
-
#include <unordered_map>
|
|
15
13
|
|
|
16
14
|
#if !RN_AUDIO_API_FFMPEG_DISABLED
|
|
17
15
|
#include <audioapi/libs/ffmpeg/FFmpegDecoding.h>
|
|
@@ -69,10 +67,10 @@ void AudioFileSourceNode::sendOnPositionChangedEvent(int framesPlayed) {
|
|
|
69
67
|
if (onPositionChangedCallbackId_ != 0 &&
|
|
70
68
|
(onPositionChangedFlush_.load(std::memory_order_acquire) ||
|
|
71
69
|
onPositionChangedTime_ > onPositionChangedInterval_)) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
audioEventHandlerRegistry_->dispatchEvent(
|
|
71
|
+
AudioEvent::POSITION_CHANGED,
|
|
72
|
+
onPositionChangedCallbackId_,
|
|
73
|
+
DoubleValuePayload{.value = getCurrentTime()});
|
|
76
74
|
|
|
77
75
|
onPositionChangedTime_ = 0;
|
|
78
76
|
onPositionChangedFlush_.store(false, std::memory_order_release);
|
|
@@ -85,7 +83,7 @@ void AudioFileSourceNode::initDecoders(
|
|
|
85
83
|
bool useFilePath,
|
|
86
84
|
const std::shared_ptr<BaseAudioContext> &context,
|
|
87
85
|
const std::shared_ptr<AudioFileDecoderState> &state) {
|
|
88
|
-
|
|
86
|
+
decoding::DecoderResult openResult = Ok(None);
|
|
89
87
|
if (requiresFFmpeg_) {
|
|
90
88
|
#if !RN_AUDIO_API_FFMPEG_DISABLED
|
|
91
89
|
decoder_ = std::make_unique<ffmpegdecoder::FFmpegDecoder>();
|
|
@@ -94,14 +92,14 @@ void AudioFileSourceNode::initDecoders(
|
|
|
94
92
|
decoder_ = std::make_unique<miniaudio_decoder::MiniAudioDecoder>();
|
|
95
93
|
}
|
|
96
94
|
if (useFilePath) {
|
|
97
|
-
|
|
95
|
+
openResult = decoder_->openFile(static_cast<int>(context->getSampleRate()), state->filePath);
|
|
98
96
|
} else {
|
|
99
|
-
|
|
97
|
+
openResult = decoder_->openMemory(
|
|
100
98
|
static_cast<int>(context->getSampleRate()),
|
|
101
99
|
state->memoryData.data(),
|
|
102
100
|
state->memoryData.size());
|
|
103
101
|
}
|
|
104
|
-
if (
|
|
102
|
+
if (openResult.is_ok()) {
|
|
105
103
|
state->channels = decoder_->outputChannels();
|
|
106
104
|
state->sampleRate = static_cast<float>(decoder_->outputSampleRate());
|
|
107
105
|
duration_ = static_cast<double>(decoder_->getDurationInSeconds());
|
|
@@ -142,7 +140,7 @@ size_t AudioFileSourceNode::readFrames(float *buf, size_t frameCount) {
|
|
|
142
140
|
}
|
|
143
141
|
|
|
144
142
|
bool AudioFileSourceNode::seekDecoderToTime(double seconds) {
|
|
145
|
-
return decoder_->seekToTime(seconds);
|
|
143
|
+
return decoder_->seekToTime(seconds).is_ok();
|
|
146
144
|
}
|
|
147
145
|
|
|
148
146
|
void AudioFileSourceNode::applyPlaybackStateAfterSuccessfulSeek(double seconds) {
|
|
@@ -81,7 +81,7 @@ class AudioFileSourceNode : public AudioScheduledSourceNode {
|
|
|
81
81
|
const std::shared_ptr<AudioFileDecoderState> &state);
|
|
82
82
|
|
|
83
83
|
std::shared_ptr<AudioFileDecoderState> decoderState_;
|
|
84
|
-
std::unique_ptr<decoding::
|
|
84
|
+
std::unique_ptr<decoding::IncrementalAudioDecoder> decoder_;
|
|
85
85
|
float volume_;
|
|
86
86
|
bool requiresFFmpeg_;
|
|
87
87
|
bool filePaused_{false};
|
|
@@ -159,8 +159,8 @@ void AudioScheduledSourceNode::disable() {
|
|
|
159
159
|
AudioNode::disable();
|
|
160
160
|
|
|
161
161
|
if (onEndedCallbackId_ != 0) {
|
|
162
|
-
audioEventHandlerRegistry_->
|
|
163
|
-
AudioEvent::ENDED, onEndedCallbackId_, {});
|
|
162
|
+
audioEventHandlerRegistry_->dispatchEvent(
|
|
163
|
+
AudioEvent::ENDED, onEndedCallbackId_, EmptyPayload{});
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
|
|
@@ -1,142 +1,171 @@
|
|
|
1
1
|
#include <audioapi/core/utils/AudioDecoder.h>
|
|
2
|
-
#include <audioapi/dsp/VectorMath.h>
|
|
3
2
|
#include <audioapi/libs/base64/base64.h>
|
|
4
|
-
#include <audioapi/
|
|
5
|
-
|
|
6
|
-
#include <audioapi/libs/miniaudio/decoders/libopus/miniaudio_libopus.h>
|
|
7
|
-
#include <audioapi/libs/miniaudio/decoders/libvorbis/miniaudio_libvorbis.h>
|
|
8
|
-
#include <audioapi/libs/miniaudio/miniaudio.h>
|
|
3
|
+
#include <audioapi/libs/decoding/IncrementalAudioDecoder.h>
|
|
4
|
+
#include <audioapi/libs/miniaudio/MiniAudioDecoding.h>
|
|
9
5
|
|
|
10
6
|
#if !RN_AUDIO_API_FFMPEG_DISABLED
|
|
11
7
|
#include <audioapi/libs/ffmpeg/FFmpegDecoding.h>
|
|
12
8
|
#endif // RN_AUDIO_API_FFMPEG_DISABLED
|
|
13
9
|
|
|
10
|
+
#include <algorithm>
|
|
11
|
+
#include <cctype>
|
|
12
|
+
#include <cstdint>
|
|
13
|
+
#include <cstring>
|
|
14
14
|
#include <memory>
|
|
15
15
|
#include <string>
|
|
16
16
|
#include <utility>
|
|
17
17
|
#include <vector>
|
|
18
18
|
|
|
19
|
-
namespace audioapi {
|
|
19
|
+
namespace audioapi::audiodecoder {
|
|
20
|
+
|
|
21
|
+
// Drains an incremental decoder into an AudioBuffer. Total frame count is not
|
|
22
|
+
// known up front for some formats (e.g. Vorbis), so we read in fixed-size
|
|
23
|
+
// chunks and grow the interleaved accumulator until the decoder reports EOF.
|
|
24
|
+
AudioBufferResult decodeAll(decoding::IncrementalAudioDecoder &decoder) {
|
|
25
|
+
const int channels = std::max(1, decoder.outputChannels());
|
|
26
|
+
const auto outputSampleRate = static_cast<float>(decoder.outputSampleRate());
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Result<std::vector<float>, std::string> AudioDecoder::readAllPcmFrames(
|
|
25
|
-
ma_decoder &decoder,
|
|
26
|
-
int outputChannels) {
|
|
27
|
-
std::vector<float> buffer;
|
|
28
|
-
std::vector<float> temp(CHUNK_SIZE * outputChannels);
|
|
29
|
-
ma_uint64 outFramesRead = 0;
|
|
28
|
+
std::vector<float> interleaved;
|
|
29
|
+
std::vector<float> chunk(
|
|
30
|
+
decoding::IncrementalAudioDecoder::CHUNK_SIZE * static_cast<size_t>(channels));
|
|
30
31
|
|
|
31
32
|
while (true) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (
|
|
33
|
+
const size_t framesRead =
|
|
34
|
+
decoder.readPcmFrames(chunk.data(), decoding::IncrementalAudioDecoder::CHUNK_SIZE);
|
|
35
|
+
if (framesRead == 0) {
|
|
35
36
|
break;
|
|
36
37
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
interleaved.insert(
|
|
39
|
+
interleaved.end(),
|
|
40
|
+
chunk.begin(),
|
|
41
|
+
chunk.begin() + static_cast<std::ptrdiff_t>(framesRead * static_cast<size_t>(channels)));
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
if (
|
|
44
|
+
if (interleaved.empty()) {
|
|
43
45
|
return Err("Failed to decode any frames");
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
const size_t outputFrames = interleaved.size() / static_cast<size_t>(channels);
|
|
49
|
+
auto audioBuffer = std::make_shared<AudioBuffer>(outputFrames, channels, outputSampleRate);
|
|
50
|
+
audioBuffer->deinterleaveFrom(interleaved.data(), outputFrames);
|
|
51
|
+
return Ok(std::move(audioBuffer));
|
|
47
52
|
}
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (buffer.empty()) {
|
|
54
|
-
return Err("Buffer is empty");
|
|
54
|
+
// NOLINTBEGIN(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers)
|
|
55
|
+
AudioFormat detectAudioFormat(const void *data, size_t size) {
|
|
56
|
+
if (size < 12) {
|
|
57
|
+
return AudioFormat::UNKNOWN;
|
|
55
58
|
}
|
|
59
|
+
const auto *bytes = static_cast<const unsigned char *>(data);
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return Ok(std::move(audioBuffer));
|
|
63
|
-
}
|
|
61
|
+
// WAV/RIFF
|
|
62
|
+
if (std::memcmp(bytes, "RIFF", 4) == 0 && std::memcmp(bytes + 8, "WAVE", 4) == 0) {
|
|
63
|
+
return AudioFormat::WAV;
|
|
64
|
+
}
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
ma_decoding_backend_vtable *customBackends[] = {
|
|
69
|
-
ma_decoding_backend_libvorbis, ma_decoding_backend_libopus};
|
|
70
|
-
|
|
71
|
-
config.ppCustomBackendVTables = customBackends;
|
|
72
|
-
config.customBackendCount = sizeof(customBackends) / sizeof(customBackends[0]);
|
|
73
|
-
|
|
74
|
-
ma_result initResult = std::visit(
|
|
75
|
-
[&config, &decoder](auto &&arg) -> ma_result {
|
|
76
|
-
using T = std::decay_t<decltype(arg)>;
|
|
77
|
-
if constexpr (std::is_same_v<T, MemorySource>) {
|
|
78
|
-
return ma_decoder_init_memory(arg.data, arg.size, &config, &decoder);
|
|
79
|
-
} else if constexpr (std::is_same_v<T, std::string>) {
|
|
80
|
-
return ma_decoder_init_file(arg.c_str(), &config, &decoder);
|
|
81
|
-
} else {
|
|
82
|
-
return MA_INVALID_ARGS;
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
source);
|
|
86
|
-
|
|
87
|
-
if (initResult != MA_SUCCESS) {
|
|
88
|
-
return Err(
|
|
89
|
-
"Failed to initialize miniaudio decoder: " +
|
|
90
|
-
std::string(ma_result_description(initResult)));
|
|
66
|
+
// OGG
|
|
67
|
+
if (std::memcmp(bytes, "OggS", 4) == 0) {
|
|
68
|
+
return AudioFormat::OGG;
|
|
91
69
|
}
|
|
92
70
|
|
|
93
|
-
|
|
94
|
-
|
|
71
|
+
// FLAC
|
|
72
|
+
if (std::memcmp(bytes, "fLaC", 4) == 0) {
|
|
73
|
+
return AudioFormat::FLAC;
|
|
74
|
+
}
|
|
95
75
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
});
|
|
76
|
+
// AAC starts with 0xFF 0xF1 or 0xFF 0xF9
|
|
77
|
+
if (bytes[0] == 0xFF && (bytes[1] & 0xF6) == 0xF0) {
|
|
78
|
+
return AudioFormat::AAC;
|
|
79
|
+
}
|
|
101
80
|
|
|
102
|
-
|
|
81
|
+
// MP3: "ID3" or 11-bit frame sync (0xFF 0xE0)
|
|
82
|
+
if (std::memcmp(bytes, "ID3", 3) == 0) {
|
|
83
|
+
return AudioFormat::MP3;
|
|
84
|
+
}
|
|
85
|
+
if (bytes[0] == 0xFF && (bytes[1] & 0xE0) == 0xE0) {
|
|
86
|
+
return AudioFormat::MP3;
|
|
87
|
+
}
|
|
103
88
|
|
|
104
|
-
|
|
89
|
+
if (std::memcmp(bytes + 4, "ftyp", 4) == 0) {
|
|
90
|
+
if (std::memcmp(bytes + 8, "M4A ", 4) == 0) {
|
|
91
|
+
return AudioFormat::M4A;
|
|
92
|
+
}
|
|
93
|
+
if (std::memcmp(bytes + 8, "qt ", 4) == 0) {
|
|
94
|
+
return AudioFormat::MOV;
|
|
95
|
+
}
|
|
96
|
+
return AudioFormat::MP4;
|
|
97
|
+
}
|
|
98
|
+
return AudioFormat::UNKNOWN;
|
|
105
99
|
}
|
|
100
|
+
// NOLINTEND(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers)
|
|
101
|
+
|
|
102
|
+
bool pathHasExtension(const std::string &path, const std::vector<std::string> &extensions) {
|
|
103
|
+
std::string pathLower = path;
|
|
104
|
+
std::ranges::transform(pathLower, pathLower.begin(), [](unsigned char c) {
|
|
105
|
+
return static_cast<char>(std::tolower(c));
|
|
106
|
+
});
|
|
107
|
+
return std::ranges::any_of(
|
|
108
|
+
extensions, [&pathLower](const std::string &ext) { return pathLower.ends_with(ext); });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
AudioBufferResult decodeWithFilePath(const std::string &path, float sampleRate) {
|
|
112
|
+
const int sr = static_cast<int>(sampleRate);
|
|
106
113
|
|
|
107
|
-
|
|
108
|
-
if (AudioDecoder::pathHasExtension(path, {".mp4", ".m4a", ".aac"})) {
|
|
114
|
+
if (needsFFmpegByPath(path)) {
|
|
109
115
|
#if !RN_AUDIO_API_FFMPEG_DISABLED
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
116
|
+
ffmpegdecoder::FFmpegDecoder decoder;
|
|
117
|
+
const auto openResult = decoder.openFile(sr, path);
|
|
118
|
+
if (openResult.is_err()) {
|
|
119
|
+
return Err("Failed to open file with FFmpeg decoder: " + openResult.unwrap_err());
|
|
113
120
|
}
|
|
114
|
-
|
|
121
|
+
auto result = decodeAll(decoder);
|
|
122
|
+
decoder.close();
|
|
123
|
+
return result;
|
|
115
124
|
#else
|
|
116
125
|
return Err("FFmpeg is disabled, cannot decode with file path");
|
|
117
126
|
#endif // RN_AUDIO_API_FFMPEG_DISABLED
|
|
118
127
|
}
|
|
119
|
-
|
|
128
|
+
|
|
129
|
+
miniaudio_decoder::MiniAudioDecoder decoder;
|
|
130
|
+
const auto openResult = decoder.openFile(sr, path);
|
|
131
|
+
if (openResult.is_err()) {
|
|
132
|
+
return Err("Failed to open file with miniaudio decoder: " + openResult.unwrap_err());
|
|
133
|
+
}
|
|
134
|
+
auto result = decodeAll(decoder);
|
|
135
|
+
decoder.close();
|
|
136
|
+
return result;
|
|
120
137
|
}
|
|
121
138
|
|
|
122
|
-
AudioBufferResult
|
|
123
|
-
|
|
124
|
-
const AudioFormat format =
|
|
125
|
-
|
|
139
|
+
AudioBufferResult decodeWithMemoryBlock(const void *data, size_t size, float sampleRate) {
|
|
140
|
+
const int sr = static_cast<int>(sampleRate);
|
|
141
|
+
const AudioFormat format = detectAudioFormat(data, size);
|
|
142
|
+
|
|
143
|
+
if (needsFFmpeg(format)) {
|
|
126
144
|
#if !RN_AUDIO_API_FFMPEG_DISABLED
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
145
|
+
ffmpegdecoder::FFmpegDecoder decoder;
|
|
146
|
+
const auto openResult = decoder.openMemory(sr, data, size);
|
|
147
|
+
if (openResult.is_err()) {
|
|
148
|
+
return Err("Failed to open memory block with FFmpeg decoder: " + openResult.unwrap_err());
|
|
130
149
|
}
|
|
131
|
-
|
|
150
|
+
auto result = decodeAll(decoder);
|
|
151
|
+
decoder.close();
|
|
152
|
+
return result;
|
|
132
153
|
#else
|
|
133
154
|
return Err("FFmpeg is disabled, cannot decode memory block");
|
|
134
155
|
#endif // RN_AUDIO_API_FFMPEG_DISABLED
|
|
135
156
|
}
|
|
136
|
-
|
|
157
|
+
|
|
158
|
+
miniaudio_decoder::MiniAudioDecoder decoder;
|
|
159
|
+
const auto openResult = decoder.openMemory(sr, data, size);
|
|
160
|
+
if (openResult.is_err()) {
|
|
161
|
+
return Err("Failed to open memory block with miniaudio decoder: " + openResult.unwrap_err());
|
|
162
|
+
}
|
|
163
|
+
auto result = decodeAll(decoder);
|
|
164
|
+
decoder.close();
|
|
165
|
+
return result;
|
|
137
166
|
}
|
|
138
167
|
|
|
139
|
-
AudioBufferResult
|
|
168
|
+
AudioBufferResult decodeWithPCMInBase64(
|
|
140
169
|
const std::string &data,
|
|
141
170
|
float inputSampleRate,
|
|
142
171
|
int inputChannelCount,
|
|
@@ -148,7 +177,7 @@ AudioBufferResult AudioDecoder::decodeWithPCMInBase64(
|
|
|
148
177
|
auto audioBuffer =
|
|
149
178
|
std::make_shared<AudioBuffer>(numFramesDecoded, inputChannelCount, inputSampleRate);
|
|
150
179
|
|
|
151
|
-
for (
|
|
180
|
+
for (int ch = 0; ch < inputChannelCount; ++ch) {
|
|
152
181
|
auto channelData = audioBuffer->getChannel(ch)->span();
|
|
153
182
|
|
|
154
183
|
for (size_t i = 0; i < numFramesDecoded; ++i) {
|
|
@@ -168,4 +197,4 @@ AudioBufferResult AudioDecoder::decodeWithPCMInBase64(
|
|
|
168
197
|
return Ok(std::move(audioBuffer));
|
|
169
198
|
}
|
|
170
199
|
|
|
171
|
-
} // namespace audioapi
|
|
200
|
+
} // namespace audioapi::audiodecoder
|
|
@@ -1,119 +1,42 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#include <audioapi/core/types/AudioFormat.h>
|
|
4
|
-
#include <audioapi/libs/miniaudio/miniaudio.h>
|
|
5
4
|
#include <audioapi/utils/AudioBuffer.hpp>
|
|
6
5
|
#include <audioapi/utils/Result.hpp>
|
|
7
|
-
#include <
|
|
8
|
-
#include <cstring>
|
|
6
|
+
#include <cstddef>
|
|
9
7
|
#include <memory>
|
|
10
8
|
#include <string>
|
|
11
|
-
#include <variant>
|
|
12
9
|
#include <vector>
|
|
13
10
|
|
|
14
|
-
namespace audioapi {
|
|
11
|
+
namespace audioapi::audiodecoder {
|
|
15
12
|
|
|
16
13
|
using AudioBufferResult = Result<std::shared_ptr<AudioBuffer>, std::string>;
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
[[nodiscard]] AudioBufferResult decodeWithFilePath(const std::string &path, float sampleRate);
|
|
16
|
+
[[nodiscard]] AudioBufferResult
|
|
17
|
+
decodeWithMemoryBlock(const void *data, size_t size, float sampleRate);
|
|
18
|
+
[[nodiscard]] AudioBufferResult decodeWithPCMInBase64(
|
|
19
|
+
const std::string &data,
|
|
20
|
+
float inputSampleRate,
|
|
21
|
+
int inputChannelCount,
|
|
22
|
+
bool interleaved);
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
[[nodiscard]] AudioFormat detectAudioFormat(const void *data, size_t size);
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
[[nodiscard]] bool pathHasExtension(
|
|
27
|
+
const std::string &path,
|
|
28
|
+
const std::vector<std::string> &extensions);
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
[[nodiscard]] inline bool needsFFmpeg(AudioFormat format) {
|
|
31
|
+
return format == AudioFormat::MP4 || format == AudioFormat::M4A || format == AudioFormat::AAC;
|
|
32
|
+
}
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
[[nodiscard]] static AudioBufferResult
|
|
35
|
-
decodeWithMemoryBlock(const void *data, size_t size, float sampleRate);
|
|
36
|
-
[[nodiscard]] static AudioBufferResult decodeWithPCMInBase64(
|
|
37
|
-
const std::string &data,
|
|
38
|
-
float inputSampleRate,
|
|
39
|
-
int inputChannelCount,
|
|
40
|
-
bool interleaved);
|
|
34
|
+
[[nodiscard]] inline bool needsFFmpegByPath(const std::string &path) {
|
|
35
|
+
return pathHasExtension(path, {".mp4", ".m4a", ".aac"});
|
|
36
|
+
}
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return AudioFormat::UNKNOWN;
|
|
46
|
-
}
|
|
47
|
-
const auto *bytes = static_cast<const unsigned char *>(data);
|
|
38
|
+
[[nodiscard]] inline float uint8ToFloat(uint8_t byte1, uint8_t byte2) {
|
|
39
|
+
return static_cast<float>(static_cast<int16_t>((byte2 << CHAR_BIT) | byte1)) / INT16_MAX;
|
|
40
|
+
}
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
if (std::memcmp(bytes, "RIFF", 4) == 0 && std::memcmp(bytes + 8, "WAVE", 4) == 0) {
|
|
51
|
-
return AudioFormat::WAV;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// OGG
|
|
55
|
-
if (std::memcmp(bytes, "OggS", 4) == 0) {
|
|
56
|
-
return AudioFormat::OGG;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// FLAC
|
|
60
|
-
if (std::memcmp(bytes, "fLaC", 4) == 0) {
|
|
61
|
-
return AudioFormat::FLAC;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// AAC starts with 0xFF 0xF1 or 0xFF 0xF9
|
|
65
|
-
if (bytes[0] == 0xFF && (bytes[1] & 0xF6) == 0xF0) {
|
|
66
|
-
return AudioFormat::AAC;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// MP3: "ID3" or 11-bit frame sync (0xFF 0xE0)
|
|
70
|
-
if (std::memcmp(bytes, "ID3", 3) == 0) {
|
|
71
|
-
return AudioFormat::MP3;
|
|
72
|
-
}
|
|
73
|
-
if (bytes[0] == 0xFF && (bytes[1] & 0xE0) == 0xE0) {
|
|
74
|
-
return AudioFormat::MP3;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (std::memcmp(bytes + 4, "ftyp", 4) == 0) {
|
|
78
|
-
if (std::memcmp(bytes + 8, "M4A ", 4) == 0) {
|
|
79
|
-
return AudioFormat::M4A;
|
|
80
|
-
}
|
|
81
|
-
if (std::memcmp(bytes + 8, "qt ", 4) == 0) {
|
|
82
|
-
return AudioFormat::MOV;
|
|
83
|
-
}
|
|
84
|
-
return AudioFormat::MP4;
|
|
85
|
-
}
|
|
86
|
-
return AudioFormat::UNKNOWN;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// NOLINTEND(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers)
|
|
90
|
-
static bool pathHasExtension(
|
|
91
|
-
const std::string &path,
|
|
92
|
-
const std::vector<std::string> &extensions) {
|
|
93
|
-
std::string pathLower = path;
|
|
94
|
-
std::ranges::transform(pathLower, pathLower.begin(), ::tolower);
|
|
95
|
-
return std::ranges::any_of(
|
|
96
|
-
extensions, [&pathLower](const std::string &ext) { return pathLower.ends_with(ext); });
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
private:
|
|
100
|
-
static AudioBufferResult decodeWithMiniaudio(float sampleRate, DecoderSource source);
|
|
101
|
-
static Result<std::vector<float>, std::string> readAllPcmFrames(
|
|
102
|
-
ma_decoder &decoder,
|
|
103
|
-
int outputChannels);
|
|
104
|
-
static AudioBufferResult makeAudioBufferFromFloatBuffer(
|
|
105
|
-
const std::vector<float> &buffer,
|
|
106
|
-
float outputSampleRate,
|
|
107
|
-
int outputChannels);
|
|
108
|
-
[[nodiscard]] static int16_t floatToInt16(float sample) {
|
|
109
|
-
return static_cast<int16_t>(sample * INT16_MAX);
|
|
110
|
-
}
|
|
111
|
-
[[nodiscard]] static float int16ToFloat(int16_t sample) {
|
|
112
|
-
return static_cast<float>(sample) / INT16_MAX;
|
|
113
|
-
}
|
|
114
|
-
[[nodiscard]] static float uint8ToFloat(uint8_t byte1, uint8_t byte2) {
|
|
115
|
-
return static_cast<float>(static_cast<int16_t>((byte2 << CHAR_BIT) | byte1)) / INT16_MAX;
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
} // namespace audioapi
|
|
42
|
+
} // namespace audioapi::audiodecoder
|