react-native-audio-api 0.4.10-rc.1 → 0.4.11
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/build.gradle +2 -0
- package/android/src/main/cpp/{core/AudioAPIInstaller.cpp → AudioAPIModule.cpp} +12 -11
- package/android/src/main/cpp/{core/AudioAPIInstaller.h → AudioAPIModule.h} +9 -11
- package/android/src/main/cpp/OnLoad.cpp +2 -2
- package/android/src/main/cpp/core/AudioDecoder.cpp +5 -5
- package/android/src/main/cpp/core/AudioPlayer.cpp +15 -3
- package/android/src/main/cpp/core/AudioPlayer.h +6 -3
- package/android/src/main/java/com/swmansion/audioapi/{module/AudioAPIInstaller.kt → AudioAPIModule.kt} +22 -10
- package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +31 -6
- package/android/src/oldarch/NativeAudioAPIModuleSpec.java +37 -0
- package/common/cpp/HostObjects/AudioContextHostObject.h +34 -1
- package/common/cpp/core/AnalyserNode.cpp +2 -2
- package/common/cpp/core/AnalyserNode.h +1 -1
- package/common/cpp/core/AudioBuffer.cpp +4 -2
- package/common/cpp/core/AudioBuffer.h +1 -1
- package/common/cpp/core/AudioBufferSourceNode.cpp +3 -3
- package/common/cpp/core/AudioBufferSourceNode.h +3 -3
- package/common/cpp/core/AudioContext.cpp +14 -3
- package/common/cpp/core/AudioContext.h +3 -1
- package/common/cpp/core/AudioDecoder.h +2 -1
- package/common/cpp/core/AudioDestinationNode.cpp +3 -3
- package/common/cpp/core/AudioDestinationNode.h +3 -3
- package/common/cpp/core/AudioNode.cpp +16 -11
- package/common/cpp/core/AudioNode.h +6 -6
- package/common/cpp/core/AudioScheduledSourceNode.cpp +1 -1
- package/common/cpp/core/AudioScheduledSourceNode.h +1 -1
- package/common/cpp/core/BiquadFilterNode.cpp +1 -1
- package/common/cpp/core/BiquadFilterNode.h +1 -1
- package/common/cpp/core/GainNode.cpp +3 -1
- package/common/cpp/core/GainNode.h +1 -1
- package/common/cpp/core/OscillatorNode.cpp +3 -1
- package/common/cpp/core/OscillatorNode.h +1 -1
- package/common/cpp/core/StereoPannerNode.cpp +1 -1
- package/common/cpp/core/StereoPannerNode.h +1 -1
- package/common/cpp/installer/AudioAPIModuleInstaller.cpp +49 -0
- package/common/cpp/installer/AudioAPIModuleInstaller.h +49 -0
- package/ios/AudioAPIModule.h +1 -1
- package/ios/AudioAPIModule.mm +10 -3
- package/ios/core/AudioDecoder.mm +2 -3
- package/ios/core/AudioPlayer.h +14 -0
- package/ios/core/AudioPlayer.m +85 -24
- package/ios/core/IOSAudioPlayer.h +6 -4
- package/ios/core/IOSAudioPlayer.mm +14 -7
- package/lib/module/core/AudioContext.js +7 -1
- package/lib/module/core/AudioContext.js.map +1 -1
- package/lib/module/index.js +11 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/NativeAudioAPIModule.js +5 -0
- package/lib/module/specs/NativeAudioAPIModule.js.map +1 -0
- package/lib/module/web-core/AudioContext.js +6 -0
- package/lib/module/web-core/AudioContext.js.map +1 -1
- package/lib/typescript/core/AudioContext.d.ts +2 -0
- package/lib/typescript/core/AudioContext.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +4 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/interfaces.d.ts +6 -1
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts +7 -0
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -0
- package/lib/typescript/web-core/AudioContext.d.ts +3 -1
- package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
- package/package.json +9 -7
- package/src/core/AudioContext.ts +9 -1
- package/src/index.ts +16 -3
- package/src/interfaces.ts +7 -1
- package/src/specs/NativeAudioAPIModule.ts +7 -0
- package/src/web-core/AudioContext.tsx +9 -1
- package/android/src/main/java/com/swmansion/audioapi/nativemodules/AudioAPIModule.kt +0 -26
- package/common/cpp/HostObjects/AudioAPIInstallerHostObject.h +0 -56
- package/lib/module/specs/global.d.js +0 -4
- package/lib/module/specs/global.d.js.map +0 -1
- package/lib/module/specs/install.js +0 -18
- package/lib/module/specs/install.js.map +0 -1
- package/lib/typescript/specs/install.d.ts +0 -7
- package/lib/typescript/specs/install.d.ts.map +0 -1
- package/src/specs/global.d.ts +0 -12
- package/src/specs/install.ts +0 -32
|
@@ -97,17 +97,19 @@ std::string AudioNode::toString(ChannelInterpretation interpretation) {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
AudioBus
|
|
100
|
+
std::shared_ptr<AudioBus> AudioNode::processAudio(
|
|
101
|
+
std::shared_ptr<AudioBus> outputBus,
|
|
102
|
+
int framesToProcess) {
|
|
101
103
|
if (!isInitialized_) {
|
|
102
104
|
return outputBus;
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
if (isAlreadyProcessed()) {
|
|
106
|
-
return audioBus_
|
|
108
|
+
return audioBus_;
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
// Process inputs and return the bus with the most channels.
|
|
110
|
-
|
|
112
|
+
auto processingBus = processInputs(outputBus, framesToProcess);
|
|
111
113
|
|
|
112
114
|
// Apply channel count mode.
|
|
113
115
|
processingBus = applyChannelCountMode(processingBus);
|
|
@@ -138,8 +140,10 @@ bool AudioNode::isAlreadyProcessed() {
|
|
|
138
140
|
return false;
|
|
139
141
|
}
|
|
140
142
|
|
|
141
|
-
AudioBus
|
|
142
|
-
|
|
143
|
+
std::shared_ptr<AudioBus> AudioNode::processInputs(
|
|
144
|
+
const std::shared_ptr<AudioBus> &outputBus,
|
|
145
|
+
int framesToProcess) {
|
|
146
|
+
auto processingBus = audioBus_;
|
|
143
147
|
processingBus->zero();
|
|
144
148
|
|
|
145
149
|
int maxNumberOfChannels = 0;
|
|
@@ -162,28 +166,29 @@ AudioBus *AudioNode::processInputs(AudioBus *outputBus, int framesToProcess) {
|
|
|
162
166
|
return processingBus;
|
|
163
167
|
}
|
|
164
168
|
|
|
165
|
-
AudioBus
|
|
169
|
+
std::shared_ptr<AudioBus> AudioNode::applyChannelCountMode(
|
|
170
|
+
std::shared_ptr<AudioBus> processingBus) {
|
|
166
171
|
// If the channelCountMode is EXPLICIT, the node should output the number of
|
|
167
172
|
// channels specified by the channelCount.
|
|
168
173
|
if (channelCountMode_ == ChannelCountMode::EXPLICIT) {
|
|
169
|
-
return audioBus_
|
|
174
|
+
return audioBus_;
|
|
170
175
|
}
|
|
171
176
|
|
|
172
177
|
// If the channelCountMode is CLAMPED_MAX, the node should output the maximum
|
|
173
178
|
// number of channels clamped to channelCount.
|
|
174
179
|
if (channelCountMode_ == ChannelCountMode::CLAMPED_MAX &&
|
|
175
180
|
processingBus->getNumberOfChannels() >= channelCount_) {
|
|
176
|
-
return audioBus_
|
|
181
|
+
return audioBus_;
|
|
177
182
|
}
|
|
178
183
|
|
|
179
184
|
return processingBus;
|
|
180
185
|
}
|
|
181
186
|
|
|
182
|
-
void AudioNode::mixInputsBuses(AudioBus
|
|
187
|
+
void AudioNode::mixInputsBuses(const std::shared_ptr<AudioBus> &processingBus) {
|
|
183
188
|
assert(processingBus != nullptr);
|
|
184
189
|
|
|
185
|
-
for (auto inputBus : inputBuses_) {
|
|
186
|
-
processingBus->sum(inputBus, channelInterpretation_);
|
|
190
|
+
for (const auto &inputBus : inputBuses_) {
|
|
191
|
+
processingBus->sum(inputBus.get(), channelInterpretation_);
|
|
187
192
|
}
|
|
188
193
|
|
|
189
194
|
inputBuses_.clear();
|
|
@@ -57,18 +57,18 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
|
|
|
57
57
|
std::size_t lastRenderedFrame_{SIZE_MAX};
|
|
58
58
|
|
|
59
59
|
private:
|
|
60
|
-
std::vector<AudioBus
|
|
60
|
+
std::vector<std::shared_ptr<AudioBus>> inputBuses_ = {};
|
|
61
61
|
|
|
62
62
|
static std::string toString(ChannelCountMode mode);
|
|
63
63
|
static std::string toString(ChannelInterpretation interpretation);
|
|
64
64
|
|
|
65
|
-
AudioBus
|
|
66
|
-
virtual void processNode(AudioBus
|
|
65
|
+
std::shared_ptr<AudioBus> processAudio(std::shared_ptr<AudioBus> outputBus, int framesToProcess);
|
|
66
|
+
virtual void processNode(const std::shared_ptr<AudioBus>&, int) = 0;
|
|
67
67
|
|
|
68
68
|
bool isAlreadyProcessed();
|
|
69
|
-
AudioBus
|
|
70
|
-
AudioBus
|
|
71
|
-
void mixInputsBuses(AudioBus
|
|
69
|
+
std::shared_ptr<AudioBus> processInputs(const std::shared_ptr<AudioBus>& outputBus, int framesToProcess);
|
|
70
|
+
std::shared_ptr<AudioBus> applyChannelCountMode(std::shared_ptr<AudioBus> processingBus);
|
|
71
|
+
void mixInputsBuses(const std::shared_ptr<AudioBus>& processingBus);
|
|
72
72
|
|
|
73
73
|
void connectNode(const std::shared_ptr<AudioNode> &node);
|
|
74
74
|
void disconnectNode(const std::shared_ptr<AudioNode> &node);
|
|
@@ -43,7 +43,7 @@ bool AudioScheduledSourceNode::isFinished() {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
void AudioScheduledSourceNode::updatePlaybackInfo(
|
|
46
|
-
AudioBus
|
|
46
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
47
47
|
int framesToProcess,
|
|
48
48
|
size_t &startOffset,
|
|
49
49
|
size_t &nonSilentFramesToProcess) {
|
|
@@ -31,7 +31,7 @@ class AudioScheduledSourceNode : public AudioNode {
|
|
|
31
31
|
PlaybackState playbackState_;
|
|
32
32
|
|
|
33
33
|
void updatePlaybackInfo(
|
|
34
|
-
AudioBus
|
|
34
|
+
const std::shared_ptr<AudioBus>& processingBus,
|
|
35
35
|
int framesToProcess,
|
|
36
36
|
size_t &startOffset,
|
|
37
37
|
size_t &nonSilentFramesToProcess);
|
|
@@ -32,7 +32,7 @@ class BiquadFilterNode : public AudioNode {
|
|
|
32
32
|
std::vector<float> &phaseResponseOutput);
|
|
33
33
|
|
|
34
34
|
protected:
|
|
35
|
-
void processNode(AudioBus
|
|
35
|
+
void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
|
|
36
36
|
|
|
37
37
|
private:
|
|
38
38
|
std::shared_ptr<AudioParam> frequencyParam_;
|
|
@@ -14,7 +14,9 @@ std::shared_ptr<AudioParam> GainNode::getGainParam() const {
|
|
|
14
14
|
return gainParam_;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
void GainNode::processNode(
|
|
17
|
+
void GainNode::processNode(
|
|
18
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
19
|
+
int framesToProcess) {
|
|
18
20
|
double time = context_->getCurrentTime();
|
|
19
21
|
double deltaTime = 1.0 / context_->getSampleRate();
|
|
20
22
|
|
|
@@ -16,7 +16,7 @@ class GainNode : public AudioNode {
|
|
|
16
16
|
[[nodiscard]] std::shared_ptr<AudioParam> getGainParam() const;
|
|
17
17
|
|
|
18
18
|
protected:
|
|
19
|
-
void processNode(AudioBus
|
|
19
|
+
void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
|
|
20
20
|
|
|
21
21
|
private:
|
|
22
22
|
std::shared_ptr<AudioParam> gainParam_;
|
|
@@ -38,7 +38,9 @@ void OscillatorNode::setPeriodicWave(
|
|
|
38
38
|
type_ = OscillatorType::CUSTOM;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
void OscillatorNode::processNode(
|
|
41
|
+
void OscillatorNode::processNode(
|
|
42
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
43
|
+
int framesToProcess) {
|
|
42
44
|
size_t startOffset = 0;
|
|
43
45
|
size_t offsetLength = 0;
|
|
44
46
|
|
|
@@ -24,7 +24,7 @@ class OscillatorNode : public AudioScheduledSourceNode {
|
|
|
24
24
|
void setPeriodicWave(const std::shared_ptr<PeriodicWave> &periodicWave);
|
|
25
25
|
|
|
26
26
|
protected:
|
|
27
|
-
void processNode(AudioBus
|
|
27
|
+
void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
|
|
28
28
|
|
|
29
29
|
private:
|
|
30
30
|
std::shared_ptr<AudioParam> frequencyParam_;
|
|
@@ -22,7 +22,7 @@ std::shared_ptr<AudioParam> StereoPannerNode::getPanParam() const {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
void StereoPannerNode::processNode(
|
|
25
|
-
AudioBus
|
|
25
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
26
26
|
int framesToProcess) {
|
|
27
27
|
double time = context_->getCurrentTime();
|
|
28
28
|
double deltaTime = 1.0 / context_->getSampleRate();
|
|
@@ -17,7 +17,7 @@ class StereoPannerNode : public AudioNode {
|
|
|
17
17
|
[[nodiscard]] std::shared_ptr<AudioParam> getPanParam() const;
|
|
18
18
|
|
|
19
19
|
protected:
|
|
20
|
-
void processNode(AudioBus
|
|
20
|
+
void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
|
|
21
21
|
|
|
22
22
|
private:
|
|
23
23
|
std::shared_ptr<AudioParam> panParam_;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// #include "AudioAPIModuleInstaller.h"
|
|
2
|
+
//
|
|
3
|
+
// #include "AudioContext.h"
|
|
4
|
+
// #include "AudioContextHostObject.h"
|
|
5
|
+
//
|
|
6
|
+
// namespace audioapi {
|
|
7
|
+
//
|
|
8
|
+
// AudioAPIModuleInstaller::AudioAPIModuleInstaller(
|
|
9
|
+
// jsi::Runtime *jsiRuntime,
|
|
10
|
+
// const std::shared_ptr<react::CallInvoker> &jsCallInvoker):
|
|
11
|
+
// jsiRuntime_(jsiRuntime), jsCallInvoker_(jsCallInvoker) {}
|
|
12
|
+
//
|
|
13
|
+
// static void AudioAPIModuleInstaller::injectJSIBindings() {
|
|
14
|
+
// auto createAudioContext = getCreateAudioContextFunction();
|
|
15
|
+
// jsiRuntime_->global().setProperty(
|
|
16
|
+
// *jsiRuntime_, "createAudioContext", createAudioContext);
|
|
17
|
+
// }
|
|
18
|
+
//
|
|
19
|
+
// jsi::Function AudioAPIModuleInstaller::getCreateAudioContextFunction() {
|
|
20
|
+
// return jsi::Function::createFromHostFunction(
|
|
21
|
+
// *jsiRuntime_,
|
|
22
|
+
// jsi::PropNameID::forAscii(*jsiRuntime_, "createAudioContext"),
|
|
23
|
+
// 0,
|
|
24
|
+
// [this](
|
|
25
|
+
// jsi::Runtime &runtime,
|
|
26
|
+
// const jsi::Value &thisValue,
|
|
27
|
+
// const jsi::Value *args,
|
|
28
|
+
// size_t count) -> jsi::Value {
|
|
29
|
+
// std::shared_ptr<AudioContext> audioContext;
|
|
30
|
+
// if (args[0].isUndefined()) {
|
|
31
|
+
// audioContext = std::make_shared<AudioContext>();
|
|
32
|
+
// } else {
|
|
33
|
+
// auto sampleRate = static_cast<float>(args[0].getNumber());
|
|
34
|
+
// audioContext = std::make_shared<AudioContext>(sampleRate);
|
|
35
|
+
// }
|
|
36
|
+
//
|
|
37
|
+
// auto promiseVendor = std::make_shared<PromiseVendor>(jsiRuntime_,
|
|
38
|
+
// jsCallInvoker_);
|
|
39
|
+
//
|
|
40
|
+
// auto audioContextHostObject =
|
|
41
|
+
// std::make_shared<AudioContextHostObject>(
|
|
42
|
+
// audioContext, promiseVendor);
|
|
43
|
+
//
|
|
44
|
+
// return jsi::Object::createFromHostObject(
|
|
45
|
+
// runtime, audioContextHostObject);
|
|
46
|
+
// });
|
|
47
|
+
// }
|
|
48
|
+
//
|
|
49
|
+
// } // namespace audioapi
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <JsiPromise.h>
|
|
4
|
+
#include "AudioContext.h"
|
|
5
|
+
#include "AudioContextHostObject.h"
|
|
6
|
+
|
|
7
|
+
namespace audioapi {
|
|
8
|
+
|
|
9
|
+
using namespace facebook;
|
|
10
|
+
|
|
11
|
+
class AudioAPIModuleInstaller {
|
|
12
|
+
public:
|
|
13
|
+
static void injectJSIBindings(jsi::Runtime *jsiRuntime, const std::shared_ptr<react::CallInvoker> &jsCallInvoker) {
|
|
14
|
+
auto createAudioContext = getCreateAudioContextFunction(jsiRuntime, jsCallInvoker);
|
|
15
|
+
jsiRuntime->global().setProperty(
|
|
16
|
+
*jsiRuntime, "createAudioContext", createAudioContext);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private:
|
|
20
|
+
static jsi::Function getCreateAudioContextFunction(jsi::Runtime *jsiRuntime, const std::shared_ptr<react::CallInvoker> &jsCallInvoker) {
|
|
21
|
+
return jsi::Function::createFromHostFunction(
|
|
22
|
+
*jsiRuntime,
|
|
23
|
+
jsi::PropNameID::forAscii(*jsiRuntime, "createAudioContext"),
|
|
24
|
+
0,
|
|
25
|
+
[jsiRuntime, jsCallInvoker](
|
|
26
|
+
jsi::Runtime &runtime,
|
|
27
|
+
const jsi::Value &thisValue,
|
|
28
|
+
const jsi::Value *args,
|
|
29
|
+
size_t count) -> jsi::Value {
|
|
30
|
+
std::shared_ptr<AudioContext> audioContext;
|
|
31
|
+
if (args[0].isUndefined()) {
|
|
32
|
+
audioContext = std::make_shared<AudioContext>();
|
|
33
|
+
} else {
|
|
34
|
+
auto sampleRate = static_cast<float>(args[0].getNumber());
|
|
35
|
+
audioContext = std::make_shared<AudioContext>(sampleRate);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
auto promiseVendor = std::make_shared<PromiseVendor>(jsiRuntime, jsCallInvoker);
|
|
39
|
+
|
|
40
|
+
auto audioContextHostObject = std::make_shared<AudioContextHostObject>(
|
|
41
|
+
audioContext, promiseVendor);
|
|
42
|
+
|
|
43
|
+
return jsi::Object::createFromHostObject(
|
|
44
|
+
runtime, audioContextHostObject);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
} // namespace audioapi
|
package/ios/AudioAPIModule.h
CHANGED
package/ios/AudioAPIModule.mm
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
#import <ReactCommon/RCTTurboModule.h>
|
|
7
7
|
#endif // RCT_NEW_ARCH_ENABLED
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
#include "AudioAPIModuleInstaller.h"
|
|
10
10
|
|
|
11
11
|
@implementation AudioAPIModule
|
|
12
12
|
|
|
@@ -38,11 +38,18 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install)
|
|
|
38
38
|
|
|
39
39
|
assert(jsiRuntime != nullptr);
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
hostObject->install();
|
|
41
|
+
audioapi::AudioAPIModuleInstaller::injectJSIBindings(jsiRuntime, jsCallInvoker);
|
|
43
42
|
|
|
44
43
|
NSLog(@"Successfully installed JSI bindings for react-native-audio-api!");
|
|
45
44
|
return @true;
|
|
46
45
|
}
|
|
47
46
|
|
|
47
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
48
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
49
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
50
|
+
{
|
|
51
|
+
return std::make_shared<facebook::react::NativeAudioAPIModuleSpecJSI>(params);
|
|
52
|
+
}
|
|
53
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
54
|
+
|
|
48
55
|
@end
|
package/ios/core/AudioDecoder.mm
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
|
10
|
-
AudioBus
|
|
10
|
+
std::shared_ptr<AudioBus> AudioDecoder::decodeWithFilePath(const std::string &path) const
|
|
11
11
|
{
|
|
12
12
|
ma_decoder decoder;
|
|
13
13
|
ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 2, sampleRate_);
|
|
@@ -23,7 +23,7 @@ AudioBus *AudioDecoder::decodeWithFilePath(const std::string &path) const
|
|
|
23
23
|
ma_uint64 totalFrameCount;
|
|
24
24
|
ma_decoder_get_length_in_pcm_frames(&decoder, &totalFrameCount);
|
|
25
25
|
|
|
26
|
-
auto
|
|
26
|
+
auto audioBus = std::make_shared<AudioBus>(static_cast<int>(totalFrameCount), 2, sampleRate_);
|
|
27
27
|
auto *buffer = new float[totalFrameCount * 2];
|
|
28
28
|
|
|
29
29
|
ma_uint64 framesDecoded;
|
|
@@ -32,7 +32,6 @@ AudioBus *AudioDecoder::decodeWithFilePath(const std::string &path) const
|
|
|
32
32
|
NSLog(@"Failed to decode audio file: %s", path.c_str());
|
|
33
33
|
|
|
34
34
|
delete[] buffer;
|
|
35
|
-
delete audioBus;
|
|
36
35
|
ma_decoder_uninit(&decoder);
|
|
37
36
|
|
|
38
37
|
return nullptr;
|
package/ios/core/AudioPlayer.h
CHANGED
|
@@ -9,10 +9,12 @@ typedef void (^RenderAudioBlock)(AudioBufferList *outputBuffer, int numFrames);
|
|
|
9
9
|
|
|
10
10
|
@property (nonatomic, strong) AVAudioEngine *audioEngine;
|
|
11
11
|
@property (nonatomic, weak) AVAudioSession *audioSession;
|
|
12
|
+
@property (nonatomic, weak) NSNotificationCenter *notificationCenter;
|
|
12
13
|
@property (nonatomic, strong) AVAudioFormat *format;
|
|
13
14
|
@property (nonatomic, strong) AVAudioSourceNode *sourceNode;
|
|
14
15
|
@property (nonatomic, copy) RenderAudioBlock renderAudio;
|
|
15
16
|
@property (nonatomic, assign) float sampleRate;
|
|
17
|
+
@property (nonatomic, assign) bool isRunning;
|
|
16
18
|
|
|
17
19
|
- (instancetype)initWithRenderAudioBlock:(RenderAudioBlock)renderAudio;
|
|
18
20
|
|
|
@@ -24,6 +26,18 @@ typedef void (^RenderAudioBlock)(AudioBufferList *outputBuffer, int numFrames);
|
|
|
24
26
|
|
|
25
27
|
- (void)stop;
|
|
26
28
|
|
|
29
|
+
- (void)resume;
|
|
30
|
+
|
|
31
|
+
- (void)suspend;
|
|
32
|
+
|
|
27
33
|
- (void)cleanup;
|
|
28
34
|
|
|
35
|
+
- (void)setupAndInitAudioSession;
|
|
36
|
+
|
|
37
|
+
- (void)setupAndInitNotificationHandlers;
|
|
38
|
+
|
|
39
|
+
- (void)connectAudioEngine;
|
|
40
|
+
|
|
41
|
+
- (void)handleEngineConfigurationChange:(NSNotification *)notification;
|
|
42
|
+
|
|
29
43
|
@end
|
package/ios/core/AudioPlayer.m
CHANGED
|
@@ -8,15 +8,11 @@
|
|
|
8
8
|
self.renderAudio = [renderAudio copy];
|
|
9
9
|
self.audioEngine = [[AVAudioEngine alloc] init];
|
|
10
10
|
self.audioEngine.mainMixerNode.outputVolume = 1;
|
|
11
|
+
self.isRunning = true;
|
|
11
12
|
|
|
12
|
-
self
|
|
13
|
+
[self setupAndInitAudioSession];
|
|
14
|
+
[self setupAndInitNotificationHandlers];
|
|
13
15
|
|
|
14
|
-
// TODO:
|
|
15
|
-
// We will probably want to change it to AVAudioSessionCategoryPlayAndRecord in the future.
|
|
16
|
-
// Eventually we to make this a dynamic setting, if user of the lib wants to use recording features.
|
|
17
|
-
// But setting a recording category might require some setup first, so lets skip it for now :)
|
|
18
|
-
// [self.audioSession setCategory:AVAudioSessionCategoryPlayback error:&error];
|
|
19
|
-
// [self.audioSession setActive:true error:&error];
|
|
20
16
|
|
|
21
17
|
self.sampleRate = [self.audioSession sampleRate];
|
|
22
18
|
|
|
@@ -45,15 +41,10 @@
|
|
|
45
41
|
self.renderAudio = [renderAudio copy];
|
|
46
42
|
self.audioEngine = [[AVAudioEngine alloc] init];
|
|
47
43
|
self.audioEngine.mainMixerNode.outputVolume = 1;
|
|
44
|
+
self.isRunning = true;
|
|
48
45
|
|
|
49
|
-
self
|
|
50
|
-
|
|
51
|
-
// TODO:
|
|
52
|
-
// We will probably want to change it to AVAudioSessionCategoryPlayAndRecord in the future.
|
|
53
|
-
// Eventually we to make this a dynamic setting, if user of the lib wants to use recording features.
|
|
54
|
-
// But setting a recording category might require some setup first, so lets skip it for now :)
|
|
55
|
-
// [self.audioSession setCategory:AVAudioSessionCategoryPlayback error:&error];
|
|
56
|
-
// [self.audioSession setActive:true error:&error];
|
|
46
|
+
[self setupAndInitAudioSession];
|
|
47
|
+
[self setupAndInitNotificationHandlers];
|
|
57
48
|
|
|
58
49
|
self.sampleRate = sampleRate;
|
|
59
50
|
|
|
@@ -83,19 +74,13 @@
|
|
|
83
74
|
|
|
84
75
|
- (void)start
|
|
85
76
|
{
|
|
86
|
-
|
|
87
|
-
[self
|
|
88
|
-
|
|
89
|
-
if (!self.audioEngine.isRunning) {
|
|
90
|
-
NSError *error = nil;
|
|
91
|
-
if (![self.audioEngine startAndReturnError:&error]) {
|
|
92
|
-
NSLog(@"Error starting audio engine: %@", [error localizedDescription]);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
77
|
+
self.isRunning = true;
|
|
78
|
+
[self connectAudioEngine];
|
|
95
79
|
}
|
|
96
80
|
|
|
97
81
|
- (void)stop
|
|
98
82
|
{
|
|
83
|
+
self.isRunning = false;
|
|
99
84
|
[self.audioEngine detachNode:self.sourceNode];
|
|
100
85
|
|
|
101
86
|
if (self.audioEngine.isRunning) {
|
|
@@ -110,6 +95,19 @@
|
|
|
110
95
|
}
|
|
111
96
|
}
|
|
112
97
|
|
|
98
|
+
- (void)suspend
|
|
99
|
+
{
|
|
100
|
+
[self.audioEngine pause];
|
|
101
|
+
self.isRunning = false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
- (void)resume
|
|
105
|
+
{
|
|
106
|
+
self.isRunning = true;
|
|
107
|
+
[self setupAndInitAudioSession];
|
|
108
|
+
[self connectAudioEngine];
|
|
109
|
+
}
|
|
110
|
+
|
|
113
111
|
- (void)cleanup
|
|
114
112
|
{
|
|
115
113
|
self.audioEngine = nil;
|
|
@@ -131,4 +129,67 @@
|
|
|
131
129
|
return noErr;
|
|
132
130
|
}
|
|
133
131
|
|
|
132
|
+
- (void)setupAndInitAudioSession
|
|
133
|
+
{
|
|
134
|
+
NSError *error = nil;
|
|
135
|
+
|
|
136
|
+
if (!self.audioSession) {
|
|
137
|
+
self.audioSession = [AVAudioSession sharedInstance];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
[self.audioSession setCategory:AVAudioSessionCategoryPlayback
|
|
141
|
+
mode:AVAudioSessionModeDefault
|
|
142
|
+
options:AVAudioSessionCategoryOptionDuckOthers|AVAudioSessionCategoryOptionAllowBluetooth|AVAudioSessionCategoryOptionAllowAirPlay
|
|
143
|
+
error:&error];
|
|
144
|
+
|
|
145
|
+
if (error != nil) {
|
|
146
|
+
NSLog(@"Error while configuring audio session: %@", [error localizedDescription]);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
[self.audioSession setActive:true error:&error];
|
|
150
|
+
|
|
151
|
+
if (error != nil) {
|
|
152
|
+
NSLog(@"Error while activating audio session: %@", [error localizedDescription]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
- (void)setupAndInitNotificationHandlers
|
|
157
|
+
{
|
|
158
|
+
if (!self.notificationCenter) {
|
|
159
|
+
self.notificationCenter = [NSNotificationCenter defaultCenter];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
[self.notificationCenter addObserver:self
|
|
163
|
+
selector:@selector(handleEngineConfigurationChange:)
|
|
164
|
+
name:AVAudioEngineConfigurationChangeNotification
|
|
165
|
+
object:nil];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
- (void)connectAudioEngine
|
|
169
|
+
{
|
|
170
|
+
if ([self.audioEngine isRunning]) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
[self.audioEngine attachNode:self.sourceNode];
|
|
175
|
+
[self.audioEngine connect:self.sourceNode to:self.audioEngine.mainMixerNode format:self.format];
|
|
176
|
+
|
|
177
|
+
if (![self.audioEngine isRunning]) {
|
|
178
|
+
NSError *error = nil;
|
|
179
|
+
|
|
180
|
+
if (![self.audioEngine startAndReturnError:&error]) {
|
|
181
|
+
NSLog(@"Error starting audio engine: %@", [error localizedDescription]);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
- (void)handleEngineConfigurationChange:(NSNotification *)notification
|
|
187
|
+
{
|
|
188
|
+
if (!self.isRunning) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
[self connectAudioEngine];
|
|
193
|
+
}
|
|
194
|
+
|
|
134
195
|
@end
|
|
@@ -15,15 +15,15 @@ class AudioBus;
|
|
|
15
15
|
|
|
16
16
|
class IOSAudioPlayer {
|
|
17
17
|
protected:
|
|
18
|
-
AudioBus
|
|
18
|
+
std::shared_ptr<AudioBus> audioBus_;
|
|
19
19
|
AudioPlayer *audioPlayer_;
|
|
20
|
-
std::function<void(AudioBus
|
|
20
|
+
std::function<void(std::shared_ptr<AudioBus>, int)> renderAudio_;
|
|
21
21
|
|
|
22
22
|
public:
|
|
23
23
|
explicit IOSAudioPlayer(
|
|
24
|
-
const std::function<void(AudioBus
|
|
24
|
+
const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio);
|
|
25
25
|
IOSAudioPlayer(
|
|
26
|
-
const std::function<void(AudioBus
|
|
26
|
+
const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio,
|
|
27
27
|
float sampleRate);
|
|
28
28
|
~IOSAudioPlayer();
|
|
29
29
|
|
|
@@ -31,5 +31,7 @@ class IOSAudioPlayer {
|
|
|
31
31
|
|
|
32
32
|
void start();
|
|
33
33
|
void stop();
|
|
34
|
+
void resume();
|
|
35
|
+
void suspend();
|
|
34
36
|
};
|
|
35
37
|
} // namespace audioapi
|
|
@@ -7,11 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
|
10
|
-
IOSAudioPlayer::IOSAudioPlayer(const std::function<void(AudioBus
|
|
10
|
+
IOSAudioPlayer::IOSAudioPlayer(const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio)
|
|
11
11
|
: renderAudio_(renderAudio), audioBus_(0)
|
|
12
12
|
{
|
|
13
|
-
audioBus_ = new AudioBus(RENDER_QUANTUM_SIZE, CHANNEL_COUNT, getSampleRate());
|
|
14
|
-
|
|
15
13
|
RenderAudioBlock renderAudioBlock = ^(AudioBufferList *outputData, int numFrames) {
|
|
16
14
|
int processedFrames = 0;
|
|
17
15
|
|
|
@@ -34,10 +32,10 @@ IOSAudioPlayer::IOSAudioPlayer(const std::function<void(AudioBus *, int)> &rende
|
|
|
34
32
|
};
|
|
35
33
|
|
|
36
34
|
audioPlayer_ = [[AudioPlayer alloc] initWithRenderAudioBlock:renderAudioBlock];
|
|
37
|
-
audioBus_ =
|
|
35
|
+
audioBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, CHANNEL_COUNT, getSampleRate());
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
IOSAudioPlayer::IOSAudioPlayer(const std::function<void(AudioBus
|
|
38
|
+
IOSAudioPlayer::IOSAudioPlayer(const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio, float sampleRate)
|
|
41
39
|
: renderAudio_(renderAudio), audioBus_(0)
|
|
42
40
|
{
|
|
43
41
|
RenderAudioBlock renderAudioBlock = ^(AudioBufferList *outputData, int numFrames) {
|
|
@@ -62,7 +60,7 @@ IOSAudioPlayer::IOSAudioPlayer(const std::function<void(AudioBus *, int)> &rende
|
|
|
62
60
|
};
|
|
63
61
|
|
|
64
62
|
audioPlayer_ = [[AudioPlayer alloc] initWithRenderAudioBlock:renderAudioBlock sampleRate:sampleRate];
|
|
65
|
-
audioBus_ =
|
|
63
|
+
audioBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, CHANNEL_COUNT, getSampleRate());
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
IOSAudioPlayer::~IOSAudioPlayer()
|
|
@@ -71,7 +69,6 @@ IOSAudioPlayer::~IOSAudioPlayer()
|
|
|
71
69
|
[audioPlayer_ cleanup];
|
|
72
70
|
|
|
73
71
|
if (audioBus_) {
|
|
74
|
-
delete audioBus_;
|
|
75
72
|
audioBus_ = 0;
|
|
76
73
|
}
|
|
77
74
|
}
|
|
@@ -86,6 +83,16 @@ void IOSAudioPlayer::stop()
|
|
|
86
83
|
return [audioPlayer_ stop];
|
|
87
84
|
}
|
|
88
85
|
|
|
86
|
+
void IOSAudioPlayer::resume()
|
|
87
|
+
{
|
|
88
|
+
return [audioPlayer_ resume];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
void IOSAudioPlayer::suspend()
|
|
92
|
+
{
|
|
93
|
+
return [audioPlayer_ suspend];
|
|
94
|
+
}
|
|
95
|
+
|
|
89
96
|
float IOSAudioPlayer::getSampleRate() const
|
|
90
97
|
{
|
|
91
98
|
return [audioPlayer_ getSampleRate];
|
|
@@ -7,10 +7,16 @@ export default class AudioContext extends BaseAudioContext {
|
|
|
7
7
|
if (options && (options.sampleRate < 8000 || options.sampleRate > 96000)) {
|
|
8
8
|
throw new NotSupportedError(`The provided sampleRate is not supported: ${options.sampleRate}`);
|
|
9
9
|
}
|
|
10
|
-
super(global.
|
|
10
|
+
super(global.createAudioContext(options?.sampleRate));
|
|
11
11
|
}
|
|
12
12
|
async close() {
|
|
13
13
|
await this.context.close();
|
|
14
14
|
}
|
|
15
|
+
async resume() {
|
|
16
|
+
await this.context.resume();
|
|
17
|
+
}
|
|
18
|
+
async suspend() {
|
|
19
|
+
await this.context.suspend();
|
|
20
|
+
}
|
|
15
21
|
}
|
|
16
22
|
//# sourceMappingURL=AudioContext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["BaseAudioContext","NotSupportedError","AudioContext","constructor","options","sampleRate","global","
|
|
1
|
+
{"version":3,"names":["BaseAudioContext","NotSupportedError","AudioContext","constructor","options","sampleRate","global","createAudioContext","close","context","resume","suspend"],"sourceRoot":"../../../src","sources":["core/AudioContext.ts"],"mappings":";;AACA,OAAOA,gBAAgB,MAAM,uBAAoB;AAEjD,SAASC,iBAAiB,QAAQ,oBAAW;AAE7C,eAAe,MAAMC,YAAY,SAASF,gBAAgB,CAAC;EACzDG,WAAWA,CAACC,OAA6B,EAAE;IACzC,IAAIA,OAAO,KAAKA,OAAO,CAACC,UAAU,GAAG,IAAI,IAAID,OAAO,CAACC,UAAU,GAAG,KAAK,CAAC,EAAE;MACxE,MAAM,IAAIJ,iBAAiB,CACzB,6CAA6CG,OAAO,CAACC,UAAU,EACjE,CAAC;IACH;IAEA,KAAK,CAACC,MAAM,CAACC,kBAAkB,CAACH,OAAO,EAAEC,UAAU,CAAC,CAAC;EACvD;EAEA,MAAMG,KAAKA,CAAA,EAAuB;IAChC,MAAO,IAAI,CAACC,OAAO,CAAmBD,KAAK,CAAC,CAAC;EAC/C;EAEA,MAAME,MAAMA,CAAA,EAAuB;IACjC,MAAO,IAAI,CAACD,OAAO,CAAmBC,MAAM,CAAC,CAAC;EAChD;EAEA,MAAMC,OAAOA,CAAA,EAAuB;IAClC,MAAO,IAAI,CAACF,OAAO,CAAmBE,OAAO,CAAC,CAAC;EACjD;AACF","ignoreList":[]}
|