react-native-audio-api 0.6.4-nightly-c1e4367-20250715 → 0.6.4-nightly-61e39e7-20250716
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/AudioBufferBaseSourceNodeHostObject.h +9 -0
- package/common/cpp/audioapi/HostObjects/AudioScheduledSourceNodeHostObject.h +9 -0
- package/common/cpp/audioapi/core/AudioParam.cpp +4 -5
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +11 -0
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +3 -1
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +11 -0
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +2 -1
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +32 -4
- package/ios/audioapi/ios/AudioAPIModule.mm +10 -13
- package/package.json +1 -1
|
@@ -26,6 +26,15 @@ class AudioBufferBaseSourceNodeHostObject
|
|
|
26
26
|
JSI_EXPORT_PROPERTY_SETTER(AudioBufferBaseSourceNodeHostObject, onPositionChangedInterval));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
~AudioBufferBaseSourceNodeHostObject() {
|
|
30
|
+
auto sourceNode =
|
|
31
|
+
std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
|
|
32
|
+
|
|
33
|
+
// When JSI object is garbage collected (together with the eventual callback),
|
|
34
|
+
// underlying source node might still be active and try to call the non-existing callback.
|
|
35
|
+
sourceNode->clearOnPositionChangedCallback();
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
JSI_PROPERTY_GETTER(detune) {
|
|
30
39
|
auto sourceNode =
|
|
31
40
|
std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
|
|
@@ -21,6 +21,15 @@ class AudioScheduledSourceNodeHostObject : public AudioNodeHostObject {
|
|
|
21
21
|
JSI_EXPORT_FUNCTION(AudioScheduledSourceNodeHostObject, stop));
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
~AudioScheduledSourceNodeHostObject() {
|
|
25
|
+
auto audioScheduledSourceNode =
|
|
26
|
+
std::static_pointer_cast<AudioScheduledSourceNode>(node_);
|
|
27
|
+
|
|
28
|
+
// When JSI object is garbage collected (together with the eventual callback),
|
|
29
|
+
// underlying source node might still be active and try to call the non-existing callback.
|
|
30
|
+
audioScheduledSourceNode->clearOnEndedCallback();
|
|
31
|
+
}
|
|
32
|
+
|
|
24
33
|
JSI_PROPERTY_SETTER(onEnded) {
|
|
25
34
|
auto audioScheduleSourceNode =
|
|
26
35
|
std::static_pointer_cast<AudioScheduledSourceNode>(node_);
|
|
@@ -18,11 +18,10 @@ AudioParam::AudioParam(
|
|
|
18
18
|
minValue_(minValue),
|
|
19
19
|
maxValue_(maxValue),
|
|
20
20
|
context_(context),
|
|
21
|
-
audioBus_(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
context->getSampleRate())) {
|
|
21
|
+
audioBus_(std::make_shared<AudioBus>(
|
|
22
|
+
RENDER_QUANTUM_SIZE,
|
|
23
|
+
1,
|
|
24
|
+
context->getSampleRate())) {
|
|
26
25
|
startTime_ = 0;
|
|
27
26
|
endTime_ = 0;
|
|
28
27
|
startValue_ = value_;
|
|
@@ -41,6 +41,17 @@ std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getPlaybackRateParam()
|
|
|
41
41
|
return playbackRateParam_;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
void AudioBufferBaseSourceNode::clearOnPositionChangedCallback() {
|
|
45
|
+
if (onPositionChangedCallbackId_ == 0 || context_ == nullptr ||
|
|
46
|
+
context_->audioEventHandlerRegistry_ == nullptr) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
context_->audioEventHandlerRegistry_->unregisterHandler(
|
|
51
|
+
"positionChanged", onPositionChangedCallbackId_);
|
|
52
|
+
onPositionChangedCallbackId_ = 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
void AudioBufferBaseSourceNode::setOnPositionChangedCallbackId(
|
|
45
56
|
uint64_t callbackId) {
|
|
46
57
|
onPositionChangedCallbackId_ = callbackId;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
#include <memory>
|
|
7
7
|
#include <mutex>
|
|
8
|
+
#include <atomic>
|
|
8
9
|
|
|
9
10
|
namespace audioapi {
|
|
10
11
|
|
|
@@ -19,6 +20,7 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
|
|
|
19
20
|
[[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
|
|
20
21
|
[[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
|
|
21
22
|
|
|
23
|
+
void clearOnPositionChangedCallback();
|
|
22
24
|
void setOnPositionChangedCallbackId(uint64_t callbackId);
|
|
23
25
|
void setOnPositionChangedInterval(int interval);
|
|
24
26
|
[[nodiscard]] int getOnPositionChangedInterval();
|
|
@@ -37,7 +39,7 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
|
|
|
37
39
|
// internal helper
|
|
38
40
|
double vReadIndex_;
|
|
39
41
|
|
|
40
|
-
uint64_t onPositionChangedCallbackId_ = 0; // 0 means no callback
|
|
42
|
+
std::atomic<uint64_t> onPositionChangedCallbackId_ = 0; // 0 means no callback
|
|
41
43
|
int onPositionChangedInterval_;
|
|
42
44
|
int onPositionChangedTime_ = 0;
|
|
43
45
|
|
|
@@ -54,6 +54,17 @@ bool AudioScheduledSourceNode::isStopScheduled() {
|
|
|
54
54
|
return playbackState_ == PlaybackState::STOP_SCHEDULED;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
void AudioScheduledSourceNode::clearOnEndedCallback() {
|
|
58
|
+
if (onEndedCallbackId_ == 0 || context_ == nullptr ||
|
|
59
|
+
context_->audioEventHandlerRegistry_ == nullptr) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
context_->audioEventHandlerRegistry_->unregisterHandler(
|
|
64
|
+
"ended", onEndedCallbackId_);
|
|
65
|
+
onEndedCallbackId_ = 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
57
68
|
void AudioScheduledSourceNode::setOnEndedCallbackId(const uint64_t callbackId) {
|
|
58
69
|
onEndedCallbackId_ = callbackId;
|
|
59
70
|
}
|
|
@@ -38,6 +38,7 @@ class AudioScheduledSourceNode : public AudioNode {
|
|
|
38
38
|
bool isFinished();
|
|
39
39
|
bool isStopScheduled();
|
|
40
40
|
|
|
41
|
+
void clearOnEndedCallback();
|
|
41
42
|
void setOnEndedCallbackId(uint64_t callbackId);
|
|
42
43
|
|
|
43
44
|
void disable() override;
|
|
@@ -48,7 +49,7 @@ class AudioScheduledSourceNode : public AudioNode {
|
|
|
48
49
|
|
|
49
50
|
PlaybackState playbackState_;
|
|
50
51
|
|
|
51
|
-
uint64_t onEndedCallbackId_ = 0;
|
|
52
|
+
std::atomic<uint64_t> onEndedCallbackId_ = 0;
|
|
52
53
|
|
|
53
54
|
void updatePlaybackInfo(
|
|
54
55
|
const std::shared_ptr<AudioBus>& processingBus,
|
|
@@ -92,8 +92,18 @@ void AudioEventHandlerRegistry::invokeHandlerWithEventBody(
|
|
|
92
92
|
continue;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
try {
|
|
96
|
+
auto eventObject = createEventObject(body);
|
|
97
|
+
handler->call(*runtime_, eventObject);
|
|
98
|
+
} catch (const std::exception &e) {
|
|
99
|
+
// re-throw the exception to be handled by the caller
|
|
100
|
+
// std::exception is safe to parse by the rn bridge
|
|
101
|
+
throw;
|
|
102
|
+
} catch (...) {
|
|
103
|
+
printf(
|
|
104
|
+
"Unknown exception occurred while invoking handler for event: %s\n",
|
|
105
|
+
eventName.c_str());
|
|
106
|
+
}
|
|
97
107
|
}
|
|
98
108
|
});
|
|
99
109
|
}
|
|
@@ -123,8 +133,26 @@ void AudioEventHandlerRegistry::invokeHandlerWithEventBody(
|
|
|
123
133
|
return;
|
|
124
134
|
}
|
|
125
135
|
|
|
126
|
-
|
|
127
|
-
|
|
136
|
+
// Depending on how the AudioBufferSourceNode is handled on the JS side,
|
|
137
|
+
// it sometimes might enter race condition where the ABSN is deleted on JS
|
|
138
|
+
// side, but it is still processed on the audio thread, leading to a crash
|
|
139
|
+
// when f.e. `positionChanged` event is triggered.
|
|
140
|
+
|
|
141
|
+
// In case of debugging this, please increment the hours spent counter
|
|
142
|
+
|
|
143
|
+
// Hours spent on this: 5
|
|
144
|
+
try {
|
|
145
|
+
auto eventObject = createEventObject(body);
|
|
146
|
+
handlerIt->second->call(*runtime_, eventObject);
|
|
147
|
+
} catch (const std::exception &e) {
|
|
148
|
+
// re-throw the exception to be handled by the caller
|
|
149
|
+
// std::exception is safe to parse by the rn bridge
|
|
150
|
+
throw;
|
|
151
|
+
} catch (...) {
|
|
152
|
+
printf(
|
|
153
|
+
"Unknown exception occurred while invoking handler for event: %s\n",
|
|
154
|
+
eventName.c_str());
|
|
155
|
+
}
|
|
128
156
|
});
|
|
129
157
|
}
|
|
130
158
|
|
|
@@ -85,9 +85,8 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getDevicePreferredSampleRate)
|
|
|
85
85
|
return [self.audioSessionManager getDevicePreferredSampleRate];
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
RCT_EXPORT_METHOD(
|
|
89
|
-
|
|
90
|
-
reject)
|
|
88
|
+
RCT_EXPORT_METHOD(setAudioSessionActivity : (BOOL)enabled resolve : (RCTPromiseResolveBlock)
|
|
89
|
+
resolve reject : (RCTPromiseRejectBlock)reject)
|
|
91
90
|
{
|
|
92
91
|
if ([self.audioSessionManager setActive:enabled]) {
|
|
93
92
|
resolve(@"true");
|
|
@@ -97,9 +96,8 @@ RCT_EXPORT_METHOD(
|
|
|
97
96
|
resolve(@"false");
|
|
98
97
|
}
|
|
99
98
|
|
|
100
|
-
RCT_EXPORT_METHOD(
|
|
101
|
-
|
|
102
|
-
options allowHaptics : (BOOL)allowHaptics)
|
|
99
|
+
RCT_EXPORT_METHOD(setAudioSessionOptions : (NSString *)category mode : (NSString *)mode options : (NSArray *)
|
|
100
|
+
options allowHaptics : (BOOL)allowHaptics)
|
|
103
101
|
{
|
|
104
102
|
[self.audioSessionManager setAudioSessionOptions:category mode:mode options:options allowHaptics:allowHaptics];
|
|
105
103
|
}
|
|
@@ -129,21 +127,20 @@ RCT_EXPORT_METHOD(observeVolumeChanges : (BOOL)enabled)
|
|
|
129
127
|
[self.notificationManager observeVolumeChanges:(BOOL)enabled];
|
|
130
128
|
}
|
|
131
129
|
|
|
132
|
-
RCT_EXPORT_METHOD(
|
|
133
|
-
|
|
134
|
-
reject)
|
|
130
|
+
RCT_EXPORT_METHOD(requestRecordingPermissions : (nonnull RCTPromiseResolveBlock)
|
|
131
|
+
resolve reject : (nonnull RCTPromiseRejectBlock)reject)
|
|
135
132
|
{
|
|
136
133
|
[self.audioSessionManager requestRecordingPermissions:resolve reject:reject];
|
|
137
134
|
}
|
|
138
135
|
|
|
139
|
-
RCT_EXPORT_METHOD(
|
|
140
|
-
|
|
136
|
+
RCT_EXPORT_METHOD(checkRecordingPermissions : (nonnull RCTPromiseResolveBlock)
|
|
137
|
+
resolve reject : (nonnull RCTPromiseRejectBlock)reject)
|
|
141
138
|
{
|
|
142
139
|
[self.audioSessionManager checkRecordingPermissions:resolve reject:reject];
|
|
143
140
|
}
|
|
144
141
|
|
|
145
|
-
RCT_EXPORT_METHOD(
|
|
146
|
-
|
|
142
|
+
RCT_EXPORT_METHOD(getDevicesInfo : (nonnull RCTPromiseResolveBlock)resolve reject : (nonnull RCTPromiseRejectBlock)
|
|
143
|
+
reject)
|
|
147
144
|
{
|
|
148
145
|
[self.audioSessionManager getDevicesInfo:resolve reject:reject];
|
|
149
146
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-audio-api",
|
|
3
|
-
"version": "0.6.4-nightly-
|
|
3
|
+
"version": "0.6.4-nightly-61e39e7-20250716",
|
|
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"
|