react-native-audio-api 0.6.0-rc.0 → 0.6.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -22
- package/android/CMakeLists.txt +6 -3
- package/android/build.gradle +1 -0
- package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +73 -0
- package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.h +37 -0
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +6 -10
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +2 -3
- package/android/src/main/java/com/swmansion/audioapi/AudioManagerModule.kt +19 -14
- package/android/src/main/java/com/swmansion/audioapi/system/AudioFocusListener.kt +60 -0
- package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +294 -0
- package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +279 -0
- package/android/src/main/java/com/swmansion/audioapi/system/MediaReceiver.kt +46 -0
- package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionCallback.kt +39 -0
- package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionEventEmitter.kt +88 -0
- package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +162 -0
- package/android/src/main/java/com/swmansion/audioapi/system/VolumeChangeListener.kt +27 -0
- package/android/src/main/res/drawable/next.xml +9 -0
- package/android/src/main/res/drawable/pause.xml +9 -0
- package/android/src/main/res/drawable/play.xml +9 -0
- package/android/src/main/res/drawable/previous.xml +9 -0
- package/android/src/main/res/drawable/skip_backward_5.xml +9 -0
- package/android/src/main/res/drawable/skip_forward_5.xml +9 -0
- package/android/src/main/res/drawable/stop.xml +9 -0
- package/app.plugin.js +1 -0
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +29 -5
- package/common/cpp/audioapi/HostObjects/AnalyserNodeHostObject.h +1 -0
- package/common/cpp/audioapi/HostObjects/AudioRecorderHostObject.h +149 -0
- package/common/cpp/audioapi/core/AudioContext.cpp +4 -3
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +6 -6
- package/common/cpp/audioapi/core/inputs/AudioRecorder.h +38 -0
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +1 -6
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +8 -4
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +6 -0
- package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +1 -1
- package/common/cpp/audioapi/core/utils/AudioNodeDestructor.cpp +3 -3
- package/common/cpp/audioapi/core/utils/AudioNodeManager.cpp +45 -11
- package/common/cpp/audioapi/core/utils/AudioNodeManager.h +6 -2
- package/ios/audioapi/ios/AudioManagerModule.mm +16 -15
- package/ios/audioapi/ios/core/IOSAudioPlayer.h +11 -12
- package/ios/audioapi/ios/core/IOSAudioPlayer.mm +22 -16
- package/ios/audioapi/ios/core/IOSAudioRecorder.h +36 -0
- package/ios/audioapi/ios/core/IOSAudioRecorder.mm +62 -0
- package/ios/audioapi/ios/core/{AudioPlayer.h → NativeAudioPlayer.h} +1 -8
- package/ios/audioapi/ios/core/{AudioPlayer.m → NativeAudioPlayer.m} +4 -33
- package/ios/audioapi/ios/core/NativeAudioRecorder.h +25 -0
- package/ios/audioapi/ios/core/NativeAudioRecorder.m +47 -0
- package/ios/audioapi/ios/system/AudioEngine.h +7 -1
- package/ios/audioapi/ios/system/AudioEngine.mm +64 -20
- package/ios/audioapi/ios/system/AudioSessionManager.h +3 -1
- package/ios/audioapi/ios/system/AudioSessionManager.mm +37 -25
- package/ios/audioapi/ios/system/LockScreenManager.mm +4 -8
- package/ios/audioapi/ios/system/NotificationManager.h +13 -1
- package/ios/audioapi/ios/system/NotificationManager.mm +96 -44
- package/lib/commonjs/api.js +211 -0
- package/lib/commonjs/api.js.map +1 -0
- package/lib/commonjs/api.web.js +219 -0
- package/lib/commonjs/api.web.js.map +1 -0
- package/lib/commonjs/core/AnalyserNode.js +71 -0
- package/lib/commonjs/core/AnalyserNode.js.map +1 -0
- package/lib/commonjs/core/AudioBuffer.js +44 -0
- package/lib/commonjs/core/AudioBuffer.js.map +1 -0
- package/lib/commonjs/core/AudioBufferSourceNode.js +68 -0
- package/lib/commonjs/core/AudioBufferSourceNode.js.map +1 -0
- package/lib/commonjs/core/AudioContext.js +29 -0
- package/lib/commonjs/core/AudioContext.js.map +1 -0
- package/lib/commonjs/core/AudioDestinationNode.js +11 -0
- package/lib/commonjs/core/AudioDestinationNode.js.map +1 -0
- package/lib/commonjs/core/AudioNode.js +30 -0
- package/lib/commonjs/core/AudioNode.js.map +1 -0
- package/lib/commonjs/core/AudioParam.js +82 -0
- package/lib/commonjs/core/AudioParam.js.map +1 -0
- package/lib/commonjs/core/AudioRecorder.js +51 -0
- package/lib/commonjs/core/AudioRecorder.js.map +1 -0
- package/lib/commonjs/core/AudioScheduledSourceNode.js +38 -0
- package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -0
- package/lib/commonjs/core/BaseAudioContext.js +80 -0
- package/lib/commonjs/core/BaseAudioContext.js.map +1 -0
- package/lib/commonjs/core/BiquadFilterNode.js +33 -0
- package/lib/commonjs/core/BiquadFilterNode.js.map +1 -0
- package/lib/commonjs/core/GainNode.js +17 -0
- package/lib/commonjs/core/GainNode.js.map +1 -0
- package/lib/commonjs/core/OfflineAudioContext.js +63 -0
- package/lib/commonjs/core/OfflineAudioContext.js.map +1 -0
- package/lib/commonjs/core/OscillatorNode.js +32 -0
- package/lib/commonjs/core/OscillatorNode.js.map +1 -0
- package/lib/commonjs/core/PeriodicWave.js +15 -0
- package/lib/commonjs/core/PeriodicWave.js.map +1 -0
- package/lib/commonjs/core/StereoPannerNode.js +17 -0
- package/lib/commonjs/core/StereoPannerNode.js.map +1 -0
- package/lib/commonjs/errors/IndexSizeError.js +14 -0
- package/lib/commonjs/errors/IndexSizeError.js.map +1 -0
- package/lib/commonjs/errors/InvalidAccessError.js +14 -0
- package/lib/commonjs/errors/InvalidAccessError.js.map +1 -0
- package/lib/commonjs/errors/InvalidStateError.js +14 -0
- package/lib/commonjs/errors/InvalidStateError.js.map +1 -0
- package/lib/commonjs/errors/NotSupportedError.js +14 -0
- package/lib/commonjs/errors/NotSupportedError.js.map +1 -0
- package/lib/commonjs/errors/RangeError.js +14 -0
- package/lib/commonjs/errors/RangeError.js.map +1 -0
- package/lib/commonjs/errors/index.js +42 -0
- package/lib/commonjs/errors/index.js.map +1 -0
- package/lib/commonjs/hooks/useSytemVolume.js +24 -0
- package/lib/commonjs/hooks/useSytemVolume.js.map +1 -0
- package/lib/commonjs/index.js +17 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/interfaces.js +6 -0
- package/lib/commonjs/interfaces.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/plugin/withAudioAPI.js +62 -0
- package/lib/commonjs/plugin/withAudioAPI.js.map +1 -0
- package/lib/commonjs/specs/NativeAudioAPIModule.js +9 -0
- package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -0
- package/lib/commonjs/specs/NativeAudioManagerModule.js +36 -0
- package/lib/commonjs/specs/NativeAudioManagerModule.js.map +1 -0
- package/lib/commonjs/specs/index.js +27 -0
- package/lib/commonjs/specs/index.js.map +1 -0
- package/lib/commonjs/system/AudioManager.js +52 -0
- package/lib/commonjs/system/AudioManager.js.map +1 -0
- package/lib/commonjs/system/index.js +14 -0
- package/lib/commonjs/system/index.js.map +1 -0
- package/lib/commonjs/system/types.js +2 -0
- package/lib/commonjs/system/types.js.map +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/utils/index.js +10 -0
- package/lib/commonjs/utils/index.js.map +1 -0
- package/lib/commonjs/web-core/AnalyserNode.js +38 -0
- package/lib/commonjs/web-core/AnalyserNode.js.map +1 -0
- package/lib/commonjs/web-core/AudioBuffer.js +44 -0
- package/lib/commonjs/web-core/AudioBuffer.js.map +1 -0
- package/lib/commonjs/web-core/AudioBufferSourceNode.js +214 -0
- package/lib/commonjs/web-core/AudioBufferSourceNode.js.map +1 -0
- package/lib/commonjs/web-core/AudioContext.js +93 -0
- package/lib/commonjs/web-core/AudioContext.js.map +1 -0
- package/lib/commonjs/web-core/AudioDestinationNode.js +11 -0
- package/lib/commonjs/web-core/AudioDestinationNode.js.map +1 -0
- package/lib/commonjs/web-core/AudioNode.js +33 -0
- package/lib/commonjs/web-core/AudioNode.js.map +1 -0
- package/lib/commonjs/web-core/AudioParam.js +81 -0
- package/lib/commonjs/web-core/AudioParam.js.map +1 -0
- package/lib/commonjs/web-core/AudioScheduledSourceNode.js +41 -0
- package/lib/commonjs/web-core/AudioScheduledSourceNode.js.map +1 -0
- package/lib/commonjs/web-core/BaseAudioContext.js +2 -0
- package/lib/commonjs/web-core/BaseAudioContext.js.map +1 -0
- package/lib/commonjs/web-core/BiquadFilterNode.js +33 -0
- package/lib/commonjs/web-core/BiquadFilterNode.js.map +1 -0
- package/lib/commonjs/web-core/GainNode.js +17 -0
- package/lib/commonjs/web-core/GainNode.js.map +1 -0
- package/lib/commonjs/web-core/OfflineAudioContext.js +96 -0
- package/lib/commonjs/web-core/OfflineAudioContext.js.map +1 -0
- package/lib/commonjs/web-core/OscillatorNode.js +31 -0
- package/lib/commonjs/web-core/OscillatorNode.js.map +1 -0
- package/lib/commonjs/web-core/PeriodicWave.js +15 -0
- package/lib/commonjs/web-core/PeriodicWave.js.map +1 -0
- package/lib/commonjs/web-core/StereoPannerNode.js +17 -0
- package/lib/commonjs/web-core/StereoPannerNode.js.map +1 -0
- package/lib/commonjs/web-core/custom/LoadCustomWasm.js +37 -0
- package/lib/commonjs/web-core/custom/LoadCustomWasm.js.map +1 -0
- package/lib/commonjs/web-core/custom/index.js +14 -0
- package/lib/commonjs/web-core/custom/index.js.map +1 -0
- package/lib/commonjs/web-core/custom/signalsmithStretch/LICENSE.txt +21 -0
- package/lib/commonjs/web-core/custom/signalsmithStretch/README.md +46 -0
- package/lib/commonjs/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs +826 -0
- package/lib/commonjs/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs.map +1 -0
- package/lib/module/api.js +3 -1
- package/lib/module/api.js.map +1 -1
- package/lib/module/core/AudioRecorder.js +45 -0
- package/lib/module/core/AudioRecorder.js.map +1 -0
- package/lib/module/errors/NotSupportedError.js.map +1 -1
- package/lib/module/hooks/useSytemVolume.js +19 -0
- package/lib/module/hooks/useSytemVolume.js.map +1 -0
- package/lib/module/plugin/withAudioAPI.js +58 -0
- package/lib/module/plugin/withAudioAPI.js.map +1 -0
- package/lib/module/specs/NativeAudioManagerModule.js +10 -8
- package/lib/module/specs/NativeAudioManagerModule.js.map +1 -1
- package/lib/module/system/AudioManager.js +26 -44
- package/lib/module/system/AudioManager.js.map +1 -1
- package/lib/typescript/api.d.ts +5 -1
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/core/AudioRecorder.d.ts +22 -0
- package/lib/typescript/core/AudioRecorder.d.ts.map +1 -0
- package/lib/typescript/errors/NotSupportedError.d.ts.map +1 -1
- package/lib/typescript/hooks/useSytemVolume.d.ts +2 -0
- package/lib/typescript/hooks/useSytemVolume.d.ts.map +1 -0
- package/lib/typescript/interfaces.d.ts +11 -5
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/plugin/withAudioAPI.d.ts +9 -0
- package/lib/typescript/plugin/withAudioAPI.d.ts.map +1 -0
- package/lib/typescript/specs/NativeAudioManagerModule.d.ts +4 -2
- package/lib/typescript/specs/NativeAudioManagerModule.d.ts.map +1 -1
- package/lib/typescript/system/AudioManager.d.ts +5 -2
- package/lib/typescript/system/AudioManager.d.ts.map +1 -1
- package/lib/typescript/system/types.d.ts +36 -5
- package/lib/typescript/system/types.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +5 -0
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +7 -3
- package/src/api.ts +13 -2
- package/src/core/AudioRecorder.ts +81 -0
- package/src/hooks/useSytemVolume.ts +19 -0
- package/src/interfaces.ts +25 -11
- package/src/plugin/withAudioAPI.ts +91 -0
- package/src/specs/NativeAudioManagerModule.ts +13 -19
- package/src/system/AudioManager.ts +37 -87
- package/src/system/types.ts +43 -17
- package/src/types.ts +13 -0
- /package/src/errors/{NotSupportedError.tsx → NotSupportedError.ts} +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <memory>
|
|
4
|
+
#include <functional>
|
|
5
|
+
|
|
6
|
+
namespace audioapi {
|
|
7
|
+
class AudioBus;
|
|
8
|
+
|
|
9
|
+
class AudioRecorder {
|
|
10
|
+
public:
|
|
11
|
+
explicit AudioRecorder(
|
|
12
|
+
float sampleRate,
|
|
13
|
+
int bufferLength,
|
|
14
|
+
const std::function<void(void)> &onError,
|
|
15
|
+
const std::function<void(void)> &onStatusChange,
|
|
16
|
+
const std::function<void(std::shared_ptr<AudioBus>, int, double)> &onAudioReady
|
|
17
|
+
)
|
|
18
|
+
: sampleRate_(sampleRate),
|
|
19
|
+
bufferLength_(bufferLength),
|
|
20
|
+
onError_(onError),
|
|
21
|
+
onStatusChange_(onStatusChange),
|
|
22
|
+
onAudioReady_(onAudioReady) {}
|
|
23
|
+
|
|
24
|
+
virtual ~AudioRecorder() = default;
|
|
25
|
+
|
|
26
|
+
virtual void start() = 0;
|
|
27
|
+
virtual void stop() = 0;
|
|
28
|
+
|
|
29
|
+
protected:
|
|
30
|
+
float sampleRate_;
|
|
31
|
+
int bufferLength_;
|
|
32
|
+
|
|
33
|
+
std::function<void(void)> onError_;
|
|
34
|
+
std::function<void(void)> onStatusChange_;
|
|
35
|
+
std::function<void(std::shared_ptr<AudioBus>, int, double)> onAudioReady_;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
} // namespace audioapi
|
|
@@ -128,12 +128,7 @@ void AudioBufferSourceNode::start(double when, double offset, double duration) {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
void AudioBufferSourceNode::disable() {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (onendedCallback_) {
|
|
134
|
-
onendedCallback_(getStopTime());
|
|
135
|
-
}
|
|
136
|
-
|
|
131
|
+
AudioScheduledSourceNode::disable();
|
|
137
132
|
alignedBus_.reset();
|
|
138
133
|
}
|
|
139
134
|
|
|
@@ -141,12 +141,16 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
|
|
|
141
141
|
nonSilentFramesToProcess = framesToProcess;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
void AudioScheduledSourceNode::disable() {
|
|
145
|
+
AudioNode::disable();
|
|
146
|
+
|
|
147
|
+
if (onendedCallback_) {
|
|
148
|
+
onendedCallback_(getStopTime());
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
144
152
|
void AudioScheduledSourceNode::handleStopScheduled() {
|
|
145
153
|
if (isStopScheduled()) {
|
|
146
|
-
if (onendedCallback_) {
|
|
147
|
-
onendedCallback_(getStopTime());
|
|
148
|
-
}
|
|
149
|
-
|
|
150
154
|
playbackState_ = PlaybackState::FINISHED;
|
|
151
155
|
disable();
|
|
152
156
|
}
|
|
@@ -18,6 +18,11 @@ namespace audioapi {
|
|
|
18
18
|
|
|
19
19
|
class AudioScheduledSourceNode : public AudioNode {
|
|
20
20
|
public:
|
|
21
|
+
// UNSCHEDULED: The node is not scheduled to play.
|
|
22
|
+
// SCHEDULED: The node is scheduled to play at a specific time.
|
|
23
|
+
// PLAYING: The node is currently playing.
|
|
24
|
+
// FINISHED: The node has finished playing.
|
|
25
|
+
// STOP_SCHEDULED: The node is scheduled to stop at a specific time, but is still playing.
|
|
21
26
|
enum class PlaybackState { UNSCHEDULED, SCHEDULED, PLAYING, FINISHED, STOP_SCHEDULED };
|
|
22
27
|
explicit AudioScheduledSourceNode(BaseAudioContext *context);
|
|
23
28
|
|
|
@@ -33,6 +38,7 @@ class AudioScheduledSourceNode : public AudioNode {
|
|
|
33
38
|
void setOnendedCallback(const std::function<void(double)> &onendedCallback);
|
|
34
39
|
|
|
35
40
|
virtual double getStopTime() const = 0;
|
|
41
|
+
void disable() override;
|
|
36
42
|
|
|
37
43
|
protected:
|
|
38
44
|
PlaybackState playbackState_;
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
namespace audioapi {
|
|
6
6
|
|
|
7
|
-
AudioNodeDestructor::AudioNodeDestructor()
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
AudioNodeDestructor::AudioNodeDestructor() : isExiting_(false) {
|
|
8
|
+
thread_ = std::thread(&AudioNodeDestructor::process, this);
|
|
9
|
+
}
|
|
10
10
|
|
|
11
11
|
AudioNodeDestructor::~AudioNodeDestructor() {
|
|
12
12
|
isExiting_ = true;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include <audioapi/core/AudioNode.h>
|
|
2
|
+
#include <audioapi/core/sources/AudioScheduledSourceNode.h>
|
|
2
3
|
#include <audioapi/core/utils/AudioNodeManager.h>
|
|
3
4
|
#include <audioapi/core/utils/Locker.h>
|
|
4
5
|
|
|
@@ -28,9 +29,16 @@ std::mutex &AudioNodeManager::getGraphLock() {
|
|
|
28
29
|
return graphLock_;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
void AudioNodeManager::
|
|
32
|
+
void AudioNodeManager::addProcessingNode(
|
|
33
|
+
const std::shared_ptr<AudioNode> &node) {
|
|
32
34
|
Locker lock(getGraphLock());
|
|
33
|
-
|
|
35
|
+
processingNodes_.insert(node);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
void AudioNodeManager::addSourceNode(
|
|
39
|
+
const std::shared_ptr<AudioScheduledSourceNode> &node) {
|
|
40
|
+
Locker lock(getGraphLock());
|
|
41
|
+
sourceNodes_.insert(node);
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
void AudioNodeManager::settlePendingConnections() {
|
|
@@ -54,17 +62,35 @@ void AudioNodeManager::settlePendingConnections() {
|
|
|
54
62
|
audioNodesToConnect_.clear();
|
|
55
63
|
}
|
|
56
64
|
|
|
65
|
+
void AudioNodeManager::cleanupNode(const std::shared_ptr<AudioNode> &node) {
|
|
66
|
+
nodeDeconstructor_.addNodeForDeconstruction(node);
|
|
67
|
+
node.get()->cleanup();
|
|
68
|
+
}
|
|
69
|
+
|
|
57
70
|
void AudioNodeManager::prepareNodesForDestruction() {
|
|
58
71
|
nodeDeconstructor_.tryCallWithLock([this]() {
|
|
59
|
-
auto
|
|
72
|
+
auto sNodesIt = sourceNodes_.begin();
|
|
73
|
+
|
|
74
|
+
while (sNodesIt != sourceNodes_.end()) {
|
|
75
|
+
// we don't want to destroy nodes that are still playing or will be
|
|
76
|
+
// playing
|
|
77
|
+
if (sNodesIt->use_count() == 1 &&
|
|
78
|
+
(sNodesIt->get()->isUnscheduled() || sNodesIt->get()->isFinished())) {
|
|
79
|
+
cleanupNode(*sNodesIt);
|
|
80
|
+
sNodesIt = sourceNodes_.erase(sNodesIt);
|
|
81
|
+
} else {
|
|
82
|
+
++sNodesIt;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
60
85
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
86
|
+
auto pNodesIt = processingNodes_.begin();
|
|
87
|
+
|
|
88
|
+
while (pNodesIt != processingNodes_.end()) {
|
|
89
|
+
if (pNodesIt->use_count() == 1) {
|
|
90
|
+
cleanupNode(*pNodesIt);
|
|
91
|
+
pNodesIt = processingNodes_.erase(pNodesIt);
|
|
66
92
|
} else {
|
|
67
|
-
++
|
|
93
|
+
++pNodesIt;
|
|
68
94
|
}
|
|
69
95
|
}
|
|
70
96
|
});
|
|
@@ -74,11 +100,19 @@ void AudioNodeManager::prepareNodesForDestruction() {
|
|
|
74
100
|
void AudioNodeManager::cleanup() {
|
|
75
101
|
Locker lock(getGraphLock());
|
|
76
102
|
|
|
77
|
-
for (auto it =
|
|
103
|
+
for (auto it = sourceNodes_.begin(), end = sourceNodes_.end(); it != end;
|
|
104
|
+
++it) {
|
|
105
|
+
it->get()->cleanup();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (auto it = processingNodes_.begin(), end = processingNodes_.end();
|
|
109
|
+
it != end;
|
|
110
|
+
++it) {
|
|
78
111
|
it->get()->cleanup();
|
|
79
112
|
}
|
|
80
113
|
|
|
81
|
-
|
|
114
|
+
sourceNodes_.clear();
|
|
115
|
+
processingNodes_.clear();
|
|
82
116
|
}
|
|
83
117
|
|
|
84
118
|
} // namespace audioapi
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
namespace audioapi {
|
|
12
12
|
|
|
13
13
|
class AudioNode;
|
|
14
|
+
class AudioScheduledSourceNode;
|
|
14
15
|
|
|
15
16
|
class AudioNodeManager {
|
|
16
17
|
public:
|
|
@@ -27,7 +28,8 @@ class AudioNodeManager {
|
|
|
27
28
|
const std::shared_ptr<AudioNode> &to,
|
|
28
29
|
ConnectionType type);
|
|
29
30
|
|
|
30
|
-
void
|
|
31
|
+
void addProcessingNode(const std::shared_ptr<AudioNode> &node);
|
|
32
|
+
void addSourceNode(const std::shared_ptr<AudioScheduledSourceNode> &node);
|
|
31
33
|
|
|
32
34
|
void cleanup();
|
|
33
35
|
|
|
@@ -36,7 +38,8 @@ class AudioNodeManager {
|
|
|
36
38
|
AudioNodeDestructor nodeDeconstructor_;
|
|
37
39
|
|
|
38
40
|
// all nodes created in the context
|
|
39
|
-
std::unordered_set<std::shared_ptr<
|
|
41
|
+
std::unordered_set<std::shared_ptr<AudioScheduledSourceNode>> sourceNodes_;
|
|
42
|
+
std::unordered_set<std::shared_ptr<AudioNode>> processingNodes_;
|
|
40
43
|
|
|
41
44
|
// connections to be settled
|
|
42
45
|
std::vector<std::tuple<
|
|
@@ -46,6 +49,7 @@ class AudioNodeManager {
|
|
|
46
49
|
audioNodesToConnect_;
|
|
47
50
|
|
|
48
51
|
void settlePendingConnections();
|
|
52
|
+
void cleanupNode(const std::shared_ptr<AudioNode> &node);
|
|
49
53
|
void prepareNodesForDestruction();
|
|
50
54
|
};
|
|
51
55
|
|
|
@@ -14,7 +14,7 @@ RCT_EXPORT_MODULE(AudioManagerModule);
|
|
|
14
14
|
if (self == [super init]) {
|
|
15
15
|
self.audioEngine = [AudioEngine sharedInstance];
|
|
16
16
|
self.audioSessionManager = [AudioSessionManager sharedInstance];
|
|
17
|
-
self.notificationManager = [NotificationManager
|
|
17
|
+
self.notificationManager = [NotificationManager sharedInstanceWithAudioManagerModule:self];
|
|
18
18
|
self.lockScreenManager = [LockScreenManager sharedInstanceWithAudioManagerModule:self];
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -49,16 +49,19 @@ RCT_EXPORT_METHOD(enableRemoteCommand : (NSString *)name enabled : (BOOL)enabled
|
|
|
49
49
|
[self.lockScreenManager enableRemoteCommand:name enabled:enabled];
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
RCT_EXPORT_METHOD(setAudioSessionOptions : (NSString *)category mode : (NSString *)mode options : (NSArray *)
|
|
53
|
-
options active : (BOOL)active)
|
|
52
|
+
RCT_EXPORT_METHOD(setAudioSessionOptions : (NSString *)category mode : (NSString *)mode options : (NSArray *)options)
|
|
54
53
|
{
|
|
55
|
-
|
|
54
|
+
[self.audioSessionManager setAudioSessionOptions:category mode:mode options:options];
|
|
55
|
+
}
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
RCT_EXPORT_METHOD(observeAudioInterruptions : (BOOL)enabled)
|
|
58
|
+
{
|
|
59
|
+
[self.notificationManager observeAudioInterruptions:enabled];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
RCT_EXPORT_METHOD(observeVolumeChanges : (BOOL)enabled)
|
|
63
|
+
{
|
|
64
|
+
[self.notificationManager observeVolumeChanges:(BOOL)enabled];
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getDevicePreferredSampleRate)
|
|
@@ -80,13 +83,11 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getDevicePreferredSampleRate)
|
|
|
80
83
|
@"onRemoteSkipBackward",
|
|
81
84
|
@"onRemoteSeekForward",
|
|
82
85
|
@"onRemoteSeekBackward",
|
|
83
|
-
@"onRemoteChangePlaybackPosition"
|
|
86
|
+
@"onRemoteChangePlaybackPosition",
|
|
87
|
+
@"onInterruption",
|
|
88
|
+
@"onRouteChange",
|
|
89
|
+
@"onVolumeChange"
|
|
84
90
|
];
|
|
85
91
|
}
|
|
86
92
|
|
|
87
|
-
- (void)sendEventWithValue:(NSString *)event withValue:(NSString *)value
|
|
88
|
-
{
|
|
89
|
-
[self sendEventWithName:@"AudioManagerModule" body:@{@"name" : event, @"value" : value}];
|
|
90
|
-
}
|
|
91
|
-
|
|
92
93
|
@end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#ifdef __OBJC__ // when compiled as Objective-C++
|
|
4
|
-
#import <
|
|
4
|
+
#import <NativeAudioPlayer.h>
|
|
5
5
|
#else // when compiled as C++
|
|
6
|
-
typedef struct objc_object
|
|
6
|
+
typedef struct objc_object NativeAudioPlayer;
|
|
7
7
|
#endif // __OBJC__
|
|
8
8
|
|
|
9
9
|
#include <functional>
|
|
@@ -14,23 +14,22 @@ class AudioBus;
|
|
|
14
14
|
class AudioContext;
|
|
15
15
|
|
|
16
16
|
class IOSAudioPlayer {
|
|
17
|
-
protected:
|
|
18
|
-
std::shared_ptr<AudioBus> audioBus_;
|
|
19
|
-
AudioPlayer *audioPlayer_;
|
|
20
|
-
std::function<void(std::shared_ptr<AudioBus>, int)> renderAudio_;
|
|
21
|
-
int channelCount_;
|
|
22
|
-
|
|
23
17
|
public:
|
|
24
18
|
IOSAudioPlayer(
|
|
25
19
|
const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio,
|
|
26
20
|
float sampleRate);
|
|
27
21
|
~IOSAudioPlayer();
|
|
28
22
|
|
|
29
|
-
float getSampleRate() const;
|
|
30
|
-
|
|
31
23
|
void start();
|
|
32
|
-
void stop();
|
|
33
24
|
void resume();
|
|
34
|
-
void
|
|
25
|
+
void stop();
|
|
26
|
+
void pause();
|
|
27
|
+
|
|
28
|
+
protected:
|
|
29
|
+
std::shared_ptr<AudioBus> audioBus_;
|
|
30
|
+
NativeAudioPlayer *audioPlayer_;
|
|
31
|
+
std::function<void(std::shared_ptr<AudioBus>, int)> renderAudio_;
|
|
32
|
+
int channelCount_;
|
|
33
|
+
std::atomic<bool> isRunning_;
|
|
35
34
|
};
|
|
36
35
|
} // namespace audioapi
|
|
@@ -9,14 +9,19 @@
|
|
|
9
9
|
namespace audioapi {
|
|
10
10
|
|
|
11
11
|
IOSAudioPlayer::IOSAudioPlayer(const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio, float sampleRate)
|
|
12
|
-
: channelCount_(2), renderAudio_(renderAudio), audioBus_(0)
|
|
12
|
+
: channelCount_(2), renderAudio_(renderAudio), audioBus_(0), isRunning_(false)
|
|
13
13
|
{
|
|
14
14
|
RenderAudioBlock renderAudioBlock = ^(AudioBufferList *outputData, int numFrames) {
|
|
15
15
|
int processedFrames = 0;
|
|
16
16
|
|
|
17
17
|
while (processedFrames < numFrames) {
|
|
18
18
|
int framesToProcess = std::min(numFrames - processedFrames, RENDER_QUANTUM_SIZE);
|
|
19
|
-
|
|
19
|
+
|
|
20
|
+
if (isRunning_.load()) {
|
|
21
|
+
renderAudio_(audioBus_, framesToProcess);
|
|
22
|
+
} else {
|
|
23
|
+
audioBus_->zero();
|
|
24
|
+
}
|
|
20
25
|
|
|
21
26
|
for (int channel = 0; channel < channelCount_; channel += 1) {
|
|
22
27
|
float *outputChannel = (float *)outputData->mBuffers[channel].mData;
|
|
@@ -29,11 +34,11 @@ IOSAudioPlayer::IOSAudioPlayer(const std::function<void(std::shared_ptr<AudioBus
|
|
|
29
34
|
}
|
|
30
35
|
};
|
|
31
36
|
|
|
32
|
-
audioPlayer_ = [[
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
audioPlayer_ = [[NativeAudioPlayer alloc] initWithRenderAudio:renderAudioBlock
|
|
38
|
+
sampleRate:sampleRate
|
|
39
|
+
channelCount:channelCount_];
|
|
35
40
|
|
|
36
|
-
audioBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_,
|
|
41
|
+
audioBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, sampleRate);
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
IOSAudioPlayer::~IOSAudioPlayer()
|
|
@@ -48,27 +53,28 @@ IOSAudioPlayer::~IOSAudioPlayer()
|
|
|
48
53
|
|
|
49
54
|
void IOSAudioPlayer::start()
|
|
50
55
|
{
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
if (isRunning_.load()) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return [audioPlayer_ stop];
|
|
60
|
+
[audioPlayer_ start];
|
|
61
|
+
isRunning_.store(true);
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
void IOSAudioPlayer::resume()
|
|
60
65
|
{
|
|
61
|
-
|
|
66
|
+
isRunning_.store(true);
|
|
62
67
|
}
|
|
63
68
|
|
|
64
|
-
void IOSAudioPlayer::
|
|
69
|
+
void IOSAudioPlayer::stop()
|
|
65
70
|
{
|
|
66
|
-
|
|
71
|
+
isRunning_.store(false);
|
|
72
|
+
[audioPlayer_ stop];
|
|
67
73
|
}
|
|
68
74
|
|
|
69
|
-
|
|
75
|
+
void IOSAudioPlayer::pause()
|
|
70
76
|
{
|
|
71
|
-
|
|
77
|
+
isRunning_.store(false);
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
} // namespace audioapi
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#ifdef __OBJC__ // when compiled as Objective-C++
|
|
4
|
+
#import <NativeAudioRecorder.h>
|
|
5
|
+
#else // when compiled as C++
|
|
6
|
+
typedef struct objc_object NativeAudioRecorder;
|
|
7
|
+
#endif // __OBJC__
|
|
8
|
+
|
|
9
|
+
#include <audioapi/core/inputs/AudioRecorder.h>
|
|
10
|
+
#include <functional>
|
|
11
|
+
|
|
12
|
+
namespace audioapi {
|
|
13
|
+
|
|
14
|
+
class AudioBus;
|
|
15
|
+
|
|
16
|
+
class IOSAudioRecorder : public AudioRecorder {
|
|
17
|
+
public:
|
|
18
|
+
IOSAudioRecorder(
|
|
19
|
+
float sampleRate,
|
|
20
|
+
int bufferLength,
|
|
21
|
+
const std::function<void(void)> &onError,
|
|
22
|
+
const std::function<void(void)> &onStatusChange,
|
|
23
|
+
const std::function<void(std::shared_ptr<AudioBus>, int, double)>
|
|
24
|
+
&onAudioReady);
|
|
25
|
+
|
|
26
|
+
~IOSAudioRecorder() override;
|
|
27
|
+
|
|
28
|
+
void start() override;
|
|
29
|
+
void stop() override;
|
|
30
|
+
|
|
31
|
+
private:
|
|
32
|
+
NativeAudioRecorder *audioRecorder_;
|
|
33
|
+
std::atomic<bool> isRunning_;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#import <AVFoundation/AVFoundation.h>
|
|
2
|
+
|
|
3
|
+
#include <audioapi/core/Constants.h>
|
|
4
|
+
#include <audioapi/dsp/VectorMath.h>
|
|
5
|
+
#include <audioapi/ios/core/IOSAudioRecorder.h>
|
|
6
|
+
#include <audioapi/utils/AudioArray.h>
|
|
7
|
+
#include <audioapi/utils/AudioBus.h>
|
|
8
|
+
|
|
9
|
+
namespace audioapi {
|
|
10
|
+
|
|
11
|
+
IOSAudioRecorder::IOSAudioRecorder(
|
|
12
|
+
float sampleRate,
|
|
13
|
+
int bufferLength,
|
|
14
|
+
const std::function<void(void)> &onError,
|
|
15
|
+
const std::function<void(void)> &onStatusChange,
|
|
16
|
+
const std::function<void(std::shared_ptr<AudioBus>, int, double)> &onAudioReady)
|
|
17
|
+
: AudioRecorder(sampleRate, bufferLength, onError, onStatusChange, onAudioReady)
|
|
18
|
+
{
|
|
19
|
+
AudioReceiverBlock audioReceiverBlock = ^(const AudioBufferList *inputBuffer, int numFrames, AVAudioTime *when) {
|
|
20
|
+
if (isRunning_.load()) {
|
|
21
|
+
auto bus = std::make_shared<AudioBus>(numFrames, 1, sampleRate);
|
|
22
|
+
|
|
23
|
+
auto *inputChannel = (float *)inputBuffer->mBuffers[0].mData;
|
|
24
|
+
auto *outputChannel = bus->getChannel(0)->getData();
|
|
25
|
+
|
|
26
|
+
memcpy(outputChannel, inputChannel, numFrames * sizeof(float));
|
|
27
|
+
onAudioReady_(bus, numFrames, [when sampleTime] / [when sampleRate]);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
audioRecorder_ = [[NativeAudioRecorder alloc] initWithReceiverBlock:audioReceiverBlock bufferLength:bufferLength];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
IOSAudioRecorder::~IOSAudioRecorder()
|
|
35
|
+
{
|
|
36
|
+
AudioRecorder::~AudioRecorder();
|
|
37
|
+
|
|
38
|
+
stop();
|
|
39
|
+
[audioRecorder_ cleanup];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
void IOSAudioRecorder::start()
|
|
43
|
+
{
|
|
44
|
+
if (isRunning_.load()) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
[audioRecorder_ start];
|
|
49
|
+
isRunning_.store(true);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void IOSAudioRecorder::stop()
|
|
53
|
+
{
|
|
54
|
+
if (!isRunning_.load()) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
isRunning_.store(false);
|
|
59
|
+
[audioRecorder_ stop];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
} // namespace audioapi
|
|
@@ -5,14 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
typedef void (^RenderAudioBlock)(AudioBufferList *outputBuffer, int numFrames);
|
|
7
7
|
|
|
8
|
-
@interface
|
|
8
|
+
@interface NativeAudioPlayer : NSObject
|
|
9
9
|
|
|
10
10
|
@property (nonatomic, strong) AVAudioFormat *format;
|
|
11
11
|
@property (nonatomic, strong) AVAudioSourceNode *sourceNode;
|
|
12
12
|
@property (nonatomic, copy) RenderAudioBlock renderAudio;
|
|
13
13
|
@property (nonatomic, assign) float sampleRate;
|
|
14
14
|
@property (nonatomic, assign) int channelCount;
|
|
15
|
-
@property (nonatomic, assign) bool isRunning;
|
|
16
15
|
@property (nonatomic, strong) NSString *sourceNodeId;
|
|
17
16
|
@property (nonatomic, strong) AVAudioSourceNodeRenderBlock renderBlock;
|
|
18
17
|
|
|
@@ -20,16 +19,10 @@ typedef void (^RenderAudioBlock)(AudioBufferList *outputBuffer, int numFrames);
|
|
|
20
19
|
sampleRate:(float)sampleRate
|
|
21
20
|
channelCount:(int)channelCount;
|
|
22
21
|
|
|
23
|
-
- (float)getSampleRate;
|
|
24
|
-
|
|
25
22
|
- (void)start;
|
|
26
23
|
|
|
27
24
|
- (void)stop;
|
|
28
25
|
|
|
29
|
-
- (void)resume;
|
|
30
|
-
|
|
31
|
-
- (void)suspend;
|
|
32
|
-
|
|
33
26
|
- (void)cleanup;
|
|
34
27
|
|
|
35
28
|
@end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
#import <audioapi/ios/core/
|
|
1
|
+
#import <audioapi/ios/core/NativeAudioPlayer.h>
|
|
2
2
|
#import <audioapi/ios/system/AudioEngine.h>
|
|
3
3
|
|
|
4
|
-
@implementation
|
|
4
|
+
@implementation NativeAudioPlayer
|
|
5
5
|
|
|
6
6
|
- (instancetype)initWithRenderAudio:(RenderAudioBlock)renderAudio
|
|
7
7
|
sampleRate:(float)sampleRate
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
weakSelf.renderAudio(outputData, frameCount);
|
|
24
|
+
|
|
24
25
|
return kAudioServicesNoError;
|
|
25
26
|
};
|
|
26
27
|
|
|
@@ -31,53 +32,23 @@
|
|
|
31
32
|
return self;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
- (float)getSampleRate
|
|
35
|
-
{
|
|
36
|
-
return self.sampleRate;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
35
|
- (void)start
|
|
40
36
|
{
|
|
41
37
|
NSLog(@"[AudioPlayer] start");
|
|
38
|
+
|
|
42
39
|
AudioEngine *audioEngine = [AudioEngine sharedInstance];
|
|
43
|
-
self.isRunning = true;
|
|
44
40
|
self.sourceNodeId = [audioEngine attachSourceNode:self.sourceNode format:self.format];
|
|
45
41
|
}
|
|
46
42
|
|
|
47
43
|
- (void)stop
|
|
48
44
|
{
|
|
49
45
|
NSLog(@"[AudioPlayer] stop");
|
|
50
|
-
if (!self.isRunning) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
46
|
|
|
54
47
|
AudioEngine *audioEngine = [AudioEngine sharedInstance];
|
|
55
|
-
self.isRunning = false;
|
|
56
48
|
[audioEngine detachSourceNodeWithId:self.sourceNodeId];
|
|
57
49
|
self.sourceNodeId = nil;
|
|
58
50
|
}
|
|
59
51
|
|
|
60
|
-
- (void)suspend
|
|
61
|
-
{
|
|
62
|
-
NSLog(@"[AudioPlayer] suspend");
|
|
63
|
-
if (!self.isRunning) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
AudioEngine *audioEngine = [AudioEngine sharedInstance];
|
|
68
|
-
self.isRunning = false;
|
|
69
|
-
[audioEngine detachSourceNodeWithId:self.sourceNodeId];
|
|
70
|
-
self.sourceNodeId = nil;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
- (void)resume
|
|
74
|
-
{
|
|
75
|
-
NSLog(@"[AudioPlayer] resume");
|
|
76
|
-
AudioEngine *audioEngine = [AudioEngine sharedInstance];
|
|
77
|
-
self.isRunning = true;
|
|
78
|
-
self.sourceNodeId = [audioEngine attachSourceNode:self.sourceNode format:self.format];
|
|
79
|
-
}
|
|
80
|
-
|
|
81
52
|
- (void)cleanup
|
|
82
53
|
{
|
|
83
54
|
self.renderAudio = nil;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#import <AVFoundation/AVFoundation.h>
|
|
4
|
+
#import <Foundation/Foundation.h>
|
|
5
|
+
|
|
6
|
+
typedef void (^AudioReceiverBlock)(const AudioBufferList *inputBuffer, int numFrames, AVAudioTime *when);
|
|
7
|
+
|
|
8
|
+
@interface NativeAudioRecorder : NSObject
|
|
9
|
+
|
|
10
|
+
@property (nonatomic, assign) int bufferLength;
|
|
11
|
+
@property (nonatomic, assign) double sampleRate;
|
|
12
|
+
|
|
13
|
+
@property (nonatomic, strong) AVAudioSinkNode *sinkNode;
|
|
14
|
+
@property (nonatomic, copy) AVAudioSinkNodeReceiverBlock receiverSinkBlock;
|
|
15
|
+
@property (nonatomic, copy) AudioReceiverBlock receiverBlock;
|
|
16
|
+
|
|
17
|
+
- (instancetype)initWithReceiverBlock:(AudioReceiverBlock)receiverBlock bufferLength:(int)bufferLength;
|
|
18
|
+
|
|
19
|
+
- (void)start;
|
|
20
|
+
|
|
21
|
+
- (void)stop;
|
|
22
|
+
|
|
23
|
+
- (void)cleanup;
|
|
24
|
+
|
|
25
|
+
@end
|