react-native-audio-api 0.10.0-nightly-44925d7-20251104 → 0.10.0-nightly-98d2e0d-20251106
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/java/com/swmansion/audioapi/AudioAPIModule.kt +0 -2
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.cpp +1 -1
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp +1 -1
- package/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.cpp +1 -1
- package/common/cpp/audioapi/core/effects/ConvolverNode.cpp +5 -5
- package/common/cpp/audioapi/core/effects/ConvolverNode.h +1 -1
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +14 -17
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +0 -1
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +8 -14
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +0 -1
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +14 -18
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +2 -2
- package/common/cpp/audioapi/core/sources/StreamerNode.cpp +2 -2
- package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.cpp +3 -3
- package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.h +1 -1
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +1 -1
- package/common/cpp/test/src/AudioParamTest.cpp +1 -1
- package/common/cpp/test/src/AudioScheduledSourceTest.cpp +134 -0
- package/common/cpp/test/src/ConstantSourceTest.cpp +1 -1
- package/common/cpp/test/src/GainTest.cpp +1 -1
- package/common/cpp/test/src/MockAudioEventHandlerRegistry.h +4 -4
- package/common/cpp/test/src/OscillatorTest.cpp +1 -1
- package/common/cpp/test/src/StereoPannerTest.cpp +1 -1
- package/common/cpp/test/src/biquad/BiquadFilterTest.h +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,6 @@ package com.swmansion.audioapi
|
|
|
2
2
|
|
|
3
3
|
import com.facebook.jni.HybridData
|
|
4
4
|
import com.facebook.react.bridge.LifecycleEventListener
|
|
5
|
-
import com.facebook.react.bridge.NativeModule
|
|
6
5
|
import com.facebook.react.bridge.Promise
|
|
7
6
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
8
7
|
import com.facebook.react.bridge.ReadableArray
|
|
@@ -27,7 +26,6 @@ class AudioAPIModule(
|
|
|
27
26
|
val reactContext: WeakReference<ReactApplicationContext> = WeakReference(reactContext)
|
|
28
27
|
|
|
29
28
|
private val mHybridData: HybridData
|
|
30
|
-
private var reanimatedModule: NativeModule? = null
|
|
31
29
|
|
|
32
30
|
external fun initHybrid(
|
|
33
31
|
workletsModule: Any?,
|
|
@@ -28,7 +28,7 @@ AudioBufferBaseSourceNodeHostObject::~AudioBufferBaseSourceNodeHostObject() {
|
|
|
28
28
|
// When JSI object is garbage collected (together with the eventual callback),
|
|
29
29
|
// underlying source node might still be active and try to call the
|
|
30
30
|
// non-existing callback.
|
|
31
|
-
sourceNode->
|
|
31
|
+
sourceNode->setOnPositionChangedCallbackId(0);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
JSI_PROPERTY_GETTER_IMPL(AudioBufferBaseSourceNodeHostObject, detune) {
|
|
@@ -37,7 +37,7 @@ AudioBufferSourceNodeHostObject::~AudioBufferSourceNodeHostObject() {
|
|
|
37
37
|
// When JSI object is garbage collected (together with the eventual callback),
|
|
38
38
|
// underlying source node might still be active and try to call the
|
|
39
39
|
// non-existing callback.
|
|
40
|
-
audioBufferSourceNode->
|
|
40
|
+
audioBufferSourceNode->setOnLoopEndedCallbackId(0);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
JSI_PROPERTY_GETTER_IMPL(AudioBufferSourceNodeHostObject, loop) {
|
|
@@ -22,7 +22,7 @@ AudioScheduledSourceNodeHostObject::~AudioScheduledSourceNodeHostObject() {
|
|
|
22
22
|
// When JSI object is garbage collected (together with the eventual callback),
|
|
23
23
|
// underlying source node might still be active and try to call the
|
|
24
24
|
// non-existing callback.
|
|
25
|
-
audioScheduledSourceNode->
|
|
25
|
+
audioScheduledSourceNode->setOnEndedCallbackId(0);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
JSI_PROPERTY_SETTER_IMPL(AudioScheduledSourceNodeHostObject, onEnded) {
|
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
namespace audioapi {
|
|
12
12
|
ConvolverNode::ConvolverNode(
|
|
13
13
|
BaseAudioContext *context,
|
|
14
|
-
std::shared_ptr<AudioBuffer> buffer,
|
|
14
|
+
const std::shared_ptr<AudioBuffer> &buffer,
|
|
15
15
|
bool disableNormalization)
|
|
16
16
|
: AudioNode(context),
|
|
17
|
-
buffer_(nullptr),
|
|
18
|
-
internalBuffer_(nullptr),
|
|
19
|
-
signalledToStop_(false),
|
|
20
17
|
remainingSegments_(0),
|
|
21
18
|
internalBufferIndex_(0),
|
|
19
|
+
signalledToStop_(false),
|
|
22
20
|
scaleFactor_(1.0f),
|
|
23
|
-
intermediateBus_(nullptr)
|
|
21
|
+
intermediateBus_(nullptr),
|
|
22
|
+
buffer_(nullptr),
|
|
23
|
+
internalBuffer_(nullptr) {
|
|
24
24
|
channelCount_ = 2;
|
|
25
25
|
channelCountMode_ = ChannelCountMode::CLAMPED_MAX;
|
|
26
26
|
normalize_ = !disableNormalization;
|
|
@@ -19,7 +19,7 @@ class AudioBuffer;
|
|
|
19
19
|
|
|
20
20
|
class ConvolverNode : public AudioNode {
|
|
21
21
|
public:
|
|
22
|
-
explicit ConvolverNode(BaseAudioContext *context, std::shared_ptr<AudioBuffer
|
|
22
|
+
explicit ConvolverNode(BaseAudioContext *context, const std::shared_ptr<AudioBuffer>& buffer, bool disableNormalization);
|
|
23
23
|
|
|
24
24
|
[[nodiscard]] bool getNormalize_() const;
|
|
25
25
|
[[nodiscard]] const std::shared_ptr<AudioBuffer> &getBuffer() const;
|
|
@@ -36,20 +36,15 @@ std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getPlaybackRateParam()
|
|
|
36
36
|
return playbackRateParam_;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
void AudioBufferBaseSourceNode::clearOnPositionChangedCallback() {
|
|
40
|
-
if (onPositionChangedCallbackId_ == 0 || context_ == nullptr ||
|
|
41
|
-
context_->audioEventHandlerRegistry_ == nullptr) {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
context_->audioEventHandlerRegistry_->unregisterHandler(
|
|
46
|
-
"positionChanged", onPositionChangedCallbackId_);
|
|
47
|
-
onPositionChangedCallbackId_ = 0;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
39
|
void AudioBufferBaseSourceNode::setOnPositionChangedCallbackId(
|
|
51
40
|
uint64_t callbackId) {
|
|
52
|
-
|
|
41
|
+
auto oldCallbackId = onPositionChangedCallbackId_.exchange(
|
|
42
|
+
callbackId, std::memory_order_acq_rel);
|
|
43
|
+
|
|
44
|
+
if (oldCallbackId != 0) {
|
|
45
|
+
audioEventHandlerRegistry_->unregisterHandler(
|
|
46
|
+
"positionChanged", oldCallbackId);
|
|
47
|
+
}
|
|
53
48
|
}
|
|
54
49
|
|
|
55
50
|
void AudioBufferBaseSourceNode::setOnPositionChangedInterval(int interval) {
|
|
@@ -66,14 +61,16 @@ std::mutex &AudioBufferBaseSourceNode::getBufferLock() {
|
|
|
66
61
|
}
|
|
67
62
|
|
|
68
63
|
void AudioBufferBaseSourceNode::sendOnPositionChangedEvent() {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
auto onPositionChangedCallbackId =
|
|
65
|
+
onPositionChangedCallbackId_.load(std::memory_order_acquire);
|
|
66
|
+
|
|
67
|
+
if (onPositionChangedCallbackId != 0 &&
|
|
68
|
+
onPositionChangedTime_ > onPositionChangedInterval_) {
|
|
72
69
|
std::unordered_map<std::string, EventValue> body = {
|
|
73
70
|
{"value", getCurrentPosition()}};
|
|
74
71
|
|
|
75
|
-
|
|
76
|
-
"positionChanged",
|
|
72
|
+
audioEventHandlerRegistry_->invokeHandlerWithEventBody(
|
|
73
|
+
"positionChanged", onPositionChangedCallbackId, body);
|
|
77
74
|
|
|
78
75
|
onPositionChangedTime_ = 0;
|
|
79
76
|
}
|
|
@@ -19,7 +19,6 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
|
|
|
19
19
|
[[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
|
|
20
20
|
[[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
|
|
21
21
|
|
|
22
|
-
void clearOnPositionChangedCallback();
|
|
23
22
|
void setOnPositionChangedCallbackId(uint64_t callbackId);
|
|
24
23
|
void setOnPositionChangedInterval(int interval);
|
|
25
24
|
[[nodiscard]] int getOnPositionChangedInterval() const;
|
|
@@ -123,19 +123,13 @@ void AudioBufferSourceNode::disable() {
|
|
|
123
123
|
alignedBus_.reset();
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
void AudioBufferSourceNode::clearOnLoopEndedCallback() {
|
|
127
|
-
if (onLoopEndedCallbackId_ == 0 || context_ == nullptr ||
|
|
128
|
-
context_->audioEventHandlerRegistry_ == nullptr) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
context_->audioEventHandlerRegistry_->unregisterHandler(
|
|
133
|
-
"loopEnded", onLoopEndedCallbackId_);
|
|
134
|
-
onLoopEndedCallbackId_ = 0;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
126
|
void AudioBufferSourceNode::setOnLoopEndedCallbackId(uint64_t callbackId) {
|
|
138
|
-
|
|
127
|
+
auto oldCallbackId =
|
|
128
|
+
onLoopEndedCallbackId_.exchange(callbackId, std::memory_order_acq_rel);
|
|
129
|
+
|
|
130
|
+
if (oldCallbackId != 0) {
|
|
131
|
+
audioEventHandlerRegistry_->unregisterHandler("loopEnded", oldCallbackId);
|
|
132
|
+
}
|
|
139
133
|
}
|
|
140
134
|
|
|
141
135
|
std::shared_ptr<AudioBus> AudioBufferSourceNode::processNode(
|
|
@@ -171,8 +165,8 @@ void AudioBufferSourceNode::sendOnLoopEndedEvent() {
|
|
|
171
165
|
auto onLoopEndedCallbackId =
|
|
172
166
|
onLoopEndedCallbackId_.load(std::memory_order_acquire);
|
|
173
167
|
if (onLoopEndedCallbackId != 0) {
|
|
174
|
-
|
|
175
|
-
"loopEnded",
|
|
168
|
+
audioEventHandlerRegistry_->invokeHandlerWithEventBody(
|
|
169
|
+
"loopEnded", onLoopEndedCallbackId, {});
|
|
176
170
|
}
|
|
177
171
|
}
|
|
178
172
|
|
|
@@ -34,7 +34,6 @@ class AudioBufferSourceNode : public AudioBufferBaseSourceNode {
|
|
|
34
34
|
void start(double when, double offset, double duration = -1);
|
|
35
35
|
void disable() override;
|
|
36
36
|
|
|
37
|
-
void clearOnLoopEndedCallback();
|
|
38
37
|
void setOnLoopEndedCallbackId(uint64_t callbackId);
|
|
39
38
|
|
|
40
39
|
protected:
|
|
@@ -14,6 +14,7 @@ AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
|
|
|
14
14
|
stopTime_(-1.0),
|
|
15
15
|
playbackState_(PlaybackState::UNSCHEDULED) {
|
|
16
16
|
numberOfInputs_ = 0;
|
|
17
|
+
audioEventHandlerRegistry_ = context_->audioEventHandlerRegistry_;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
void AudioScheduledSourceNode::start(double when) {
|
|
@@ -45,19 +46,13 @@ bool AudioScheduledSourceNode::isStopScheduled() {
|
|
|
45
46
|
return playbackState_ == PlaybackState::STOP_SCHEDULED;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
void AudioScheduledSourceNode::clearOnEndedCallback() {
|
|
49
|
-
if (onEndedCallbackId_ == 0 || context_ == nullptr ||
|
|
50
|
-
context_->audioEventHandlerRegistry_ == nullptr) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
context_->audioEventHandlerRegistry_->unregisterHandler(
|
|
55
|
-
"ended", onEndedCallbackId_);
|
|
56
|
-
onEndedCallbackId_ = 0;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
49
|
void AudioScheduledSourceNode::setOnEndedCallbackId(const uint64_t callbackId) {
|
|
60
|
-
|
|
50
|
+
auto oldCallbackId =
|
|
51
|
+
onEndedCallbackId_.exchange(callbackId, std::memory_order_acq_rel);
|
|
52
|
+
|
|
53
|
+
if (oldCallbackId != 0) {
|
|
54
|
+
audioEventHandlerRegistry_->unregisterHandler("ended", oldCallbackId);
|
|
55
|
+
}
|
|
61
56
|
}
|
|
62
57
|
|
|
63
58
|
void AudioScheduledSourceNode::updatePlaybackInfo(
|
|
@@ -76,7 +71,7 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
|
|
|
76
71
|
auto sampleRate = context_->getSampleRate();
|
|
77
72
|
|
|
78
73
|
size_t firstFrame = context_->getCurrentSampleFrame();
|
|
79
|
-
size_t lastFrame = firstFrame + framesToProcess;
|
|
74
|
+
size_t lastFrame = firstFrame + framesToProcess - 1;
|
|
80
75
|
|
|
81
76
|
size_t startFrame =
|
|
82
77
|
std::max(dsp::timeToSampleFrame(startTime_, sampleRate), firstFrame);
|
|
@@ -105,7 +100,7 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
|
|
|
105
100
|
? std::max(startFrame, firstFrame) - firstFrame
|
|
106
101
|
: 0;
|
|
107
102
|
nonSilentFramesToProcess =
|
|
108
|
-
std::max(std::min(lastFrame, stopFrame), startFrame) - startFrame;
|
|
103
|
+
std::max(std::min(lastFrame, stopFrame) + 1, startFrame) - startFrame;
|
|
109
104
|
|
|
110
105
|
assert(startOffset <= framesToProcess);
|
|
111
106
|
assert(nonSilentFramesToProcess <= framesToProcess);
|
|
@@ -124,7 +119,7 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
|
|
|
124
119
|
|
|
125
120
|
// stop will happen in this render quantum
|
|
126
121
|
// zero remaining frames after stop frame
|
|
127
|
-
if (stopFrame
|
|
122
|
+
if (stopFrame <= lastFrame && stopFrame >= firstFrame) {
|
|
128
123
|
playbackState_ = PlaybackState::STOP_SCHEDULED;
|
|
129
124
|
startOffset = 0;
|
|
130
125
|
nonSilentFramesToProcess = stopFrame - firstFrame;
|
|
@@ -160,9 +155,10 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
|
|
|
160
155
|
void AudioScheduledSourceNode::disable() {
|
|
161
156
|
AudioNode::disable();
|
|
162
157
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
auto onEndedCallbackId = onEndedCallbackId_.load(std::memory_order_acquire);
|
|
159
|
+
if (onEndedCallbackId != 0) {
|
|
160
|
+
audioEventHandlerRegistry_->invokeHandlerWithEventBody(
|
|
161
|
+
"ended", onEndedCallbackId, {});
|
|
166
162
|
}
|
|
167
163
|
}
|
|
168
164
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
namespace audioapi {
|
|
18
18
|
|
|
19
|
-
class
|
|
19
|
+
class IAudioEventHandlerRegistry;
|
|
20
20
|
|
|
21
21
|
class AudioScheduledSourceNode : public AudioNode {
|
|
22
22
|
public:
|
|
@@ -37,7 +37,6 @@ class AudioScheduledSourceNode : public AudioNode {
|
|
|
37
37
|
bool isFinished();
|
|
38
38
|
bool isStopScheduled();
|
|
39
39
|
|
|
40
|
-
void clearOnEndedCallback();
|
|
41
40
|
void setOnEndedCallbackId(uint64_t callbackId);
|
|
42
41
|
|
|
43
42
|
void disable() override;
|
|
@@ -49,6 +48,7 @@ class AudioScheduledSourceNode : public AudioNode {
|
|
|
49
48
|
PlaybackState playbackState_;
|
|
50
49
|
|
|
51
50
|
std::atomic<uint64_t> onEndedCallbackId_ = 0;
|
|
51
|
+
std::shared_ptr<IAudioEventHandlerRegistry> audioEventHandlerRegistry_;
|
|
52
52
|
|
|
53
53
|
void updatePlaybackInfo(
|
|
54
54
|
const std::shared_ptr<AudioBus>& processingBus,
|
|
@@ -25,10 +25,10 @@ StreamerNode::StreamerNode(BaseAudioContext *context)
|
|
|
25
25
|
codecpar_(nullptr),
|
|
26
26
|
pkt_(nullptr),
|
|
27
27
|
frame_(nullptr),
|
|
28
|
-
bufferedBus_(nullptr),
|
|
29
|
-
audio_stream_index_(-1),
|
|
30
28
|
swrCtx_(nullptr),
|
|
31
29
|
resampledData_(nullptr),
|
|
30
|
+
bufferedBus_(nullptr),
|
|
31
|
+
audio_stream_index_(-1),
|
|
32
32
|
maxResampledSamples_(0),
|
|
33
33
|
processedSamples_(0) {}
|
|
34
34
|
|
|
@@ -4,7 +4,7 @@ namespace audioapi {
|
|
|
4
4
|
|
|
5
5
|
WorkletsRunner::WorkletsRunner(
|
|
6
6
|
std::weak_ptr<worklets::WorkletRuntime> weakRuntime,
|
|
7
|
-
std::shared_ptr<worklets::SerializableWorklet> shareableWorklet,
|
|
7
|
+
const std::shared_ptr<worklets::SerializableWorklet> &shareableWorklet,
|
|
8
8
|
bool shouldLockRuntime)
|
|
9
9
|
: weakRuntime_(std::move(weakRuntime)),
|
|
10
10
|
shouldLockRuntime(shouldLockRuntime) {
|
|
@@ -33,8 +33,8 @@ WorkletsRunner::WorkletsRunner(
|
|
|
33
33
|
WorkletsRunner::WorkletsRunner(WorkletsRunner &&other)
|
|
34
34
|
: weakRuntime_(std::move(other.weakRuntime_)),
|
|
35
35
|
unsafeRuntimePtr(other.unsafeRuntimePtr),
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
workletInitialized(other.workletInitialized),
|
|
37
|
+
shouldLockRuntime(other.shouldLockRuntime) {
|
|
38
38
|
if (workletInitialized) {
|
|
39
39
|
std::memcpy(&unsafeWorklet, &other.unsafeWorklet, sizeof(unsafeWorklet));
|
|
40
40
|
other.workletInitialized = false;
|
|
@@ -28,7 +28,7 @@ class WorkletsRunner {
|
|
|
28
28
|
public:
|
|
29
29
|
explicit WorkletsRunner(
|
|
30
30
|
std::weak_ptr<worklets::WorkletRuntime> weakRuntime,
|
|
31
|
-
std::shared_ptr<worklets::SerializableWorklet
|
|
31
|
+
const std::shared_ptr<worklets::SerializableWorklet>& shareableWorklet,
|
|
32
32
|
bool shouldLockRuntime = true);
|
|
33
33
|
WorkletsRunner(WorkletsRunner&&);
|
|
34
34
|
~WorkletsRunner();
|
|
@@ -20,7 +20,7 @@ class AudioEventHandlerRegistry : public IAudioEventHandlerRegistry {
|
|
|
20
20
|
explicit AudioEventHandlerRegistry(
|
|
21
21
|
jsi::Runtime *runtime,
|
|
22
22
|
const std::shared_ptr<react::CallInvoker> &callInvoker);
|
|
23
|
-
~AudioEventHandlerRegistry();
|
|
23
|
+
~AudioEventHandlerRegistry() override;
|
|
24
24
|
|
|
25
25
|
uint64_t registerHandler(const std::string &eventName, const std::shared_ptr<jsi::Function> &handler) override;
|
|
26
26
|
void unregisterHandler(const std::string &eventName, uint64_t listenerId) override;
|
|
@@ -8,7 +8,7 @@ using namespace audioapi;
|
|
|
8
8
|
|
|
9
9
|
class AudioParamTest : public ::testing::Test {
|
|
10
10
|
protected:
|
|
11
|
-
std::shared_ptr<
|
|
11
|
+
std::shared_ptr<MockAudioEventHandlerRegistry> eventRegistry;
|
|
12
12
|
std::unique_ptr<OfflineAudioContext> context;
|
|
13
13
|
static constexpr int sampleRate = 44100;
|
|
14
14
|
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#include <audioapi/core/OfflineAudioContext.h>
|
|
2
|
+
#include <audioapi/core/destinations/AudioDestinationNode.h>
|
|
3
|
+
#include <audioapi/core/sources/AudioScheduledSourceNode.h>
|
|
4
|
+
#include <audioapi/core/utils/worklets/SafeIncludes.h>
|
|
5
|
+
#include <audioapi/utils/AudioBus.h>
|
|
6
|
+
#include <gtest/gtest.h>
|
|
7
|
+
#include <test/src/MockAudioEventHandlerRegistry.h>
|
|
8
|
+
|
|
9
|
+
using namespace audioapi;
|
|
10
|
+
static constexpr int SAMPLE_RATE = 44100;
|
|
11
|
+
static constexpr int RENDER_QUANTUM = 128;
|
|
12
|
+
static constexpr double RENDER_QUANTUM_TIME =
|
|
13
|
+
static_cast<double>(RENDER_QUANTUM) / SAMPLE_RATE;
|
|
14
|
+
|
|
15
|
+
class AudioScheduledSourceTest : public ::testing::Test {
|
|
16
|
+
protected:
|
|
17
|
+
std::shared_ptr<MockAudioEventHandlerRegistry> eventRegistry;
|
|
18
|
+
std::unique_ptr<OfflineAudioContext> context;
|
|
19
|
+
|
|
20
|
+
void SetUp() override {
|
|
21
|
+
eventRegistry = std::make_shared<MockAudioEventHandlerRegistry>();
|
|
22
|
+
context = std::make_unique<OfflineAudioContext>(
|
|
23
|
+
2, 5 * SAMPLE_RATE, SAMPLE_RATE, eventRegistry, RuntimeRegistry{});
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
class TestableAudioScheduledSourceNode : public AudioScheduledSourceNode {
|
|
28
|
+
public:
|
|
29
|
+
explicit TestableAudioScheduledSourceNode(BaseAudioContext *context)
|
|
30
|
+
: AudioScheduledSourceNode(context) {
|
|
31
|
+
isInitialized_ = true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
void updatePlaybackInfo(
|
|
35
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
36
|
+
int framesToProcess,
|
|
37
|
+
size_t &startOffset,
|
|
38
|
+
size_t &nonSilentFramesToProcess) {
|
|
39
|
+
AudioScheduledSourceNode::updatePlaybackInfo(
|
|
40
|
+
processingBus, framesToProcess, startOffset, nonSilentFramesToProcess);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
std::shared_ptr<AudioBus> processNode(const std::shared_ptr<AudioBus> &, int)
|
|
44
|
+
override {
|
|
45
|
+
return nullptr;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
PlaybackState getPlaybackState() const {
|
|
49
|
+
return playbackState_;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void playFrames(int frames) {
|
|
53
|
+
size_t startOffset = 0;
|
|
54
|
+
size_t nonSilentFramesToProcess = 0;
|
|
55
|
+
auto processingBus =
|
|
56
|
+
std::make_shared<AudioBus>(128, 2, static_cast<float>(SAMPLE_RATE));
|
|
57
|
+
updatePlaybackInfo(
|
|
58
|
+
processingBus, frames, startOffset, nonSilentFramesToProcess);
|
|
59
|
+
context_->getDestination()->renderAudio(processingBus, frames);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
TEST_F(AudioScheduledSourceTest, IsUnscheduledStateSetCorrectly) {
|
|
64
|
+
auto sourceNode = TestableAudioScheduledSourceNode(context.get());
|
|
65
|
+
EXPECT_EQ(
|
|
66
|
+
sourceNode.getPlaybackState(),
|
|
67
|
+
AudioScheduledSourceNode::PlaybackState::UNSCHEDULED);
|
|
68
|
+
|
|
69
|
+
sourceNode.start(RENDER_QUANTUM_TIME);
|
|
70
|
+
EXPECT_NE(
|
|
71
|
+
sourceNode.getPlaybackState(),
|
|
72
|
+
AudioScheduledSourceNode::PlaybackState::UNSCHEDULED);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
TEST_F(AudioScheduledSourceTest, IsScheduledStateSetCorrectly) {
|
|
76
|
+
auto sourceNode = TestableAudioScheduledSourceNode(context.get());
|
|
77
|
+
sourceNode.start(RENDER_QUANTUM_TIME);
|
|
78
|
+
EXPECT_EQ(
|
|
79
|
+
sourceNode.getPlaybackState(),
|
|
80
|
+
AudioScheduledSourceNode::PlaybackState::SCHEDULED);
|
|
81
|
+
|
|
82
|
+
sourceNode.playFrames(RENDER_QUANTUM);
|
|
83
|
+
EXPECT_EQ(
|
|
84
|
+
sourceNode.getPlaybackState(),
|
|
85
|
+
AudioScheduledSourceNode::PlaybackState::SCHEDULED);
|
|
86
|
+
|
|
87
|
+
sourceNode.playFrames(1);
|
|
88
|
+
EXPECT_NE(
|
|
89
|
+
sourceNode.getPlaybackState(),
|
|
90
|
+
AudioScheduledSourceNode::PlaybackState::SCHEDULED);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
TEST_F(AudioScheduledSourceTest, IsPlayingStateSetCorrectly) {
|
|
94
|
+
auto sourceNode = TestableAudioScheduledSourceNode(context.get());
|
|
95
|
+
sourceNode.start(0);
|
|
96
|
+
sourceNode.stop(RENDER_QUANTUM_TIME);
|
|
97
|
+
|
|
98
|
+
sourceNode.playFrames(RENDER_QUANTUM);
|
|
99
|
+
EXPECT_EQ(
|
|
100
|
+
sourceNode.getPlaybackState(),
|
|
101
|
+
AudioScheduledSourceNode::PlaybackState::PLAYING);
|
|
102
|
+
|
|
103
|
+
sourceNode.playFrames(1);
|
|
104
|
+
EXPECT_NE(
|
|
105
|
+
sourceNode.getPlaybackState(),
|
|
106
|
+
AudioScheduledSourceNode::PlaybackState::PLAYING);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
TEST_F(AudioScheduledSourceTest, IsStopScheduledStateSetCorrectly) {
|
|
110
|
+
auto sourceNode = TestableAudioScheduledSourceNode(context.get());
|
|
111
|
+
sourceNode.start(0);
|
|
112
|
+
sourceNode.stop(RENDER_QUANTUM_TIME);
|
|
113
|
+
sourceNode.playFrames(1); // start playing
|
|
114
|
+
sourceNode.playFrames(RENDER_QUANTUM);
|
|
115
|
+
EXPECT_EQ(
|
|
116
|
+
sourceNode.getPlaybackState(),
|
|
117
|
+
AudioScheduledSourceNode::PlaybackState::STOP_SCHEDULED);
|
|
118
|
+
|
|
119
|
+
sourceNode.playFrames(1);
|
|
120
|
+
EXPECT_NE(
|
|
121
|
+
sourceNode.getPlaybackState(),
|
|
122
|
+
AudioScheduledSourceNode::PlaybackState::STOP_SCHEDULED);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
TEST_F(AudioScheduledSourceTest, IsFinishedStateSetCorrectly) {
|
|
126
|
+
auto sourceNode = TestableAudioScheduledSourceNode(context.get());
|
|
127
|
+
sourceNode.start(0);
|
|
128
|
+
sourceNode.stop(RENDER_QUANTUM_TIME);
|
|
129
|
+
sourceNode.playFrames(1); // start playing
|
|
130
|
+
|
|
131
|
+
sourceNode.playFrames(RENDER_QUANTUM);
|
|
132
|
+
sourceNode.playFrames(1);
|
|
133
|
+
EXPECT_TRUE(sourceNode.isFinished());
|
|
134
|
+
}
|
|
@@ -10,7 +10,7 @@ using namespace audioapi;
|
|
|
10
10
|
|
|
11
11
|
class ConstantSourceTest : public ::testing::Test {
|
|
12
12
|
protected:
|
|
13
|
-
std::shared_ptr<
|
|
13
|
+
std::shared_ptr<MockAudioEventHandlerRegistry> eventRegistry;
|
|
14
14
|
std::unique_ptr<OfflineAudioContext> context;
|
|
15
15
|
static constexpr int sampleRate = 44100;
|
|
16
16
|
|
|
@@ -10,7 +10,7 @@ using namespace audioapi;
|
|
|
10
10
|
|
|
11
11
|
class GainTest : public ::testing::Test {
|
|
12
12
|
protected:
|
|
13
|
-
std::shared_ptr<
|
|
13
|
+
std::shared_ptr<MockAudioEventHandlerRegistry> eventRegistry;
|
|
14
14
|
std::unique_ptr<OfflineAudioContext> context;
|
|
15
15
|
static constexpr int sampleRate = 44100;
|
|
16
16
|
|
|
@@ -17,8 +17,8 @@ class MockAudioEventHandlerRegistry : public IAudioEventHandlerRegistry {
|
|
|
17
17
|
MOCK_METHOD(void, unregisterHandler,
|
|
18
18
|
(const std::string &eventName, uint64_t listenerId), (override));
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
(const std::string &eventName, const EventMap &body)
|
|
22
|
-
|
|
23
|
-
(const std::string &eventName, uint64_t listenerId, const EventMap &body)
|
|
20
|
+
MOCK_METHOD2(invokeHandlerWithEventBody, void
|
|
21
|
+
(const std::string &eventName, const EventMap &body));
|
|
22
|
+
MOCK_METHOD3(invokeHandlerWithEventBody, void
|
|
23
|
+
(const std::string &eventName, uint64_t listenerId, const EventMap &body));
|
|
24
24
|
};
|
|
@@ -8,7 +8,7 @@ using namespace audioapi;
|
|
|
8
8
|
|
|
9
9
|
class OscillatorTest : public ::testing::Test {
|
|
10
10
|
protected:
|
|
11
|
-
std::shared_ptr<
|
|
11
|
+
std::shared_ptr<MockAudioEventHandlerRegistry> eventRegistry;
|
|
12
12
|
std::unique_ptr<OfflineAudioContext> context;
|
|
13
13
|
static constexpr int sampleRate = 44100;
|
|
14
14
|
|
|
@@ -10,7 +10,7 @@ using namespace audioapi;
|
|
|
10
10
|
|
|
11
11
|
class StereoPannerTest : public ::testing::Test {
|
|
12
12
|
protected:
|
|
13
|
-
std::shared_ptr<
|
|
13
|
+
std::shared_ptr<MockAudioEventHandlerRegistry> eventRegistry;
|
|
14
14
|
std::unique_ptr<OfflineAudioContext> context;
|
|
15
15
|
static constexpr int sampleRate = 44100;
|
|
16
16
|
|
|
@@ -14,7 +14,7 @@ static constexpr float tolerance = 0.0001f;
|
|
|
14
14
|
namespace audioapi {
|
|
15
15
|
class BiquadFilterTest : public ::testing::Test {
|
|
16
16
|
protected:
|
|
17
|
-
std::shared_ptr<
|
|
17
|
+
std::shared_ptr<MockAudioEventHandlerRegistry> eventRegistry;
|
|
18
18
|
std::unique_ptr<OfflineAudioContext> context;
|
|
19
19
|
|
|
20
20
|
void SetUp() override {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-audio-api",
|
|
3
|
-
"version": "0.10.0-nightly-
|
|
3
|
+
"version": "0.10.0-nightly-98d2e0d-20251106",
|
|
4
4
|
"description": "react-native-audio-api provides system for controlling audio in React Native environment compatible with Web Audio API specification",
|
|
5
5
|
"bin": {
|
|
6
6
|
"setup-rn-audio-api-web": "./scripts/setup-rn-audio-api-web.js"
|