react-native-audio-api 0.9.0-nightly-7ecb495-20251008 → 0.9.1

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.
Files changed (106) hide show
  1. package/android/src/main/cpp/audioapi/android/core/{utils/AudioDecoder.cpp → AudioDecoder.cpp} +75 -79
  2. package/android/src/main/jniLibs/arm64-v8a/libavcodec.so +0 -0
  3. package/android/src/main/jniLibs/arm64-v8a/libavformat.so +0 -0
  4. package/android/src/main/jniLibs/arm64-v8a/libavutil.so +0 -0
  5. package/android/src/main/jniLibs/arm64-v8a/libswresample.so +0 -0
  6. package/android/src/main/jniLibs/armeabi-v7a/libavcodec.so +0 -0
  7. package/android/src/main/jniLibs/armeabi-v7a/libavformat.so +0 -0
  8. package/android/src/main/jniLibs/armeabi-v7a/libavutil.so +0 -0
  9. package/android/src/main/jniLibs/armeabi-v7a/libswresample.so +0 -0
  10. package/android/src/main/jniLibs/x86/libavcodec.so +0 -0
  11. package/android/src/main/jniLibs/x86/libavformat.so +0 -0
  12. package/android/src/main/jniLibs/x86/libavutil.so +0 -0
  13. package/android/src/main/jniLibs/x86/libswresample.so +0 -0
  14. package/android/src/main/jniLibs/x86_64/libavcodec.so +0 -0
  15. package/android/src/main/jniLibs/x86_64/libavformat.so +0 -0
  16. package/android/src/main/jniLibs/x86_64/libavutil.so +0 -0
  17. package/android/src/main/jniLibs/x86_64/libswresample.so +0 -0
  18. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +43 -124
  19. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +101 -1
  20. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +3 -0
  21. package/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.cpp +3 -8
  22. package/common/cpp/audioapi/core/AudioContext.cpp +2 -0
  23. package/common/cpp/audioapi/core/BaseAudioContext.cpp +35 -0
  24. package/common/cpp/audioapi/core/BaseAudioContext.h +12 -4
  25. package/common/cpp/audioapi/core/OfflineAudioContext.cpp +2 -0
  26. package/common/cpp/audioapi/core/effects/WorkletNode.cpp +16 -28
  27. package/common/cpp/audioapi/core/effects/WorkletNode.h +2 -3
  28. package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +5 -6
  29. package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -0
  30. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +0 -4
  31. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +0 -1
  32. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +0 -2
  33. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +0 -4
  34. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +0 -1
  35. package/common/cpp/audioapi/core/sources/StreamerNode.cpp +16 -6
  36. package/common/cpp/audioapi/core/sources/StreamerNode.h +3 -1
  37. package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +2 -3
  38. package/common/cpp/audioapi/core/utils/AudioDecoder.h +91 -36
  39. package/common/cpp/audioapi/core/utils/Constants.h +0 -4
  40. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +5 -1
  41. package/common/cpp/audioapi/external/libavcodec.xcframework/ios-arm64/libavcodec.framework/libavcodec +0 -0
  42. package/common/cpp/audioapi/external/libavcodec.xcframework/ios-arm64_x86_64-simulator/libavcodec.framework/libavcodec +0 -0
  43. package/common/cpp/audioapi/external/libavformat.xcframework/Info.plist +5 -5
  44. package/common/cpp/audioapi/external/libavformat.xcframework/ios-arm64/libavformat.framework/libavformat +0 -0
  45. package/common/cpp/audioapi/external/libavformat.xcframework/ios-arm64_x86_64-simulator/libavformat.framework/libavformat +0 -0
  46. package/common/cpp/audioapi/external/libavutil.xcframework/ios-arm64/libavutil.framework/libavutil +0 -0
  47. package/common/cpp/audioapi/external/libavutil.xcframework/ios-arm64_x86_64-simulator/libavutil.framework/libavutil +0 -0
  48. package/common/cpp/audioapi/external/libswresample.xcframework/Info.plist +5 -5
  49. package/common/cpp/audioapi/external/libswresample.xcframework/ios-arm64/libswresample.framework/libswresample +0 -0
  50. package/common/cpp/audioapi/external/libswresample.xcframework/ios-arm64_x86_64-simulator/libswresample.framework/libswresample +0 -0
  51. package/common/cpp/audioapi/jsi/AudioArrayBuffer.cpp +2 -2
  52. package/common/cpp/audioapi/jsi/AudioArrayBuffer.h +10 -11
  53. package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +282 -241
  54. package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.h +19 -57
  55. package/common/cpp/audioapi/libs/ffmpeg/ffmpeg_setup.sh +1 -1
  56. package/common/cpp/audioapi/utils/AudioBus.cpp +4 -0
  57. package/common/cpp/audioapi/utils/AudioBus.h +1 -0
  58. package/common/cpp/test/CMakeLists.txt +8 -5
  59. package/common/cpp/test/RunTests.sh +2 -2
  60. package/common/cpp/test/{AudioParamTest.cpp → src/AudioParamTest.cpp} +1 -1
  61. package/common/cpp/test/src/ConstantSourceTest.cpp +64 -0
  62. package/common/cpp/test/{GainTest.cpp → src/GainTest.cpp} +11 -10
  63. package/common/cpp/test/{MockAudioEventHandlerRegistry.h → src/MockAudioEventHandlerRegistry.h} +4 -2
  64. package/common/cpp/test/{OscillatorTest.cpp → src/OscillatorTest.cpp} +6 -4
  65. package/common/cpp/test/{StereoPannerTest.cpp → src/StereoPannerTest.cpp} +1 -1
  66. package/ios/audioapi/ios/core/AudioDecoder.mm +156 -0
  67. package/lib/commonjs/api.js +1 -21
  68. package/lib/commonjs/api.js.map +1 -1
  69. package/lib/commonjs/core/BaseAudioContext.js +18 -11
  70. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  71. package/lib/module/api.js +1 -3
  72. package/lib/module/api.js.map +1 -1
  73. package/lib/module/core/BaseAudioContext.js +18 -11
  74. package/lib/module/core/BaseAudioContext.js.map +1 -1
  75. package/lib/typescript/api.d.ts +1 -5
  76. package/lib/typescript/api.d.ts.map +1 -1
  77. package/lib/typescript/core/BaseAudioContext.d.ts +6 -3
  78. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  79. package/lib/typescript/interfaces.d.ts +3 -10
  80. package/lib/typescript/interfaces.d.ts.map +1 -1
  81. package/package.json +1 -1
  82. package/src/api.ts +0 -10
  83. package/src/core/BaseAudioContext.ts +29 -26
  84. package/src/interfaces.ts +6 -26
  85. package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +0 -133
  86. package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.h +0 -28
  87. package/common/cpp/audioapi/HostObjects/utils/AudioStretcherHostObject.cpp +0 -58
  88. package/common/cpp/audioapi/HostObjects/utils/AudioStretcherHostObject.h +0 -26
  89. package/common/cpp/audioapi/core/types/AudioFormat.h +0 -16
  90. package/common/cpp/audioapi/core/utils/AudioStretcher.cpp +0 -75
  91. package/common/cpp/audioapi/core/utils/AudioStretcher.h +0 -30
  92. package/ios/audioapi/ios/core/utils/AudioDecoder.mm +0 -160
  93. package/lib/commonjs/core/AudioDecoder.js +0 -48
  94. package/lib/commonjs/core/AudioDecoder.js.map +0 -1
  95. package/lib/commonjs/core/AudioStretcher.js +0 -31
  96. package/lib/commonjs/core/AudioStretcher.js.map +0 -1
  97. package/lib/module/core/AudioDecoder.js +0 -42
  98. package/lib/module/core/AudioDecoder.js.map +0 -1
  99. package/lib/module/core/AudioStretcher.js +0 -26
  100. package/lib/module/core/AudioStretcher.js.map +0 -1
  101. package/lib/typescript/core/AudioDecoder.d.ts +0 -4
  102. package/lib/typescript/core/AudioDecoder.d.ts.map +0 -1
  103. package/lib/typescript/core/AudioStretcher.d.ts +0 -3
  104. package/lib/typescript/core/AudioStretcher.d.ts.map +0 -1
  105. package/src/core/AudioDecoder.ts +0 -78
  106. package/src/core/AudioStretcher.ts +0 -43
