react-native-audio-api 0.6.1-rc.1 → 0.6.1-rc.10

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 (159) hide show
  1. package/README.md +6 -11
  2. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +13 -8
  3. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +3 -2
  4. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +27 -10
  5. package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +12 -3
  6. package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +2 -2
  7. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionCallback.kt +4 -6
  8. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +1 -1
  9. package/android/src/main/res/drawable/skip_backward_10.xml +9 -0
  10. package/android/src/main/res/drawable/skip_forward_10.xml +9 -0
  11. package/android/src/oldarch/NativeAudioAPIModuleSpec.java +68 -64
  12. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +2 -1
  13. package/common/cpp/audioapi/HostObjects/AudioBufferQueueSourceNodeHostObject.h +94 -0
  14. package/common/cpp/audioapi/HostObjects/AudioContextHostObject.h +7 -7
  15. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +9 -0
  16. package/common/cpp/audioapi/core/AudioContext.cpp +29 -4
  17. package/common/cpp/audioapi/core/AudioContext.h +2 -1
  18. package/common/cpp/audioapi/core/BaseAudioContext.cpp +12 -0
  19. package/common/cpp/audioapi/core/BaseAudioContext.h +4 -3
  20. package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -0
  21. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +236 -0
  22. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +72 -0
  23. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +1 -1
  24. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +2 -2
  25. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +3 -4
  26. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +2 -1
  27. package/ios/audioapi/ios/AudioAPIModule.mm +23 -11
  28. package/ios/audioapi/ios/core/IOSAudioPlayer.h +3 -2
  29. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +21 -10
  30. package/ios/audioapi/ios/core/NativeAudioPlayer.h +4 -0
  31. package/ios/audioapi/ios/core/NativeAudioPlayer.m +15 -0
  32. package/ios/audioapi/ios/system/AudioEngine.h +1 -0
  33. package/ios/audioapi/ios/system/AudioEngine.mm +11 -1
  34. package/ios/audioapi/ios/system/AudioSessionManager.mm +1 -1
  35. package/ios/audioapi/ios/system/LockScreenManager.mm +13 -1
  36. package/ios/audioapi/ios/system/NotificationManager.mm +1 -1
  37. package/lib/commonjs/api.js +7 -0
  38. package/lib/commonjs/api.js.map +1 -1
  39. package/lib/commonjs/core/AudioBufferQueueSourceNode.js +46 -0
  40. package/lib/commonjs/core/AudioBufferQueueSourceNode.js.map +1 -0
  41. package/lib/commonjs/core/AudioContext.js +2 -2
  42. package/lib/commonjs/core/AudioContext.js.map +1 -1
  43. package/lib/commonjs/core/AudioNode.js +5 -1
  44. package/lib/commonjs/core/AudioNode.js.map +1 -1
  45. package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -1
  46. package/lib/commonjs/core/BaseAudioContext.js +4 -0
  47. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  48. package/lib/commonjs/hooks/useSytemVolume.js +1 -1
  49. package/lib/commonjs/hooks/useSytemVolume.js.map +1 -1
  50. package/lib/commonjs/plugin/withAudioAPI.js +15 -14
  51. package/lib/commonjs/plugin/withAudioAPI.js.map +1 -1
  52. package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
  53. package/lib/commonjs/system/AudioManager.js +12 -10
  54. package/lib/commonjs/system/AudioManager.js.map +1 -1
  55. package/lib/commonjs/web-core/AudioBufferSourceNode.js +4 -4
  56. package/lib/commonjs/web-core/AudioBufferSourceNode.js.map +1 -1
  57. package/lib/commonjs/web-core/AudioContext.js +5 -3
  58. package/lib/commonjs/web-core/AudioContext.js.map +1 -1
  59. package/lib/commonjs/web-core/AudioNode.js +8 -2
  60. package/lib/commonjs/web-core/AudioNode.js.map +1 -1
  61. package/lib/commonjs/web-core/AudioParam.js +2 -1
  62. package/lib/commonjs/web-core/AudioParam.js.map +1 -1
  63. package/lib/commonjs/web-core/BiquadFilterNode.js +4 -4
  64. package/lib/commonjs/web-core/BiquadFilterNode.js.map +1 -1
  65. package/lib/commonjs/web-core/GainNode.js +1 -1
  66. package/lib/commonjs/web-core/GainNode.js.map +1 -1
  67. package/lib/commonjs/web-core/OscillatorNode.js +2 -2
  68. package/lib/commonjs/web-core/OscillatorNode.js.map +1 -1
  69. package/lib/commonjs/web-core/StereoPannerNode.js +1 -1
  70. package/lib/commonjs/web-core/StereoPannerNode.js.map +1 -1
  71. package/lib/module/api.js +1 -0
  72. package/lib/module/api.js.map +1 -1
  73. package/lib/module/core/AudioBufferQueueSourceNode.js +40 -0
  74. package/lib/module/core/AudioBufferQueueSourceNode.js.map +1 -0
  75. package/lib/module/core/AudioContext.js +2 -2
  76. package/lib/module/core/AudioContext.js.map +1 -1
  77. package/lib/module/core/AudioNode.js +5 -1
  78. package/lib/module/core/AudioNode.js.map +1 -1
  79. package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
  80. package/lib/module/core/BaseAudioContext.js +4 -0
  81. package/lib/module/core/BaseAudioContext.js.map +1 -1
  82. package/lib/module/hooks/useSytemVolume.js +1 -1
  83. package/lib/module/hooks/useSytemVolume.js.map +1 -1
  84. package/lib/module/plugin/withAudioAPI.js +15 -14
  85. package/lib/module/plugin/withAudioAPI.js.map +1 -1
  86. package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
  87. package/lib/module/system/AudioManager.js +12 -10
  88. package/lib/module/system/AudioManager.js.map +1 -1
  89. package/lib/module/web-core/AudioBufferSourceNode.js +4 -4
  90. package/lib/module/web-core/AudioBufferSourceNode.js.map +1 -1
  91. package/lib/module/web-core/AudioContext.js +5 -3
  92. package/lib/module/web-core/AudioContext.js.map +1 -1
  93. package/lib/module/web-core/AudioNode.js +7 -2
  94. package/lib/module/web-core/AudioNode.js.map +1 -1
  95. package/lib/module/web-core/AudioParam.js +2 -1
  96. package/lib/module/web-core/AudioParam.js.map +1 -1
  97. package/lib/module/web-core/BiquadFilterNode.js +4 -4
  98. package/lib/module/web-core/BiquadFilterNode.js.map +1 -1
  99. package/lib/module/web-core/GainNode.js +1 -1
  100. package/lib/module/web-core/GainNode.js.map +1 -1
  101. package/lib/module/web-core/OscillatorNode.js +2 -2
  102. package/lib/module/web-core/OscillatorNode.js.map +1 -1
  103. package/lib/module/web-core/StereoPannerNode.js +1 -1
  104. package/lib/module/web-core/StereoPannerNode.js.map +1 -1
  105. package/lib/typescript/api.d.ts +2 -1
  106. package/lib/typescript/api.d.ts.map +1 -1
  107. package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts +16 -0
  108. package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts.map +1 -0
  109. package/lib/typescript/core/AudioContext.d.ts.map +1 -1
  110. package/lib/typescript/core/AudioNode.d.ts +1 -1
  111. package/lib/typescript/core/AudioNode.d.ts.map +1 -1
  112. package/lib/typescript/core/AudioScheduledSourceNode.d.ts +4 -3
  113. package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -1
  114. package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
  115. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  116. package/lib/typescript/events/types.d.ts +18 -9
  117. package/lib/typescript/events/types.d.ts.map +1 -1
  118. package/lib/typescript/hooks/useSytemVolume.d.ts.map +1 -1
  119. package/lib/typescript/interfaces.d.ts +9 -0
  120. package/lib/typescript/interfaces.d.ts.map +1 -1
  121. package/lib/typescript/plugin/withAudioAPI.d.ts +7 -6
  122. package/lib/typescript/plugin/withAudioAPI.d.ts.map +1 -1
  123. package/lib/typescript/specs/NativeAudioAPIModule.d.ts +3 -2
  124. package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
  125. package/lib/typescript/system/AudioManager.d.ts +6 -4
  126. package/lib/typescript/system/AudioManager.d.ts.map +1 -1
  127. package/lib/typescript/types.d.ts +2 -1
  128. package/lib/typescript/types.d.ts.map +1 -1
  129. package/lib/typescript/web-core/AudioBufferSourceNode.d.ts.map +1 -1
  130. package/lib/typescript/web-core/AudioContext.d.ts +1 -1
  131. package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
  132. package/lib/typescript/web-core/AudioNode.d.ts +2 -1
  133. package/lib/typescript/web-core/AudioNode.d.ts.map +1 -1
  134. package/lib/typescript/web-core/AudioParam.d.ts +4 -2
  135. package/lib/typescript/web-core/AudioParam.d.ts.map +1 -1
  136. package/package.json +2 -1
  137. package/src/api.ts +5 -1
  138. package/src/core/AudioBufferQueueSourceNode.ts +71 -0
  139. package/src/core/AudioContext.ts +7 -2
  140. package/src/core/AudioNode.ts +6 -2
  141. package/src/core/AudioScheduledSourceNode.ts +3 -3
  142. package/src/core/BaseAudioContext.ts +8 -0
  143. package/src/events/types.ts +29 -9
  144. package/src/hooks/useSytemVolume.ts +6 -3
  145. package/src/interfaces.ts +18 -0
  146. package/src/plugin/withAudioAPI.ts +36 -29
  147. package/src/specs/NativeAudioAPIModule.ts +14 -6
  148. package/src/system/AudioManager.ts +21 -16
  149. package/src/types.ts +2 -1
  150. package/src/web-core/AudioBufferSourceNode.tsx +9 -4
  151. package/src/web-core/AudioContext.tsx +7 -3
  152. package/src/web-core/AudioNode.tsx +10 -3
  153. package/src/web-core/AudioParam.tsx +5 -2
  154. package/src/web-core/BiquadFilterNode.tsx +4 -4
  155. package/src/web-core/GainNode.tsx +1 -1
  156. package/src/web-core/OscillatorNode.tsx +2 -2
  157. package/src/web-core/StereoPannerNode.tsx +1 -1
  158. package/android/src/main/res/drawable/skip_backward_5.xml +0 -9
  159. package/android/src/main/res/drawable/skip_forward_5.xml +0 -9
