react-native-audio-api 0.6.0 → 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.
- package/README.md +6 -11
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +13 -8
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +3 -2
- package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +27 -10
- package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +12 -3
- package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +2 -2
- package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionCallback.kt +4 -6
- package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +1 -1
- package/android/src/main/res/drawable/skip_backward_10.xml +9 -0
- package/android/src/main/res/drawable/skip_forward_10.xml +9 -0
- package/android/src/oldarch/NativeAudioAPIModuleSpec.java +68 -64
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +2 -1
- package/common/cpp/audioapi/HostObjects/AudioBufferQueueSourceNodeHostObject.h +94 -0
- package/common/cpp/audioapi/HostObjects/AudioContextHostObject.h +7 -7
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +9 -0
- package/common/cpp/audioapi/core/AudioContext.cpp +29 -4
- package/common/cpp/audioapi/core/AudioContext.h +2 -1
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +12 -0
- package/common/cpp/audioapi/core/BaseAudioContext.h +4 -3
- package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -0
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +236 -0
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +72 -0
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +1 -1
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +11 -3
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +3 -4
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +2 -1
- package/ios/audioapi/ios/AudioAPIModule.mm +28 -15
- package/ios/audioapi/ios/core/IOSAudioPlayer.h +3 -2
- package/ios/audioapi/ios/core/IOSAudioPlayer.mm +21 -10
- package/ios/audioapi/ios/core/NativeAudioPlayer.h +4 -0
- package/ios/audioapi/ios/core/NativeAudioPlayer.m +15 -0
- package/ios/audioapi/ios/system/AudioEngine.h +1 -0
- package/ios/audioapi/ios/system/AudioEngine.mm +11 -1
- package/ios/audioapi/ios/system/AudioSessionManager.mm +1 -1
- package/ios/audioapi/ios/system/LockScreenManager.mm +13 -1
- package/ios/audioapi/ios/system/NotificationManager.mm +1 -1
- package/lib/commonjs/api.js +7 -0
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/core/AudioBufferQueueSourceNode.js +46 -0
- package/lib/commonjs/core/AudioBufferQueueSourceNode.js.map +1 -0
- package/lib/commonjs/core/AudioContext.js +2 -2
- package/lib/commonjs/core/AudioContext.js.map +1 -1
- package/lib/commonjs/core/AudioNode.js +5 -1
- package/lib/commonjs/core/AudioNode.js.map +1 -1
- package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/commonjs/core/BaseAudioContext.js +4 -0
- package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
- package/lib/commonjs/hooks/useSytemVolume.js +1 -1
- package/lib/commonjs/hooks/useSytemVolume.js.map +1 -1
- package/lib/commonjs/plugin/withAudioAPI.js +15 -14
- package/lib/commonjs/plugin/withAudioAPI.js.map +1 -1
- package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
- package/lib/commonjs/system/AudioManager.js +12 -10
- package/lib/commonjs/system/AudioManager.js.map +1 -1
- package/lib/commonjs/web-core/AudioBufferSourceNode.js +4 -4
- package/lib/commonjs/web-core/AudioBufferSourceNode.js.map +1 -1
- package/lib/commonjs/web-core/AudioContext.js +5 -3
- package/lib/commonjs/web-core/AudioContext.js.map +1 -1
- package/lib/commonjs/web-core/AudioNode.js +8 -2
- package/lib/commonjs/web-core/AudioNode.js.map +1 -1
- package/lib/commonjs/web-core/AudioParam.js +2 -1
- package/lib/commonjs/web-core/AudioParam.js.map +1 -1
- package/lib/commonjs/web-core/BiquadFilterNode.js +4 -4
- package/lib/commonjs/web-core/BiquadFilterNode.js.map +1 -1
- package/lib/commonjs/web-core/GainNode.js +1 -1
- package/lib/commonjs/web-core/GainNode.js.map +1 -1
- package/lib/commonjs/web-core/OscillatorNode.js +2 -2
- package/lib/commonjs/web-core/OscillatorNode.js.map +1 -1
- package/lib/commonjs/web-core/StereoPannerNode.js +1 -1
- package/lib/commonjs/web-core/StereoPannerNode.js.map +1 -1
- package/lib/module/api.js +1 -0
- package/lib/module/api.js.map +1 -1
- package/lib/module/core/AudioBufferQueueSourceNode.js +40 -0
- package/lib/module/core/AudioBufferQueueSourceNode.js.map +1 -0
- package/lib/module/core/AudioContext.js +2 -2
- package/lib/module/core/AudioContext.js.map +1 -1
- package/lib/module/core/AudioNode.js +5 -1
- package/lib/module/core/AudioNode.js.map +1 -1
- package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/module/core/BaseAudioContext.js +4 -0
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/hooks/useSytemVolume.js +1 -1
- package/lib/module/hooks/useSytemVolume.js.map +1 -1
- package/lib/module/plugin/withAudioAPI.js +15 -14
- package/lib/module/plugin/withAudioAPI.js.map +1 -1
- package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
- package/lib/module/system/AudioManager.js +12 -10
- package/lib/module/system/AudioManager.js.map +1 -1
- package/lib/module/web-core/AudioBufferSourceNode.js +4 -4
- package/lib/module/web-core/AudioBufferSourceNode.js.map +1 -1
- package/lib/module/web-core/AudioContext.js +5 -3
- package/lib/module/web-core/AudioContext.js.map +1 -1
- package/lib/module/web-core/AudioNode.js +7 -2
- package/lib/module/web-core/AudioNode.js.map +1 -1
- package/lib/module/web-core/AudioParam.js +2 -1
- package/lib/module/web-core/AudioParam.js.map +1 -1
- package/lib/module/web-core/BiquadFilterNode.js +4 -4
- package/lib/module/web-core/BiquadFilterNode.js.map +1 -1
- package/lib/module/web-core/GainNode.js +1 -1
- package/lib/module/web-core/GainNode.js.map +1 -1
- package/lib/module/web-core/OscillatorNode.js +2 -2
- package/lib/module/web-core/OscillatorNode.js.map +1 -1
- package/lib/module/web-core/StereoPannerNode.js +1 -1
- package/lib/module/web-core/StereoPannerNode.js.map +1 -1
- package/lib/typescript/api.d.ts +2 -1
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts +16 -0
- package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts.map +1 -0
- package/lib/typescript/core/AudioContext.d.ts.map +1 -1
- package/lib/typescript/core/AudioNode.d.ts +1 -1
- package/lib/typescript/core/AudioNode.d.ts.map +1 -1
- package/lib/typescript/core/AudioScheduledSourceNode.d.ts +4 -3
- package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -1
- package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/events/types.d.ts +21 -8
- package/lib/typescript/events/types.d.ts.map +1 -1
- package/lib/typescript/hooks/useSytemVolume.d.ts.map +1 -1
- package/lib/typescript/interfaces.d.ts +9 -0
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/plugin/withAudioAPI.d.ts +7 -6
- package/lib/typescript/plugin/withAudioAPI.d.ts.map +1 -1
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts +3 -2
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
- package/lib/typescript/system/AudioManager.d.ts +6 -4
- package/lib/typescript/system/AudioManager.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +2 -1
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioBufferSourceNode.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioContext.d.ts +1 -1
- package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioNode.d.ts +2 -1
- package/lib/typescript/web-core/AudioNode.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioParam.d.ts +4 -2
- package/lib/typescript/web-core/AudioParam.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/api.ts +5 -1
- package/src/core/AudioBufferQueueSourceNode.ts +71 -0
- package/src/core/AudioContext.ts +7 -2
- package/src/core/AudioNode.ts +6 -2
- package/src/core/AudioScheduledSourceNode.ts +3 -3
- package/src/core/BaseAudioContext.ts +8 -0
- package/src/events/types.ts +33 -8
- package/src/hooks/useSytemVolume.ts +6 -3
- package/src/interfaces.ts +18 -0
- package/src/plugin/withAudioAPI.ts +36 -29
- package/src/specs/NativeAudioAPIModule.ts +14 -6
- package/src/system/AudioManager.ts +21 -16
- package/src/types.ts +2 -1
- package/src/web-core/AudioBufferSourceNode.tsx +9 -4
- package/src/web-core/AudioContext.tsx +7 -3
- package/src/web-core/AudioNode.tsx +10 -3
- package/src/web-core/AudioParam.tsx +5 -2
- package/src/web-core/BiquadFilterNode.tsx +4 -4
- package/src/web-core/GainNode.tsx +1 -1
- package/src/web-core/OscillatorNode.tsx +2 -2
- package/src/web-core/StereoPannerNode.tsx +1 -1
- package/android/src/main/res/drawable/skip_backward_5.xml +0 -9
- 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
|
-
|
|
83
|
-
friend class AudioScheduledSourceNode;
|
|
84
|
-
|
|
85
|
+
public:
|
|
85
86
|
std::shared_ptr<AudioEventHandlerRegistry> audioEventHandlerRegistry_;
|
|
86
87
|
};
|
|
87
88
|
|
|
@@ -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
|
|
|
@@ -144,7 +144,15 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
|
|
|
144
144
|
void AudioScheduledSourceNode::disable() {
|
|
145
145
|
AudioNode::disable();
|
|
146
146
|
|
|
147
|
-
std::
|
|
147
|
+
std::string state = "stopped";
|
|
148
|
+
|
|
149
|
+
// if it has not been stopped, it is ended
|
|
150
|
+
if (stopTime_ < 0) {
|
|
151
|
+
state = "ended";
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
std::unordered_map<std::string, EventValue> body = {
|
|
155
|
+
{"value", getStopTime()}, {"state", state}};
|
|
148
156
|
|
|
149
157
|
context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
|
|
150
158
|
"ended", onEndedCallbackId_, body);
|
|
@@ -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,
|
|
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
|
-
|
|
83
|
+
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getDevicePreferredSampleRate)
|
|
84
84
|
{
|
|
85
|
-
[self.
|
|
85
|
+
return [self.audioSessionManager getDevicePreferredSampleRate];
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
RCT_EXPORT_METHOD(
|
|
88
|
+
RCT_EXPORT_METHOD(
|
|
89
|
+
setAudioSessionActivity : (BOOL)enabled resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)
|
|
90
|
+
reject)
|
|
89
91
|
{
|
|
90
|
-
[self.
|
|
91
|
-
|
|
92
|
+
if ([self.audioSessionManager setActive:enabled]) {
|
|
93
|
+
resolve(@"true");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
92
96
|
|
|
93
|
-
|
|
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
|
-
|
|
105
|
+
RCT_EXPORT_METHOD(setLockScreenInfo : (NSDictionary *)info)
|
|
104
106
|
{
|
|
105
|
-
|
|
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)
|
|
@@ -115,15 +127,16 @@ RCT_EXPORT_METHOD(observeVolumeChanges : (BOOL)enabled)
|
|
|
115
127
|
[self.notificationManager observeVolumeChanges:(BOOL)enabled];
|
|
116
128
|
}
|
|
117
129
|
|
|
118
|
-
RCT_EXPORT_METHOD(
|
|
119
|
-
|
|
130
|
+
RCT_EXPORT_METHOD(
|
|
131
|
+
requestRecordingPermissions : (nonnull RCTPromiseResolveBlock)resolve reject : (nonnull RCTPromiseRejectBlock)
|
|
132
|
+
reject)
|
|
120
133
|
{
|
|
121
134
|
NSString *res = [self.audioSessionManager requestRecordingPermissions];
|
|
122
135
|
resolve(res);
|
|
123
136
|
}
|
|
124
137
|
|
|
125
|
-
RCT_EXPORT_METHOD(
|
|
126
|
-
|
|
138
|
+
RCT_EXPORT_METHOD(
|
|
139
|
+
checkRecordingPermissions : (nonnull RCTPromiseResolveBlock)resolve reject : (nonnull RCTPromiseRejectBlock)reject)
|
|
127
140
|
{
|
|
128
141
|
NSString *res = [self.audioSessionManager checkRecordingPermissions];
|
|
129
142
|
resolve(res);
|
|
@@ -158,7 +171,7 @@ RCT_EXPORT_METHOD(checkRecordingPermissions : (nonnull RCTPromiseResolveBlock)
|
|
|
158
171
|
body[stdKey] = EventValue([value doubleValue]);
|
|
159
172
|
} else if (strcmp(type, @encode(float)) == 0) {
|
|
160
173
|
body[stdKey] = EventValue([value floatValue]);
|
|
161
|
-
} else
|
|
174
|
+
} else {
|
|
162
175
|
body[stdKey] = EventValue([value boolValue]);
|
|
163
176
|
}
|
|
164
177
|
}
|
|
@@ -43,12 +43,7 @@ IOSAudioPlayer::IOSAudioPlayer(const std::function<void(std::shared_ptr<AudioBus
|
|
|
43
43
|
|
|
44
44
|
IOSAudioPlayer::~IOSAudioPlayer()
|
|
45
45
|
{
|
|
46
|
-
|
|
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::
|
|
75
|
+
void IOSAudioPlayer::suspend()
|
|
70
76
|
{
|
|
71
77
|
isRunning_.store(false);
|
|
72
|
-
[audioPlayer_
|
|
78
|
+
[audioPlayer_ suspend];
|
|
73
79
|
}
|
|
74
80
|
|
|
75
|
-
void IOSAudioPlayer::
|
|
81
|
+
void IOSAudioPlayer::cleanup()
|
|
76
82
|
{
|
|
77
|
-
|
|
83
|
+
stop();
|
|
84
|
+
[audioPlayer_ cleanup];
|
|
85
|
+
|
|
86
|
+
if (audioBus_) {
|
|
87
|
+
audioBus_ = nullptr;
|
|
88
|
+
}
|
|
78
89
|
}
|
|
79
90
|
|
|
80
91
|
} // namespace audioapi
|
|
@@ -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;
|