@@ -1,6 +1,7 @@
1
1
  #include <audioapi/HostObjects/sources/AudioBufferHostObject.h>
2
2
 
3
3
  #include <audioapi/jsi/AudioArrayBuffer.h>
4
+ #include <audioapi/utils/AudioBus.h>
4
5
 
5
6
  namespace audioapi {
6
7
 
@@ -42,14 +43,8 @@ JSI_PROPERTY_GETTER_IMPL(AudioBufferHostObject, numberOfChannels) {
42
43
 
43
44
  JSI_HOST_FUNCTION_IMPL(AudioBufferHostObject, getChannelData) {
44
45
  auto channel = static_cast<int>(args[0].getNumber());
45
- auto channelData =
46
- reinterpret_cast<uint8_t *>(audioBuffer_->getChannelData(channel));
47
- auto length = static_cast<int>(audioBuffer_->getLength());
48
- auto size = static_cast<int>(length * sizeof(float));
49
-
50
- // reading or writing from this ArrayBuffer could cause a crash
51
- // if underlying channelData is deallocated
52
- auto audioArrayBuffer = std::make_shared<AudioArrayBuffer>(channelData, size);
46
+ auto audioArrayBuffer = std::make_shared<AudioArrayBuffer>(
47
+ audioBuffer_->bus_->getSharedChannel(channel));
53
48
  auto arrayBuffer = jsi::ArrayBuffer(runtime, audioArrayBuffer);
54
49
 
55
50
  auto float32ArrayCtor =
@@ -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
  }
@@ -3,14 +3,15 @@
3
3
  #include <audioapi/core/types/ContextState.h>
4
4
  #include <audioapi/core/types/OscillatorType.h>
5
5
  #include <audioapi/core/utils/worklets/SafeIncludes.h>
6
- #include <cassert>
7
- #include <complex>
8
- #include <cstddef>
6
+
9
7
  #include <functional>
10
8
  #include <memory>
11
9
  #include <string>
12
10
  #include <utility>
13
11
  #include <vector>
12
+ #include <complex>
13
+ #include <cstddef>
14
+ #include <cassert>
14
15
 
15
16
  namespace audioapi {
16
17
 
@@ -26,6 +27,7 @@ class BiquadFilterNode;
26
27
  class AudioDestinationNode;
27
28
  class AudioBufferSourceNode;
28
29
  class AudioBufferQueueSourceNode;
30
+ class AudioDecoder;
29
31
  class AnalyserNode;
30
32
  class AudioEventHandlerRegistry;
31
33
  class IAudioEventHandlerRegistry;
@@ -66,6 +68,10 @@ class BaseAudioContext {
66
68
  int length);
67
69
  std::shared_ptr<AnalyserNode> createAnalyser();
68
70
 
71
+ std::shared_ptr<AudioBuffer> decodeAudioDataSource(const std::string &path);
72
+ std::shared_ptr<AudioBuffer> decodeAudioData(const void *data, size_t size);
73
+ std::shared_ptr<AudioBuffer> decodeWithPCMInBase64(const std::string &data, float playbackSpeed);
74
+
69
75
  std::shared_ptr<PeriodicWave> getBasicWaveForm(OscillatorType type);
70
76
  [[nodiscard]] float getNyquistFrequency() const;
71
77
  AudioNodeManager *getNodeManager();
@@ -79,7 +85,9 @@ class BaseAudioContext {
79
85
 
80
86
  std::shared_ptr<AudioDestinationNode> destination_;
81
87
  // init in AudioContext or OfflineContext constructor
82
- float sampleRate_{};
88
+ std::shared_ptr<AudioDecoder> audioDecoder_ {};
89
+ // init in AudioContext or OfflineContext constructor
90
+ float sampleRate_ {};
83
91
  ContextState state_ = ContextState::RUNNING;
84
92
  std::shared_ptr<AudioNodeManager> nodeManager_;
85
93
 
@@ -3,6 +3,7 @@
3
3
  #include <audioapi/core/AudioContext.h>
4
4
  #include <audioapi/core/destinations/AudioDestinationNode.h>
5
5
  #include <audioapi/core/sources/AudioBuffer.h>
6
+ #include <audioapi/core/utils/AudioDecoder.h>
6
7
  #include <audioapi/core/utils/AudioNodeManager.h>
7
8
  #include <audioapi/core/utils/Constants.h>
8
9
  #include <audioapi/core/utils/Locker.h>
@@ -29,6 +30,7 @@ OfflineAudioContext::OfflineAudioContext(
29
30
  numberOfChannels_(numberOfChannels),
30
31
  currentSampleFrame_(0) {
31
32
  sampleRate_ = sampleRate;
33
+ audioDecoder_ = std::make_shared<AudioDecoder>(sampleRate_);
32
34
  resultBus_ = std::make_shared<AudioBus>(
33
35
  static_cast<int>(length_), numberOfChannels_, sampleRate_);
34
36
  }
@@ -9,25 +9,16 @@ WorkletNode::WorkletNode(
9
9
  size_t bufferLength,
10
10
  size_t inputChannelCount)
11
11
  : AudioNode(context),
12
- buffRealLength_(bufferLength * sizeof(float)),
13
- bufferLength_(bufferLength),
14
12
  workletRunner_(runtime),
15
13
  shareableWorklet_(worklet),
14
+ bufferLength_(bufferLength),
16
15
  inputChannelCount_(inputChannelCount),
17
16
  curBuffIndex_(0) {
18
- buffs_.reserve(inputChannelCount_);
19
- for (size_t i = 0; i < inputChannelCount_; ++i) {
20
- buffs_.emplace_back(new uint8_t[buffRealLength_]);
21
- }
17
+ bus_ = std::make_shared<AudioBus>(
18
+ bufferLength, inputChannelCount, context->getSampleRate());
22
19
  isInitialized_ = true;
23
20
  }
24
21
 
25
- WorkletNode::~WorkletNode() {
26
- for (auto &buff : buffs_) {
27
- delete[] buff;
28
- }
29
- }
30
-
31
22
  std::shared_ptr<AudioBus> WorkletNode::processNode(
32
23
  const std::shared_ptr<AudioBus> &processingBus,
33
24
  int framesToProcess) {
@@ -40,17 +31,11 @@ std::shared_ptr<AudioBus> WorkletNode::processNode(
40
31
  size_t needsToProcess = framesToProcess - processed;
41
32
  size_t shouldProcess = std::min(framesToWorkletInvoke, needsToProcess);
42
33
 
43
- for (size_t ch = 0; ch < channelCount_; ch++) {
44
- /// here we copy
45
- /// to uint8_t* [curBuffIndex_, curBuffIndex_ + shouldProcess]
46
- /// from float* [processed, processed + shouldProcess]
47
- /// so as the we need to copy shouldProcess * sizeof(float) bytes
48
- auto channelData = processingBus->getChannel(ch)->getData();
49
- std::memcpy(
50
- /* dest */ buffs_[ch] + curBuffIndex_ * sizeof(float),
51
- /* src */ reinterpret_cast<const uint8_t *>(channelData + processed),
52
- /* size */ shouldProcess * sizeof(float));
53
- }
34
+ /// here we copy
35
+ /// to [curBuffIndex_, curBuffIndex_ + shouldProcess]
36
+ /// from [processed, processed + shouldProcess]
37
+ bus_->copy(processingBus.get(), processed, curBuffIndex_, shouldProcess);
38
+
54
39
  processed += shouldProcess;
55
40
  curBuffIndex_ += shouldProcess;
56
41
 
@@ -63,16 +48,19 @@ std::shared_ptr<AudioBus> WorkletNode::processNode(
63
48
  /// Arguments preparation
64
49
  auto jsArray = jsi::Array(uiRuntimeRaw, channelCount_);
65
50
  for (size_t ch = 0; ch < channelCount_; ch++) {
66
- uint8_t *buffPtr = buffs_[ch];
67
- buffs_[ch] = new uint8_t[buffRealLength_];
51
+ auto audioArray = std::make_shared<AudioArray>(bufferLength_);
52
+ audioArray->copy(bus_->getChannel(ch));
68
53
  auto sharedAudioArray =
69
- std::make_shared<AudioArrayBuffer>(buffPtr, buffRealLength_);
54
+ std::make_shared<AudioArrayBuffer>(audioArray);
55
+ auto sharedAudioArraySize = sharedAudioArray->size();
70
56
  auto arrayBuffer =
71
57
  jsi::ArrayBuffer(uiRuntimeRaw, std::move(sharedAudioArray));
58
+ arrayBuffer.setExternalMemoryPressure(
59
+ uiRuntimeRaw, sharedAudioArraySize);
72
60
  jsArray.setValueAtIndex(uiRuntimeRaw, ch, std::move(arrayBuffer));
73
61
  }
74
- jsArray.setExternalMemoryPressure(
75
- uiRuntimeRaw, channelCount_ * buffRealLength_);
62
+
63
+ bus_->zero();
76
64
 
77
65
  workletRunner_.executeWorklet(
78
66
  shareableWorklet_,
@@ -42,7 +42,7 @@ class WorkletNode : public AudioNode {
42
42
  size_t inputChannelCount
43
43
  );
44
44
 
45
- ~WorkletNode() override;
45
+ ~WorkletNode() override = default;
46
46
 
47
47
  protected:
48
48
  std::shared_ptr<AudioBus> processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
@@ -51,10 +51,9 @@ class WorkletNode : public AudioNode {
51
51
  private:
52
52
  WorkletsRunner workletRunner_;
53
53
  std::shared_ptr<worklets::SerializableWorklet> shareableWorklet_;
54
- std::vector<uint8_t*> buffs_;
54
+ std::shared_ptr<AudioBus> bus_;
55
55
 
56
56
  /// @brief Length of the byte buffer that will be passed to the AudioArrayBuffer
57
- size_t buffRealLength_;
58
57
  size_t bufferLength_;
59
58
  size_t inputChannelCount_;
60
59
  size_t curBuffIndex_;
@@ -16,13 +16,12 @@ WorkletProcessingNode::WorkletProcessingNode(
16
16
  outputBuffsHandles_.resize(maxChannelCount);
17
17
 
18
18
  for (size_t i = 0; i < maxChannelCount; ++i) {
19
- auto inputBuff = new uint8_t[RENDER_QUANTUM_SIZE * sizeof(float)];
20
- inputBuffsHandles_[i] = std::make_shared<AudioArrayBuffer>(
21
- inputBuff, RENDER_QUANTUM_SIZE * sizeof(float));
19
+ auto inputAudioArray = std::make_shared<AudioArray>(RENDER_QUANTUM_SIZE);
20
+ inputBuffsHandles_[i] = std::make_shared<AudioArrayBuffer>(inputAudioArray);
22
21
 
23
- auto outputBuff = new uint8_t[RENDER_QUANTUM_SIZE * sizeof(float)];
24
- outputBuffsHandles_[i] = std::make_shared<AudioArrayBuffer>(
25
- outputBuff, RENDER_QUANTUM_SIZE * sizeof(float));
22
+ auto outputAudioArray = std::make_shared<AudioArray>(RENDER_QUANTUM_SIZE);
23
+ outputBuffsHandles_[i] =
24
+ std::make_shared<AudioArrayBuffer>(outputAudioArray);
26
25
  }
27
26
  }
28
27
 
@@ -37,6 +37,7 @@ class AudioBuffer : public std::enable_shared_from_this<AudioBuffer> {
37
37
  private:
38
38
  friend class AudioBufferSourceNode;
39
39
  friend class AudioBufferQueueSourceNode;
40
+ friend class AudioBufferHostObject;
40
41
 
41
42
  std::shared_ptr<AudioBus> bus_;
42
43
  };
@@ -27,10 +27,6 @@ AudioBufferBaseSourceNode::AudioBufferBaseSourceNode(
27
27
  std::make_shared<signalsmith::stretch::SignalsmithStretch<float>>();
28
28
  }
29
29
 
30
- AudioBufferBaseSourceNode::~AudioBufferBaseSourceNode() {
31
- clearOnPositionChangedCallback();
32
- }
33
-
34
30
  std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getDetuneParam() const {
35
31
  return detuneParam_;
36
32
  }
@@ -15,7 +15,6 @@ class AudioParam;
15
15
  class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
16
16
  public:
17
17
  explicit AudioBufferBaseSourceNode(BaseAudioContext *context, bool pitchCorrection);
18
- ~AudioBufferBaseSourceNode() override;
19
18
 
20
19
  [[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
21
20
  [[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
@@ -29,8 +29,6 @@ AudioBufferSourceNode::~AudioBufferSourceNode() {
29
29
 
30
30
  buffer_.reset();
31
31
  alignedBus_.reset();
32
-
33
- clearOnLoopEndedCallback();
34
32
  }
35
33
 
36
34
  bool AudioBufferSourceNode::getLoop() const {
@@ -16,10 +16,6 @@ AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
16
16
  numberOfInputs_ = 0;
17
17
  }
18
18
 
19
- AudioScheduledSourceNode::~AudioScheduledSourceNode() {
20
- clearOnEndedCallback();
21
- }
22
-
23
19
  void AudioScheduledSourceNode::start(double when) {
24
20
  playbackState_ = PlaybackState::SCHEDULED;
25
21
  startTime_ = when;
@@ -27,7 +27,6 @@ class AudioScheduledSourceNode : public AudioNode {
27
27
  // FINISHED: The node has finished playing.
28
28
  enum class PlaybackState { UNSCHEDULED, SCHEDULED, PLAYING, STOP_SCHEDULED, FINISHED };
29
29
  explicit AudioScheduledSourceNode(BaseAudioContext *context);
30
- ~AudioScheduledSourceNode() override;
31
30
 
32
31
  void start(double when);
33
32
  virtual void stop(double when);
@@ -44,10 +44,14 @@ bool StreamerNode::initialize(const std::string &input_url) {
44
44
  }
45
45
 
46
46
  if (!openInput(input_url)) {
47
+ if (VERBOSE)
48
+ printf("Failed to open input\n");
47
49
  return false;
48
50
  }
49
51
 
50
52
  if (!findAudioStream() || !setupDecoder() || !setupResampler()) {
53
+ if (VERBOSE)
54
+ printf("Failed to find/setup audio stream\n");
51
55
  cleanup();
52
56
  return false;
53
57
  }
@@ -56,6 +60,8 @@ bool StreamerNode::initialize(const std::string &input_url) {
56
60
  frame_ = av_frame_alloc();
57
61
 
58
62
  if (pkt_ == nullptr || frame_ == nullptr) {
63
+ if (VERBOSE)
64
+ printf("Failed to allocate packet or frame\n");
59
65
  cleanup();
60
66
  return false;
61
67
  }
@@ -119,29 +125,24 @@ void StreamerNode::streamAudio() {
119
125
  while (streamFlag.load()) {
120
126
  if (pendingFrame_ != nullptr) {
121
127
  if (!processFrameWithResampler(pendingFrame_)) {
122
- cleanup();
123
128
  return;
124
129
  }
125
130
  } else {
126
131
  if (av_read_frame(fmtCtx_, pkt_) < 0) {
127
- cleanup();
128
132
  return;
129
133
  }
130
134
  if (pkt_->stream_index == audio_stream_index_) {
131
135
  if (avcodec_send_packet(codecCtx_, pkt_) != 0) {
132
- cleanup();
133
136
  return;
134
137
  }
135
138
  if (avcodec_receive_frame(codecCtx_, frame_) != 0) {
136
- cleanup();
137
139
  return;
138
140
  }
139
141
  if (!processFrameWithResampler(frame_)) {
140
- cleanup();
141
142
  return;
142
143
  }
143
- av_packet_unref(pkt_);
144
144
  }
145
+ av_packet_unref(pkt_);
145
146
  }
146
147
  std::this_thread::sleep_for(std::chrono::milliseconds(10));
147
148
  }
@@ -174,6 +175,13 @@ std::shared_ptr<AudioBus> StreamerNode::processNode(
174
175
  (maxBufferSize_ - offsetLength) * sizeof(float));
175
176
  }
176
177
  bufferedBusIndex_ -= offsetLength;
178
+ } else {
179
+ if (VERBOSE)
180
+ printf(
181
+ "Buffer underrun: have %zu, need %zu\n",
182
+ bufferedBusIndex_,
183
+ (size_t)framesToProcess);
184
+ processingBus->zero();
177
185
  }
178
186
 
179
187
  return processingBus;
@@ -273,6 +281,8 @@ bool StreamerNode::setupDecoder() {
273
281
 
274
282
  void StreamerNode::cleanup() {
275
283
  streamFlag.store(false);
284
+ // cleanup cannot be called from the streaming thread so there is no need to
285
+ // check if we are in the same thread
276
286
  streamingThread_.join();
277
287
  if (swrCtx_ != nullptr) {
278
288
  swr_free(&swrCtx_);
@@ -28,6 +28,8 @@ extern "C" {
28
28
  #include <string>
29
29
  #include <atomic>
30
30
 
31
+ static bool constexpr VERBOSE = false;
32
+
31
33
  namespace audioapi {
32
34
 
33
35
  class AudioBus;
@@ -94,7 +96,7 @@ class StreamerNode : public AudioScheduledSourceNode {
94
96
 
95
97
  /**
96
98
  * @brief Open the input stream
97
- * @param input_url The URL of the input stream
99
+ * @param inputUrl The URL of the input stream
98
100
  * @return true if successful, false otherwise
99
101
  * @note This function initializes the FFmpeg libraries and opens the input stream
100
102
  */
@@ -16,9 +16,8 @@ WorkletSourceNode::WorkletSourceNode(
16
16
  size_t outputChannelCount = this->getChannelCount();
17
17
  outputBuffsHandles_.resize(outputChannelCount);
18
18
  for (size_t i = 0; i < outputChannelCount; ++i) {
19
- auto buff = new uint8_t[RENDER_QUANTUM_SIZE * sizeof(float)];
20
- outputBuffsHandles_[i] = std::make_shared<AudioArrayBuffer>(
21
- buff, RENDER_QUANTUM_SIZE * sizeof(float));
19
+ auto audioArray = std::make_shared<AudioArray>(RENDER_QUANTUM_SIZE);
20
+ outputBuffsHandles_[i] = std::make_shared<AudioArrayBuffer>(audioArray);
22
21
  }
23
22
  }
24
23
 
@@ -1,67 +1,124 @@
1
1
  #pragma once
2
2
 
3
- #include <audioapi/core/types/AudioFormat.h>
3
+ #include <audioapi/libs/audio-stretch/stretch.h>
4
4
  #include <audioapi/libs/miniaudio/miniaudio.h>
5
- #include <algorithm>
6
- #include <cstring>
7
5
  #include <memory>
8
6
  #include <string>
9
7
  #include <vector>
8
+ #include <cstring>
9
+ #include <algorithm>
10
10
 
11
11
  namespace audioapi {
12
12
 
13
- class AudioBuffer;
13
+ enum class AudioFormat {
14
+ UNKNOWN,
15
+ WAV,
16
+ OGG,
17
+ FLAC,
18
+ AAC,
19
+ MP3,
20
+ M4A,
21
+ MP4,
22
+ MOV
23
+ };
24
+
25
+ class AudioBus;
14
26
 
15
27
  static constexpr int CHUNK_SIZE = 4096;
16
28
 
17
29
  class AudioDecoder {
18
30
  public:
19
- AudioDecoder() = delete;
31
+ explicit AudioDecoder(float sampleRate) : sampleRate_(sampleRate) {}
20
32
 
21
- [[nodiscard]] static std::shared_ptr<AudioBuffer> decodeWithFilePath(const std::string &path, float sampleRate);
22
- [[nodiscard]] static std::shared_ptr<AudioBuffer>
23
- decodeWithMemoryBlock(const void *data, size_t size, float sampleRate);
24
- [[nodiscard]] static std::shared_ptr<AudioBuffer>
25
- decodeWithPCMInBase64(const std::string &data, float inputSampleRate, int inputChannelCount, bool interleaved);
33
+ [[nodiscard]] std::shared_ptr<AudioBus> decodeWithFilePath(
34
+ const std::string &path) const;
35
+ [[nodiscard]] std::shared_ptr<AudioBus> decodeWithMemoryBlock(
36
+ const void *data,
37
+ size_t size) const;
38
+ [[nodiscard]] std::shared_ptr<AudioBus> decodeWithPCMInBase64(
39
+ const std::string &data,
40
+ float playbackSpeed) const;
26
41
 
27
42
  private:
28
- static std::vector<float> readAllPcmFrames(ma_decoder &decoder, int outputChannels);
29
- static std::shared_ptr<AudioBuffer>
30
- makeAudioBufferFromFloatBuffer(const std::vector<float> &buffer, float outputSampleRate, int outputChannels);
43
+ float sampleRate_;
44
+ int numChannels_ = 2;
45
+
46
+ static std::vector<int16_t> readAllPcmFrames(
47
+ ma_decoder &decoder,
48
+ int numChannels,
49
+ ma_uint64 &outFramesRead);
50
+ static std::shared_ptr<AudioBus> makeAudioBusFromInt16Buffer(
51
+ const std::vector<int16_t> &buffer,
52
+ int numChannels,
53
+ float sampleRate);
54
+
55
+ void changePlaybackSpeedIfNeeded(
56
+ std::vector<int16_t> &buffer,
57
+ size_t framesDecoded,
58
+ int numChannels,
59
+ float playbackSpeed) const {
60
+ if (playbackSpeed == 1.0f) {
61
+ return;
62
+ }
63
+
64
+ auto stretcher = stretch_init(
65
+ static_cast<int>(sampleRate_ / 333.0f),
66
+ static_cast<int>(sampleRate_ / 55.0f),
67
+ numChannels,
68
+ 0x1);
31
69
 
32
- static AudioFormat detectAudioFormat(const void *data, size_t size) {
33
- if (size < 12)
34
- return AudioFormat::UNKNOWN;
35
- const auto *bytes = static_cast<const unsigned char *>(data);
70
+ int maxOutputFrames = stretch_output_capacity(
71
+ stretcher, static_cast<int>(framesDecoded), 1 / playbackSpeed);
72
+ std::vector<int16_t> stretchedBuffer(maxOutputFrames);
73
+
74
+ int outputFrames = stretch_samples(
75
+ stretcher,
76
+ buffer.data(),
77
+ static_cast<int>(framesDecoded),
78
+ stretchedBuffer.data(),
79
+ 1 / playbackSpeed);
80
+
81
+ outputFrames +=
82
+ stretch_flush(stretcher, stretchedBuffer.data() + (outputFrames));
83
+ stretchedBuffer.resize(outputFrames);
84
+
85
+ buffer = stretchedBuffer;
86
+
87
+ stretch_deinit(stretcher);
88
+ }
89
+
90
+ static AudioFormat detectAudioFormat(const void* data, size_t size) {
91
+ if (size < 12) return AudioFormat::UNKNOWN;
92
+ const auto* bytes = static_cast<const unsigned char*>(data);
36
93
 
37
94
  // WAV/RIFF
38
95
  if (std::memcmp(bytes, "RIFF", 4) == 0 && std::memcmp(bytes + 8, "WAVE", 4) == 0)
39
- return AudioFormat::WAV;
96
+ return AudioFormat::WAV;
40
97
 
41
98
  // OGG
42
99
  if (std::memcmp(bytes, "OggS", 4) == 0)
43
- return AudioFormat::OGG;
100
+ return AudioFormat::OGG;
44
101
 
45
102
  // FLAC
46
103
  if (std::memcmp(bytes, "fLaC", 4) == 0)
47
- return AudioFormat::FLAC;
104
+ return AudioFormat::FLAC;
48
105
 
49
106
  // AAC starts with 0xFF 0xF1 or 0xFF 0xF9
50
107
  if (bytes[0] == 0xFF && (bytes[1] & 0xF6) == 0xF0)
51
- return AudioFormat::AAC;
108
+ return AudioFormat::AAC;
52
109
 
53
110
  // MP3: "ID3" or 11-bit frame sync (0xFF 0xE0)
54
111
  if (std::memcmp(bytes, "ID3", 3) == 0)
55
- return AudioFormat::MP3;
112
+ return AudioFormat::MP3;
56
113
  if (bytes[0] == 0xFF && (bytes[1] & 0xE0) == 0xE0)
57
- return AudioFormat::MP3;
114
+ return AudioFormat::MP3;
58
115
 
59
116
  if (std::memcmp(bytes + 4, "ftyp", 4) == 0) {
60
- if (std::memcmp(bytes + 8, "M4A ", 4) == 0)
61
- return AudioFormat::M4A;
62
- else if (std::memcmp(bytes + 8, "qt ", 4) == 0)
63
- return AudioFormat::MOV;
64
- return AudioFormat::MP4;
117
+ if (std::memcmp(bytes + 8, "M4A ", 4) == 0)
118
+ return AudioFormat::M4A;
119
+ else if (std::memcmp(bytes + 8, "qt ", 4) == 0)
120
+ return AudioFormat::MOV;
121
+ return AudioFormat::MP4;
65
122
  }
66
123
  return AudioFormat::UNKNOWN;
67
124
  }
@@ -69,21 +126,19 @@ class AudioDecoder {
69
126
  static inline bool pathHasExtension(const std::string &path, const std::vector<std::string> &extensions) {
70
127
  std::string pathLower = path;
71
128
  std::transform(pathLower.begin(), pathLower.end(), pathLower.begin(), ::tolower);
72
- for (const auto &ext : extensions) {
73
- if (pathLower.ends_with(ext))
74
- return true;
129
+ for (const auto& ext : extensions) {
130
+ if (pathLower.ends_with(ext))
131
+ return true;
75
132
  }
76
133
  return false;
77
134
  }
78
135
 
136
+
79
137
  [[nodiscard]] static inline int16_t floatToInt16(float sample) {
80
- return static_cast<int16_t>(sample * INT16_MAX);
138
+ return static_cast<int16_t>(sample * 32768.0f);
81
139
  }
82
140
  [[nodiscard]] static inline float int16ToFloat(int16_t sample) {
83
- return static_cast<float>(sample) / INT16_MAX;
84
- }
85
- [[nodiscard]] static inline float uint8ToFloat(uint8_t byte1, uint8_t byte2) {
86
- return static_cast<float>(static_cast<int16_t>((byte2 << 8) | byte1)) / INT16_MAX;
141
+ return static_cast<float>(sample) / 32768.0f;
87
142
  }
88
143
  };
89
144
 
@@ -10,10 +10,6 @@ namespace audioapi {
10
10
  static constexpr int RENDER_QUANTUM_SIZE = 128;
11
11
  static constexpr size_t MAX_FFT_SIZE = 32768;
12
12
 
13
- // stretcher
14
- static constexpr float UPPER_FREQUENCY_LIMIT_DETECTION = 333.0f;
15
- static constexpr float LOWER_FREQUENCY_LIMIT_DETECTION = 55.0f;
16
-
17
13
  // general
18
14
  static constexpr float MOST_POSITIVE_SINGLE_FLOAT = static_cast<float>(std::numeric_limits<float>::max());
19
15
  static constexpr float MOST_NEGATIVE_SINGLE_FLOAT = static_cast<float>(std::numeric_limits<float>::lowest());
@@ -156,8 +156,12 @@ void AudioEventHandlerRegistry::invokeHandlerWithEventBody(
156
156
 
157
157
  // In case of debugging this, please increment the hours spent counter
158
158
 
159
- // Hours spent on this: 5
159
+ // Hours spent on this: 8
160
160
  try {
161
+ if (!handlerIt->second || !handlerIt->second->isFunction(*runtime_)) {
162
+ // If the handler is not valid, we can skip it
163
+ return;
164
+ }
161
165
  jsi::Object eventObject(*runtime_);
162
166
  // handle special logic for microphone, because we pass audio buffer which
163
167
  // has significant size