@@ -14,7 +14,7 @@ class IOSAudioPlayer;
14
14
 
15
15
  class AudioContext : public BaseAudioContext {
16
16
  public:
17
- explicit AudioContext(float sampleRate, const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry);
17
+ explicit AudioContext(float sampleRate, bool initSuspended, const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry);
18
18
  ~AudioContext() override;
19
19
 
20
20
  void close();
@@ -27,6 +27,7 @@ class AudioContext : public BaseAudioContext {
27
27
  #else
28
28
  std::shared_ptr<IOSAudioPlayer> audioPlayer_;
29
29
  #endif
30
+ bool playerHasBeenStarted_;
30
31
 
31
32
  std::function<void(std::shared_ptr<AudioBus>, int)> renderAudio();
32
33
  };
@@ -5,6 +5,7 @@
5
5
  #include <audioapi/core/effects/GainNode.h>
6
6
  #include <audioapi/core/effects/StereoPannerNode.h>
7
7
  #include <audioapi/core/sources/AudioBuffer.h>
8
+ #include <audioapi/core/sources/AudioBufferQueueSourceNode.h>
8
9
  #include <audioapi/core/sources/AudioBufferSourceNode.h>
9
10
  #include <audioapi/core/sources/OscillatorNode.h>
10
11
  #include <audioapi/core/utils/AudioDecoder.h>
@@ -79,6 +80,13 @@ std::shared_ptr<AudioBufferSourceNode> BaseAudioContext::createBufferSource(
79
80
  return bufferSource;
80
81
  }
81
82
 
83
+ std::shared_ptr<AudioBufferQueueSourceNode>
84
+ BaseAudioContext::createBufferQueueSource() {
85
+ auto bufferSource = std::make_shared<AudioBufferQueueSourceNode>(this);
86
+ nodeManager_->addSourceNode(bufferSource);
87
+ return bufferSource;
88
+ }
89
+
82
90
  std::shared_ptr<AudioBuffer> BaseAudioContext::createBuffer(
83
91
  int numberOfChannels,
84
92
  size_t length,
@@ -131,6 +139,10 @@ bool BaseAudioContext::isRunning() const {
131
139
  return state_ == ContextState::RUNNING;
132
140
  }
133
141
 
142
+ bool BaseAudioContext::isSuspended() const {
143
+ return state_ == ContextState::SUSPENDED;
144
+ }
145
+
134
146
  bool BaseAudioContext::isClosed() const {
135
147
  return state_ == ContextState::CLOSED;
136
148
  }
@@ -24,6 +24,7 @@ class AudioNodeManager;
24
24
  class BiquadFilterNode;
25
25
  class AudioDestinationNode;
26
26
  class AudioBufferSourceNode;
27
+ class AudioBufferQueueSourceNode;
27
28
  class AudioDecoder;
28
29
  class AnalyserNode;
29
30
  class AudioEventHandlerRegistry;
@@ -44,6 +45,7 @@ class BaseAudioContext {
44
45
  std::shared_ptr<StereoPannerNode> createStereoPanner();
45
46
  std::shared_ptr<BiquadFilterNode> createBiquadFilter();
46
47
  std::shared_ptr<AudioBufferSourceNode> createBufferSource(bool pitchCorrection);
48
+ std::shared_ptr<AudioBufferQueueSourceNode> createBufferQueueSource();
47
49
  static std::shared_ptr<AudioBuffer>
48
50
  createBuffer(int numberOfChannels, size_t length, float sampleRate);
49
51
  std::shared_ptr<PeriodicWave> createPeriodicWave(
@@ -60,6 +62,7 @@ class BaseAudioContext {
60
62
  AudioNodeManager *getNodeManager();
61
63
 
62
64
  [[nodiscard]] bool isRunning() const;
65
+ [[nodiscard]] bool isSuspended() const;
63
66
  [[nodiscard]] bool isClosed() const;
64
67
 
65
68
  protected:
@@ -79,9 +82,7 @@ class BaseAudioContext {
79
82
  std::shared_ptr<PeriodicWave> cachedSawtoothWave_ = nullptr;
80
83
  std::shared_ptr<PeriodicWave> cachedTriangleWave_ = nullptr;
81
84
 
82
- protected:
83
- friend class AudioScheduledSourceNode;
84
-
85
+ public:
85
86
  std::shared_ptr<AudioEventHandlerRegistry> audioEventHandlerRegistry_;
86
87
  };
87
88
 
@@ -35,6 +35,7 @@ class AudioBuffer : public std::enable_shared_from_this<AudioBuffer> {
35
35
 
36
36
  private:
37
37
  friend class AudioBufferSourceNode;
38
+ friend class AudioBufferQueueSourceNode;
38
39
 
39
40
  std::shared_ptr<AudioBus> bus_;
40
41
  };
@@ -0,0 +1,236 @@
1
+ #include <audioapi/core/AudioParam.h>
2
+ #include <audioapi/core/BaseAudioContext.h>
3
+ #include <audioapi/core/Constants.h>
4
+ #include <audioapi/core/sources/AudioBufferQueueSourceNode.h>
5
+ #include <audioapi/core/utils/Locker.h>
6
+ #include <audioapi/dsp/AudioUtils.h>
7
+ #include <audioapi/events/AudioEventHandlerRegistry.h>
8
+ #include <audioapi/utils/AudioArray.h>
9
+ #include <audioapi/utils/AudioBus.h>
10
+
11
+ namespace audioapi {
12
+
13
+ AudioBufferQueueSourceNode::AudioBufferQueueSourceNode(
14
+ BaseAudioContext *context)
15
+ : AudioScheduledSourceNode(context), vReadIndex_(0.0) {
16
+ buffers_ = {};
17
+
18
+ detuneParam_ = std::make_shared<AudioParam>(
19
+ 0.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
20
+ playbackRateParam_ = std::make_shared<AudioParam>(
21
+ 1.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
22
+
23
+ playbackRateBus_ = std::make_shared<AudioBus>(
24
+ RENDER_QUANTUM_SIZE * 3, channelCount_, context_->getSampleRate());
25
+
26
+ stretch_ =
27
+ std::make_shared<signalsmith::stretch::SignalsmithStretch<float>>();
28
+ stretch_->presetDefault(channelCount_, context_->getSampleRate(), true);
29
+
30
+ onPositionChangedInterval_ = static_cast<int>(context_->getSampleRate() / 10);
31
+
32
+ isInitialized_ = true;
33
+ }
34
+
35
+ AudioBufferQueueSourceNode::~AudioBufferQueueSourceNode() {
36
+ Locker locker(getBufferLock());
37
+
38
+ buffers_ = {};
39
+ }
40
+
41
+ std::shared_ptr<AudioParam> AudioBufferQueueSourceNode::getDetuneParam() const {
42
+ return detuneParam_;
43
+ }
44
+
45
+ std::shared_ptr<AudioParam> AudioBufferQueueSourceNode::getPlaybackRateParam()
46
+ const {
47
+ return playbackRateParam_;
48
+ }
49
+
50
+ void AudioBufferQueueSourceNode::start(double when, double offset) {
51
+ AudioScheduledSourceNode::start(when);
52
+
53
+ vReadIndex_ = static_cast<double>(context_->getSampleRate() * offset);
54
+ }
55
+
56
+ void AudioBufferQueueSourceNode::enqueueBuffer(
57
+ const std::shared_ptr<AudioBuffer> &buffer,
58
+ int bufferId,
59
+ bool isLastBuffer) {
60
+ auto locker = Locker(getBufferLock());
61
+ buffers_.emplace(bufferId, buffer);
62
+
63
+ isLastBuffer_ = isLastBuffer;
64
+ }
65
+
66
+ void AudioBufferQueueSourceNode::disable() {
67
+ audioapi::AudioNode::disable();
68
+
69
+ std::string state = "stopped";
70
+
71
+ // if it has not been stopped, it is ended
72
+ if (stopTime_ < 0) {
73
+ state = "ended";
74
+ }
75
+
76
+ std::unordered_map<std::string, EventValue> body = {
77
+ {"value", getStopTime()}, {"state", state}, {"bufferId", bufferId_}};
78
+
79
+ context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
80
+ "ended", onEndedCallbackId_, body);
81
+ buffers_ = {};
82
+ }
83
+
84
+ std::mutex &AudioBufferQueueSourceNode::getBufferLock() {
85
+ return bufferLock_;
86
+ }
87
+
88
+ void AudioBufferQueueSourceNode::processNode(
89
+ const std::shared_ptr<AudioBus> &processingBus,
90
+ int framesToProcess) {
91
+ if (auto locker = Locker::tryLock(getBufferLock())) {
92
+ // No audio data to fill, zero the output and return.
93
+ if (buffers_.empty()) {
94
+ processingBus->zero();
95
+ return;
96
+ }
97
+
98
+ processWithPitchCorrection(processingBus, framesToProcess);
99
+
100
+ handleStopScheduled();
101
+ } else {
102
+ processingBus->zero();
103
+ }
104
+ }
105
+
106
+ double AudioBufferQueueSourceNode::getStopTime() const {
107
+ return dsp::sampleFrameToTime(
108
+ static_cast<int>(vReadIndex_), context_->getSampleRate());
109
+ }
110
+
111
+ void AudioBufferQueueSourceNode::setOnPositionChangedCallbackId(
112
+ uint64_t callbackId) {
113
+ onPositionChangedCallbackId_ = callbackId;
114
+ }
115
+
116
+ void AudioBufferQueueSourceNode::sendOnPositionChangedEvent() {
117
+ if (onPositionChangedTime_ > onPositionChangedInterval_) {
118
+ std::unordered_map<std::string, EventValue> body = {
119
+ {"value", getStopTime()}, {"bufferId", bufferId_}};
120
+
121
+ context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
122
+ "positionChanged", onPositionChangedCallbackId_, body);
123
+
124
+ onPositionChangedTime_ = 0;
125
+ }
126
+
127
+ onPositionChangedTime_ += RENDER_QUANTUM_SIZE;
128
+ }
129
+
130
+ void AudioBufferQueueSourceNode::setOnPositionChangedInterval(int interval) {
131
+ onPositionChangedInterval_ = static_cast<int>(
132
+ context_->getSampleRate() * static_cast<float>(interval) / 1000);
133
+ }
134
+
135
+ /**
136
+ * Helper functions
137
+ */
138
+
139
+ void AudioBufferQueueSourceNode::processWithPitchCorrection(
140
+ const std::shared_ptr<AudioBus> &processingBus,
141
+ int framesToProcess) {
142
+ size_t startOffset = 0;
143
+ size_t offsetLength = 0;
144
+
145
+ auto time = context_->getCurrentTime();
146
+ auto playbackRate = std::clamp(
147
+ playbackRateParam_->processKRateParam(framesToProcess, time), 0.0f, 3.0f);
148
+ auto detune = std::clamp(
149
+ detuneParam_->processKRateParam(framesToProcess, time) / 100.0f,
150
+ -12.0f,
151
+ 12.0f);
152
+
153
+ playbackRateBus_->zero();
154
+
155
+ auto framesNeededToStretch =
156
+ static_cast<int>(playbackRate * static_cast<float>(framesToProcess));
157
+
158
+ updatePlaybackInfo(
159
+ playbackRateBus_, framesNeededToStretch, startOffset, offsetLength);
160
+
161
+ if (playbackRate == 0.0f || (!isPlaying() && !isStopScheduled())) {
162
+ processingBus->zero();
163
+ return;
164
+ }
165
+
166
+ // Send position changed event
167
+ sendOnPositionChangedEvent();
168
+
169
+ processWithoutInterpolation(playbackRateBus_, startOffset, offsetLength);
170
+
171
+ stretch_->process(
172
+ playbackRateBus_.get()[0],
173
+ framesNeededToStretch,
174
+ processingBus.get()[0],
175
+ framesToProcess);
176
+
177
+ if (detune != 0.0f) {
178
+ stretch_->setTransposeSemitones(detune);
179
+ }
180
+ }
181
+
182
+ void AudioBufferQueueSourceNode::processWithoutInterpolation(
183
+ const std::shared_ptr<AudioBus> &processingBus,
184
+ size_t startOffset,
185
+ size_t offsetLength) {
186
+ auto readIndex = static_cast<size_t>(vReadIndex_);
187
+ size_t writeIndex = startOffset;
188
+
189
+ auto queueData = buffers_.front();
190
+ bufferId_ = queueData.first;
191
+ auto buffer = queueData.second;
192
+
193
+ size_t framesLeft = offsetLength;
194
+
195
+ while (framesLeft > 0) {
196
+ size_t framesToEnd = buffer->getLength() - readIndex;
197
+ size_t framesToCopy = std::min(framesToEnd, framesLeft);
198
+ framesToCopy = framesToCopy > 0 ? framesToCopy : 0;
199
+
200
+ assert(readIndex >= 0);
201
+ assert(writeIndex >= 0);
202
+ assert(writeIndex + framesToCopy <= processingBus->getSize());
203
+
204
+ processingBus->copy(
205
+ buffer->bus_.get(), readIndex, writeIndex, framesToCopy);
206
+
207
+ writeIndex += framesToCopy;
208
+ readIndex += framesToCopy;
209
+ framesLeft -= framesToCopy;
210
+
211
+ if (readIndex >= buffer->getLength()) {
212
+ buffers_.pop();
213
+
214
+ if (buffers_.empty()) {
215
+ processingBus->zero(writeIndex, framesLeft);
216
+ readIndex = 0;
217
+
218
+ if (isLastBuffer_) {
219
+ playbackState_ = PlaybackState::STOP_SCHEDULED;
220
+ }
221
+ break;
222
+ } else {
223
+ queueData = buffers_.front();
224
+ bufferId_ = queueData.first;
225
+ buffer = queueData.second;
226
+
227
+ readIndex = 0;
228
+ }
229
+ }
230
+ }
231
+
232
+ // update reading index for next render quantum
233
+ vReadIndex_ = static_cast<double>(readIndex);
234
+ }
235
+
236
+ } // namespace audioapi
@@ -0,0 +1,72 @@
1
+ #pragma once
2
+
3
+ #include <audioapi/core/sources/AudioBuffer.h>
4
+ #include <audioapi/core/sources/AudioScheduledSourceNode.h>
5
+ #include <audioapi/libs/signalsmith-stretch/signalsmith-stretch.h>
6
+
7
+ #include <memory>
8
+ #include <cstddef>
9
+ #include <algorithm>
10
+ #include <string>
11
+ #include <queue>
12
+
13
+ namespace audioapi {
14
+
15
+ class AudioBus;
16
+ class AudioParam;
17
+
18
+ class AudioBufferQueueSourceNode : public AudioScheduledSourceNode {
19
+ public:
20
+ explicit AudioBufferQueueSourceNode(BaseAudioContext *context);
21
+ ~AudioBufferQueueSourceNode() override;
22
+
23
+ [[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
24
+ [[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
25
+
26
+ void start(double when, double offset);
27
+ void enqueueBuffer(const std::shared_ptr<AudioBuffer> &buffer, int bufferId, bool isLastBuffer);
28
+ void disable() override;
29
+
30
+ void setOnPositionChangedCallbackId(uint64_t callbackId);
31
+ void setOnPositionChangedInterval(int interval);
32
+ void sendOnPositionChangedEvent();
33
+
34
+ protected:
35
+ std::mutex &getBufferLock();
36
+ void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
37
+ double getStopTime() const override;
38
+
39
+ private:
40
+ std::mutex bufferLock_;
41
+
42
+ // pitch correction
43
+ std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> stretch_;
44
+ std::shared_ptr<AudioBus> playbackRateBus_;
45
+
46
+ // k-rate params
47
+ std::shared_ptr<AudioParam> detuneParam_;
48
+ std::shared_ptr<AudioParam> playbackRateParam_;
49
+
50
+ // internal helper
51
+ double vReadIndex_;
52
+
53
+ // User provided buffers
54
+ std::queue<std::pair<int, std::shared_ptr<AudioBuffer>>> buffers_;
55
+ int bufferId_ = 0;
56
+ bool isLastBuffer_ = false;
57
+
58
+ // positionChanged event props: callbackId, update interval in frames, time since last update in frames
59
+ uint64_t onPositionChangedCallbackId_ = 0;
60
+ int onPositionChangedInterval_;
61
+ int onPositionChangedTime_ = 0;
62
+
63
+ void processWithPitchCorrection(const std::shared_ptr<AudioBus> &processingBus,
64
+ int framesToProcess);
65
+
66
+ void processWithoutInterpolation(
67
+ const std::shared_ptr<AudioBus>& processingBus,
68
+ size_t startOffset,
69
+ size_t offsetLength);
70
+ };
71
+
72
+ } // namespace audioapi
@@ -17,7 +17,7 @@ class AudioParam;
17
17
  class AudioBufferSourceNode : public AudioScheduledSourceNode {
18
18
  public:
19
19
  explicit AudioBufferSourceNode(BaseAudioContext *context, bool pitchCorrection);
20
- ~AudioBufferSourceNode();
20
+ ~AudioBufferSourceNode() override;
21
21
 
22
22
  [[nodiscard]] bool getLoop() const;
23
23
  [[nodiscard]] double getLoopStart() const;
@@ -10,9 +10,9 @@ namespace audioapi {
10
10
 
11
11
  AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
12
12
  : AudioNode(context),
13
- playbackState_(PlaybackState::UNSCHEDULED),
14
13
  startTime_(-1.0),
15
- stopTime_(-1.0) {
14
+ stopTime_(-1.0),
15
+ playbackState_(PlaybackState::UNSCHEDULED) {
16
16
  numberOfInputs_ = 0;
17
17
  }
18
18
 
@@ -43,6 +43,9 @@ class AudioScheduledSourceNode : public AudioNode {
43
43
  void disable() override;
44
44
 
45
45
  protected:
46
+ double startTime_;
47
+ double stopTime_;
48
+
46
49
  PlaybackState playbackState_;
47
50
 
48
51
  void updatePlaybackInfo(
@@ -53,10 +56,6 @@ class AudioScheduledSourceNode : public AudioNode {
53
56
 
54
57
  void handleStopScheduled();
55
58
 
56
- private:
57
- double startTime_;
58
- double stopTime_;
59
-
60
59
  uint64_t onEndedCallbackId_ = 0;
61
60
  };
62
61
 
@@ -49,9 +49,10 @@ class AudioEventHandlerRegistry {
49
49
  "volumeChange",
50
50
  };
51
51
 
52
- static constexpr std::array<std::string_view, 4> AUDIO_API_EVENT_NAMES = {
52
+ static constexpr std::array<std::string_view, 5> AUDIO_API_EVENT_NAMES = {
53
53
  "ended",
54
54
  "audioReady",
55
+ "positionChanged",
55
56
  "audioError",
56
57
  "systemStateChanged"
57
58
  };
@@ -80,19 +80,21 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install)
80
80
  return @true;
81
81
  }
82
82
 
83
- RCT_EXPORT_METHOD(setLockScreenInfo : (NSDictionary *)info)
83
+ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getDevicePreferredSampleRate)
84
84
  {
85
- [self.lockScreenManager setLockScreenInfo:info];
85
+ return [self.audioSessionManager getDevicePreferredSampleRate];
86
86
  }
87
87
 
88
- RCT_EXPORT_METHOD(resetLockScreenInfo)
88
+ RCT_EXPORT_METHOD(
89
+ setAudioSessionActivity : (BOOL)enabled resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)
90
+ reject)
89
91
  {
90
- [self.lockScreenManager resetLockScreenInfo];
91
- }
92
+ if ([self.audioSessionManager setActive:enabled]) {
93
+ resolve(@"true");
94
+ return;
95
+ }
92
96
 
93
- RCT_EXPORT_METHOD(enableRemoteCommand : (NSString *)name enabled : (BOOL)enabled)
94
- {
95
- [self.lockScreenManager enableRemoteCommand:name enabled:enabled];
97
+ resolve(@"false");
96
98
  }
97
99
 
98
100
  RCT_EXPORT_METHOD(setAudioSessionOptions : (NSString *)category mode : (NSString *)mode options : (NSArray *)options)
@@ -100,9 +102,19 @@ RCT_EXPORT_METHOD(setAudioSessionOptions : (NSString *)category mode : (NSString
100
102
  [self.audioSessionManager setAudioSessionOptions:category mode:mode options:options];
101
103
  }
102
104
 
103
- RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getDevicePreferredSampleRate)
105
+ RCT_EXPORT_METHOD(setLockScreenInfo : (NSDictionary *)info)
104
106
  {
105
- return [self.audioSessionManager getDevicePreferredSampleRate];
107
+ [self.lockScreenManager setLockScreenInfo:info];
108
+ }
109
+
110
+ RCT_EXPORT_METHOD(resetLockScreenInfo)
111
+ {
112
+ [self.lockScreenManager resetLockScreenInfo];
113
+ }
114
+
115
+ RCT_EXPORT_METHOD(enableRemoteCommand : (NSString *)name enabled : (BOOL)enabled)
116
+ {
117
+ [self.lockScreenManager enableRemoteCommand:name enabled:enabled];
106
118
  }
107
119
 
108
120
  RCT_EXPORT_METHOD(observeAudioInterruptions : (BOOL)enabled)
@@ -159,7 +171,7 @@ RCT_EXPORT_METHOD(
159
171
  body[stdKey] = EventValue([value doubleValue]);
160
172
  } else if (strcmp(type, @encode(float)) == 0) {
161
173
  body[stdKey] = EventValue([value floatValue]);
162
- } else if (strcmp(type, @encode(BOOL)) == 0) {
174
+ } else {
163
175
  body[stdKey] = EventValue([value boolValue]);
164
176
  }
165
177
  }
@@ -21,9 +21,10 @@ class IOSAudioPlayer {
21
21
  ~IOSAudioPlayer();
22
22
 
23
23
  void start();
24
- void resume();
25
24
  void stop();
26
- void pause();
25
+ void resume();
26
+ void suspend();
27
+ void cleanup();
27
28
 
28
29
  protected:
29
30
  std::shared_ptr<AudioBus> audioBus_;
@@ -43,12 +43,7 @@ IOSAudioPlayer::IOSAudioPlayer(const std::function<void(std::shared_ptr<AudioBus
43
43
 
44
44
  IOSAudioPlayer::~IOSAudioPlayer()
45
45
  {
46
- stop();
47
- [audioPlayer_ cleanup];
48
-
49
- if (audioBus_) {
50
- audioBus_ = nullptr;
51
- }
46
+ cleanup();
52
47
  }
53
48
 
54
49
  void IOSAudioPlayer::start()
@@ -61,20 +56,36 @@ void IOSAudioPlayer::start()
61
56
  isRunning_.store(true);
62
57
  }
63
58
 
59
+ void IOSAudioPlayer::stop()
60
+ {
61
+ isRunning_.store(false);
62
+ [audioPlayer_ stop];
63
+ }
64
+
64
65
  void IOSAudioPlayer::resume()
65
66
  {
67
+ if (isRunning_.load()) {
68
+ return;
69
+ }
70
+
71
+ [audioPlayer_ resume];
66
72
  isRunning_.store(true);
67
73
  }
68
74
 
69
- void IOSAudioPlayer::stop()
75
+ void IOSAudioPlayer::suspend()
70
76
  {
71
77
  isRunning_.store(false);
72
- [audioPlayer_ stop];
78
+ [audioPlayer_ suspend];
73
79
  }
74
80
 
75
- void IOSAudioPlayer::pause()
81
+ void IOSAudioPlayer::cleanup()
76
82
  {
77
- isRunning_.store(false);
83
+ stop();
84
+ [audioPlayer_ cleanup];
85
+
86
+ if (audioBus_) {
87
+ audioBus_ = nullptr;
88
+ }
78
89
  }
79
90
 
80
91
  } // namespace audioapi
@@ -23,6 +23,10 @@ typedef void (^RenderAudioBlock)(AudioBufferList *outputBuffer, int numFrames);
23
23
 
24
24
  - (void)stop;
25
25
 
26
+ - (void)resume;
27
+
28
+ - (void)suspend;
29
+
26
30
  - (void)cleanup;
27
31
 
28
32
  @end
@@ -51,6 +51,21 @@
51
51
  self.sourceNodeId = nil;
52
52
  }
53
53
 
54
+ - (void)resume
55
+ {
56
+ NSLog(@"[AudioPlayer] resume");
57
+ AudioEngine *audioEngine = [AudioEngine sharedInstance];
58
+ assert(audioEngine != nil);
59
+ [audioEngine startEngine];
60
+ }
61
+
62
+ - (void)suspend
63
+ {
64
+ AudioEngine *audioEngine = [AudioEngine sharedInstance];
65
+ assert(audioEngine != nil);
66
+ [audioEngine pauseEngine];
67
+ }
68
+
54
69
  - (void)cleanup
55
70
  {
56
71
  self.renderAudio = nil;
@@ -20,6 +20,7 @@
20
20
  - (bool)rebuildAudioEngine;
21
21
  - (void)startEngine;
22
22
  - (void)stopEngine;
23
+ - (void)pauseEngine;
23
24
  - (bool)isRunning;
24
25
 
25
26
  - (NSString *)attachSourceNode:(AVAudioSourceNode *)sourceNode format:(AVAudioFormat *)format;
@@ -20,7 +20,6 @@ static AudioEngine *_sharedInstance = nil;
20
20
  self.sourceFormats = [[NSMutableDictionary alloc] init];
21
21
 
22
22
  self.sessionManager = sessionManager;
23
- [self.sessionManager setActive:true];
24
23
  }
25
24
 
26
25
  _sharedInstance = self;
@@ -76,6 +75,7 @@ static AudioEngine *_sharedInstance = nil;
76
75
  }
77
76
 
78
77
  [self.audioEngine startAndReturnError:&error];
78
+ [self.sessionManager setActive:true];
79
79
 
80
80
  if (error != nil) {
81
81
  NSLog(@"Error while starting the audio engine: %@", [error debugDescription]);
@@ -92,6 +92,16 @@ static AudioEngine *_sharedInstance = nil;
92
92
  [self.audioEngine stop];
93
93
  }
94
94
 
95
+ - (void)pauseEngine
96
+ {
97
+ NSLog(@"[AudioEngine] pauseEngine");
98
+ if (![self.audioEngine isRunning]) {
99
+ return;
100
+ }
101
+
102
+ [self.audioEngine pause];
103
+ }
104
+
95
105
  - (bool)isRunning
96
106
  {
97
107
  return [self.audioEngine isRunning];
@@ -9,7 +9,7 @@
9
9
 
10
10
  self.sessionCategory = AVAudioSessionCategoryPlayback;
11
11
  self.sessionMode = AVAudioSessionModeDefault;
12
- self.sessionOptions = AVAudioSessionCategoryOptionAllowAirPlay;
12
+ self.sessionOptions = 0;
13
13
  self.hasDirtySettings = true;
14
14
  self.isActive = false;
15
15
  }