react-native-audio-api 0.7.1-nightly-968a0e5-20250812 → 0.7.1
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/common/cpp/audioapi/HostObjects/AudioBufferHostObject.h +35 -12
- package/common/cpp/audioapi/core/utils/AudioNodeManager.cpp +4 -2
- package/common/cpp/audioapi/jsi/JsiHostObject.cpp +35 -7
- package/common/cpp/audioapi/jsi/JsiHostObject.h +8 -4
- package/ios/audioapi/ios/core/NativeAudioPlayer.m +11 -4
- package/ios/audioapi/ios/core/NativeAudioRecorder.m +9 -0
- package/package.json +1 -1
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
-
#include <audioapi/jsi/JsiHostObject.h>
|
|
4
|
-
#include <audioapi/jsi/AudioArrayBuffer.h>
|
|
5
3
|
#include <audioapi/core/sources/AudioBuffer.h>
|
|
4
|
+
#include <audioapi/jsi/AudioArrayBuffer.h>
|
|
5
|
+
#include <audioapi/jsi/JsiHostObject.h>
|
|
6
6
|
|
|
7
7
|
#include <jsi/jsi.h>
|
|
8
|
+
#include <cstddef>
|
|
8
9
|
#include <memory>
|
|
10
|
+
#include <utility>
|
|
9
11
|
#include <vector>
|
|
10
|
-
#include <cstddef>
|
|
11
12
|
|
|
12
13
|
namespace audioapi {
|
|
13
14
|
using namespace facebook;
|
|
@@ -30,9 +31,22 @@ class AudioBufferHostObject : public JsiHostObject {
|
|
|
30
31
|
JSI_EXPORT_FUNCTION(AudioBufferHostObject, copyFromChannel),
|
|
31
32
|
JSI_EXPORT_FUNCTION(AudioBufferHostObject, copyToChannel));
|
|
32
33
|
}
|
|
34
|
+
AudioBufferHostObject(const AudioBufferHostObject &) = delete;
|
|
35
|
+
AudioBufferHostObject &operator=(const AudioBufferHostObject &) = delete;
|
|
36
|
+
AudioBufferHostObject(AudioBufferHostObject &&other) noexcept
|
|
37
|
+
: JsiHostObject(std::move(other)),
|
|
38
|
+
audioBuffer_(std::move(other.audioBuffer_)) {}
|
|
39
|
+
AudioBufferHostObject &operator=(AudioBufferHostObject &&other) noexcept {
|
|
40
|
+
if (this != &other) {
|
|
41
|
+
JsiHostObject::operator=(std::move(other));
|
|
42
|
+
audioBuffer_ = std::move(other.audioBuffer_);
|
|
43
|
+
}
|
|
44
|
+
return *this;
|
|
45
|
+
}
|
|
33
46
|
|
|
34
47
|
[[nodiscard]] size_t getSizeInBytes() const {
|
|
35
|
-
return audioBuffer_->getLength() * audioBuffer_->getNumberOfChannels() *
|
|
48
|
+
return audioBuffer_->getLength() * audioBuffer_->getNumberOfChannels() *
|
|
49
|
+
sizeof(float);
|
|
36
50
|
}
|
|
37
51
|
|
|
38
52
|
JSI_PROPERTY_GETTER(sampleRate) {
|
|
@@ -53,23 +67,30 @@ class AudioBufferHostObject : public JsiHostObject {
|
|
|
53
67
|
|
|
54
68
|
JSI_HOST_FUNCTION(getChannelData) {
|
|
55
69
|
auto channel = static_cast<int>(args[0].getNumber());
|
|
56
|
-
auto channelData =
|
|
70
|
+
auto channelData =
|
|
71
|
+
reinterpret_cast<uint8_t *>(audioBuffer_->getChannelData(channel));
|
|
57
72
|
auto length = static_cast<int>(audioBuffer_->getLength());
|
|
58
73
|
auto size = static_cast<int>(length * sizeof(float));
|
|
59
74
|
|
|
60
75
|
// reading or writing from this ArrayBuffer could cause a crash
|
|
61
76
|
// if underlying channelData is deallocated
|
|
62
|
-
auto audioArrayBuffer =
|
|
77
|
+
auto audioArrayBuffer =
|
|
78
|
+
std::make_shared<AudioArrayBuffer>(channelData, size);
|
|
63
79
|
auto arrayBuffer = jsi::ArrayBuffer(runtime, audioArrayBuffer);
|
|
64
80
|
|
|
65
|
-
auto float32ArrayCtor =
|
|
66
|
-
|
|
81
|
+
auto float32ArrayCtor =
|
|
82
|
+
runtime.global().getPropertyAsFunction(runtime, "Float32Array");
|
|
83
|
+
auto float32Array = float32ArrayCtor.callAsConstructor(runtime, arrayBuffer)
|
|
84
|
+
.getObject(runtime);
|
|
67
85
|
|
|
68
86
|
return float32Array;
|
|
69
87
|
}
|
|
70
88
|
|
|
71
89
|
JSI_HOST_FUNCTION(copyFromChannel) {
|
|
72
|
-
auto arrayBuffer = args[0]
|
|
90
|
+
auto arrayBuffer = args[0]
|
|
91
|
+
.getObject(runtime)
|
|
92
|
+
.getPropertyAsObject(runtime, "buffer")
|
|
93
|
+
.getArrayBuffer(runtime);
|
|
73
94
|
auto destination = reinterpret_cast<float *>(arrayBuffer.data(runtime));
|
|
74
95
|
auto length = static_cast<int>(arrayBuffer.size(runtime));
|
|
75
96
|
auto channelNumber = static_cast<int>(args[1].getNumber());
|
|
@@ -82,14 +103,16 @@ class AudioBufferHostObject : public JsiHostObject {
|
|
|
82
103
|
}
|
|
83
104
|
|
|
84
105
|
JSI_HOST_FUNCTION(copyToChannel) {
|
|
85
|
-
auto arrayBuffer = args[0]
|
|
106
|
+
auto arrayBuffer = args[0]
|
|
107
|
+
.getObject(runtime)
|
|
108
|
+
.getPropertyAsObject(runtime, "buffer")
|
|
109
|
+
.getArrayBuffer(runtime);
|
|
86
110
|
auto source = reinterpret_cast<float *>(arrayBuffer.data(runtime));
|
|
87
111
|
auto length = static_cast<int>(arrayBuffer.size(runtime));
|
|
88
112
|
auto channelNumber = static_cast<int>(args[1].getNumber());
|
|
89
113
|
auto startInChannel = static_cast<size_t>(args[2].getNumber());
|
|
90
114
|
|
|
91
|
-
audioBuffer_->copyToChannel(
|
|
92
|
-
source, length, channelNumber, startInChannel);
|
|
115
|
+
audioBuffer_->copyToChannel(source, length, channelNumber, startInChannel);
|
|
93
116
|
|
|
94
117
|
return jsi::Value::undefined();
|
|
95
118
|
}
|
|
@@ -72,8 +72,10 @@ void AudioNodeManager::settlePendingConnections() {
|
|
|
72
72
|
assert(to != nullptr);
|
|
73
73
|
from->disconnectNode(to);
|
|
74
74
|
} else {
|
|
75
|
-
for (auto
|
|
76
|
-
|
|
75
|
+
for (auto it = from->outputNodes_.begin(); it != from->outputNodes_.end();) {
|
|
76
|
+
auto next = std::next(it);
|
|
77
|
+
from->disconnectNode(*it);
|
|
78
|
+
it = next;
|
|
77
79
|
}
|
|
78
80
|
}
|
|
79
81
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#include <audioapi/jsi/JsiHostObject.h>
|
|
2
2
|
|
|
3
3
|
// set this value to 1 in order to debug the construction/destruction
|
|
4
|
-
#define JSI_DEBUG_ALLOCATIONS
|
|
4
|
+
#define JSI_DEBUG_ALLOCATIONS 0
|
|
5
5
|
|
|
6
6
|
namespace audioapi {
|
|
7
7
|
|
|
@@ -28,15 +28,43 @@ JsiHostObject::JsiHostObject() {
|
|
|
28
28
|
#endif
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
JsiHostObject
|
|
31
|
+
JsiHostObject::JsiHostObject(JsiHostObject &&other) noexcept
|
|
32
|
+
: getters_(std::move(other.getters_)),
|
|
33
|
+
functions_(std::move(other.functions_)),
|
|
34
|
+
setters_(std::move(other.setters_)) {
|
|
35
|
+
#if JSI_DEBUG_ALLOCATIONS
|
|
36
|
+
auto it = std::find(objects.begin(), objects.end(), &other);
|
|
37
|
+
if (it != objects.end()) {
|
|
38
|
+
objects.erase(it);
|
|
39
|
+
}
|
|
40
|
+
objects.push_back(this);
|
|
41
|
+
#endif
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
JsiHostObject &JsiHostObject::operator=(JsiHostObject &&other) noexcept {
|
|
45
|
+
if (this != &other) {
|
|
46
|
+
getters_ = std::move(other.getters_);
|
|
47
|
+
functions_ = std::move(other.functions_);
|
|
48
|
+
setters_ = std::move(other.setters_);
|
|
49
|
+
|
|
32
50
|
#if JSI_DEBUG_ALLOCATIONS
|
|
33
|
-
|
|
34
|
-
if (objects.
|
|
35
|
-
objects.erase(
|
|
36
|
-
break;
|
|
51
|
+
auto it = std::find(objects.begin(), objects.end(), &other);
|
|
52
|
+
if (it != objects.end()) {
|
|
53
|
+
objects.erase(it);
|
|
37
54
|
}
|
|
55
|
+
objects.push_back(this);
|
|
56
|
+
#endif
|
|
57
|
+
}
|
|
58
|
+
return *this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
JsiHostObject::~JsiHostObject() {
|
|
62
|
+
#if JSI_DEBUG_ALLOCATIONS
|
|
63
|
+
auto it = std::find(objects.begin(), objects.end(), this);
|
|
64
|
+
if (it != objects.end()) {
|
|
65
|
+
objects.erase(it);
|
|
66
|
+
objCounter--;
|
|
38
67
|
}
|
|
39
|
-
objCounter--;
|
|
40
68
|
#endif
|
|
41
69
|
}
|
|
42
70
|
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
#include <utility>
|
|
11
11
|
#include <vector>
|
|
12
12
|
|
|
13
|
-
#define JSI_HOST_FUNCTION(NAME)
|
|
14
|
-
jsi::Value NAME(
|
|
15
|
-
jsi::Runtime &runtime,
|
|
13
|
+
#define JSI_HOST_FUNCTION(NAME) \
|
|
14
|
+
jsi::Value NAME( \
|
|
15
|
+
jsi::Runtime &runtime, \
|
|
16
16
|
const jsi::Value &thisValue, \
|
|
17
|
-
const jsi::Value *args,
|
|
17
|
+
const jsi::Value *args, \
|
|
18
18
|
size_t count)
|
|
19
19
|
|
|
20
20
|
#define JSI_EXPORT_FUNCTION(CLASS, FUNCTION) \
|
|
@@ -48,6 +48,10 @@ using namespace facebook;
|
|
|
48
48
|
class JsiHostObject : public jsi::HostObject {
|
|
49
49
|
public:
|
|
50
50
|
JsiHostObject();
|
|
51
|
+
JsiHostObject(const JsiHostObject &) = delete;
|
|
52
|
+
JsiHostObject &operator=(const JsiHostObject &) = delete;
|
|
53
|
+
JsiHostObject(JsiHostObject &&) noexcept;
|
|
54
|
+
JsiHostObject &operator=(JsiHostObject &&other) noexcept;
|
|
51
55
|
~JsiHostObject() override;
|
|
52
56
|
|
|
53
57
|
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;
|
|
@@ -35,11 +35,19 @@
|
|
|
35
35
|
- (bool)start
|
|
36
36
|
{
|
|
37
37
|
NSLog(@"[AudioPlayer] start");
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
AudioEngine *audioEngine = [AudioEngine sharedInstance];
|
|
40
40
|
assert(audioEngine != nil);
|
|
41
|
+
|
|
42
|
+
// AudioEngine allows us to attach and connect nodes at runtime but with few limitations
|
|
43
|
+
// in this case if it is the first player and recorder started the engine we need to restart.
|
|
44
|
+
// It can be optimized by tracking if we haven't break rules of at runtime modifications from docs
|
|
45
|
+
// https://developer.apple.com/documentation/avfaudio/avaudioengine?language=objc
|
|
46
|
+
//
|
|
47
|
+
// Currently we are restarting because we do not see any significant performance issue and case when
|
|
48
|
+
// you will need to start and stop player very frequently
|
|
49
|
+
[audioEngine stopEngine];
|
|
41
50
|
self.sourceNodeId = [audioEngine attachSourceNode:self.sourceNode format:self.format];
|
|
42
|
-
|
|
43
51
|
return [audioEngine startIfNecessary];
|
|
44
52
|
}
|
|
45
53
|
|
|
@@ -59,9 +67,8 @@
|
|
|
59
67
|
NSLog(@"[AudioPlayer] resume");
|
|
60
68
|
AudioEngine *audioEngine = [AudioEngine sharedInstance];
|
|
61
69
|
assert(audioEngine != nil);
|
|
62
|
-
[audioEngine startEngine];
|
|
63
70
|
|
|
64
|
-
return [audioEngine
|
|
71
|
+
return [audioEngine startIfNecessary];
|
|
65
72
|
}
|
|
66
73
|
|
|
67
74
|
- (void)suspend
|
|
@@ -100,6 +100,15 @@
|
|
|
100
100
|
{
|
|
101
101
|
AudioEngine *audioEngine = [AudioEngine sharedInstance];
|
|
102
102
|
assert(audioEngine != nil);
|
|
103
|
+
|
|
104
|
+
// AudioEngine allows us to attach and connect nodes at runtime but with few limitations
|
|
105
|
+
// in this case if it is the first recorder node and player started the engine we need to restart.
|
|
106
|
+
// It can be optimized by tracking if we haven't break rules of at runtime modifications from docs
|
|
107
|
+
// https://developer.apple.com/documentation/avfaudio/avaudioengine?language=objc
|
|
108
|
+
//
|
|
109
|
+
// Currently we are restarting because we do not see any significant performance issue and case when
|
|
110
|
+
// you will need to start and stop recorder very frequently
|
|
111
|
+
[audioEngine stopEngine];
|
|
103
112
|
[audioEngine attachInputNode:self.sinkNode];
|
|
104
113
|
[audioEngine startIfNecessary];
|
|
105
114
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-audio-api",
|
|
3
|
-
"version": "0.7.1
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "react-native-audio-api provides system for controlling audio in React Native environment compatible with Web Audio API specification",
|
|
5
5
|
"bin": {
|
|
6
6
|
"setup-rn-audio-api-web": "./scripts/setup-rn-audio-api-web.js"
|