Skip to content

Commit 5b96b79

Browse files
author
Maciej Makowski
committed
feat: added onPositionChanged event
1 parent 34dd7f7 commit 5b96b79

11 files changed

+92
-6
lines changed

packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioBufferQueueSourceNodeHostObject.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ class AudioBufferQueueSourceNodeHostObject
2121
JSI_EXPORT_PROPERTY_GETTER(AudioBufferQueueSourceNodeHostObject, detune),
2222
JSI_EXPORT_PROPERTY_GETTER(AudioBufferQueueSourceNodeHostObject, playbackRate));
2323

24+
addSetters(
25+
JSI_EXPORT_PROPERTY_SETTER(AudioBufferQueueSourceNodeHostObject, onPositionChanged),
26+
JSI_EXPORT_PROPERTY_SETTER(AudioBufferQueueSourceNodeHostObject, onPositionChangedInterval));
27+
2428
// start method is overridden in this class
2529
functions_->erase("start");
2630

@@ -46,6 +50,20 @@ class AudioBufferQueueSourceNodeHostObject
4650
return jsi::Object::createFromHostObject(runtime, playbackRateHostObject);
4751
}
4852

53+
JSI_PROPERTY_SETTER(onPositionChanged) {
54+
auto audioBufferQueueSourceNode =
55+
std::static_pointer_cast<AudioBufferQueueSourceNode>(node_);
56+
57+
audioBufferQueueSourceNode->setOnPositionChangedCallbackId(std::stoull(value.getString(runtime).utf8(runtime)));
58+
}
59+
60+
JSI_PROPERTY_SETTER(onPositionChangedInterval) {
61+
auto audioBufferQueueSourceNode =
62+
std::static_pointer_cast<AudioBufferQueueSourceNode>(node_);
63+
64+
audioBufferQueueSourceNode->setOnPositionChangedInterval(value.getNumber());
65+
}
66+
4967
JSI_HOST_FUNCTION(start) {
5068
auto when = args[0].getNumber();
5169
auto offset = args[1].getNumber();

packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ AudioBufferQueueSourceNode::AudioBufferQueueSourceNode(
2727
std::make_shared<signalsmith::stretch::SignalsmithStretch<float>>();
2828
stretch_->presetDefault(channelCount_, context_->getSampleRate(), true);
2929

30+
onPositionChangedInterval_ = static_cast<int>(context_->getSampleRate() / 10);
31+
3032
isInitialized_ = true;
3133
}
3234

@@ -106,6 +108,28 @@ double AudioBufferQueueSourceNode::getStopTime() const {
106108
static_cast<int>(vReadIndex_), context_->getSampleRate());
107109
}
108110

111+
void AudioBufferQueueSourceNode::setOnPositionChangedCallbackId(uint64_t callbackId) {
112+
onPositionChangedCallbackId_ = callbackId;
113+
}
114+
115+
void AudioBufferQueueSourceNode::sendOnPositionChangedEvent() {
116+
if (onPositionChangedTime_ > onPositionChangedInterval_) {
117+
std::unordered_map<std::string, EventValue> body = {
118+
{"value", getStopTime()}, {"bufferId", bufferId_}};
119+
120+
context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
121+
"positionChanged", onPositionChangedCallbackId_, body);
122+
123+
onPositionChangedTime_ = 0;
124+
}
125+
126+
onPositionChangedTime_ += RENDER_QUANTUM_SIZE;
127+
}
128+
129+
void AudioBufferQueueSourceNode::setOnPositionChangedInterval(int interval) {
130+
onPositionChangedInterval_ = static_cast<int>(context_->getSampleRate() * 1000 / static_cast<float>(interval));
131+
}
132+
109133
/**
110134
* Helper functions
111135
*/
@@ -133,6 +157,9 @@ void AudioBufferQueueSourceNode::processWithPitchCorrection(
133157
return;
134158
}
135159

160+
// Send position changed event
161+
sendOnPositionChangedEvent();
162+
136163
auto framesNeededToStretch =
137164
static_cast<int>(playbackRate * static_cast<float>(framesToProcess));
138165
auto stretchedStartOffset =

packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ class AudioBufferQueueSourceNode : public AudioScheduledSourceNode {
2727
void enqueueBuffer(const std::shared_ptr<AudioBuffer> &buffer, int bufferId, bool isLastBuffer);
2828
void disable() override;
2929

30+
void setOnPositionChangedCallbackId(uint64_t callbackId);
31+
void setOnPositionChangedInterval(int interval);
32+
void sendOnPositionChangedEvent();
33+
3034
protected:
3135
std::mutex &getBufferLock();
3236
void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
@@ -51,6 +55,11 @@ class AudioBufferQueueSourceNode : public AudioScheduledSourceNode {
5155
int bufferId_ = 0;
5256
bool isLastBuffer_ = false;
5357

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+
5463
void processWithPitchCorrection(const std::shared_ptr<AudioBus> &processingBus,
5564
int framesToProcess);
5665

packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class AudioParam;
1717
class AudioBufferSourceNode : public AudioScheduledSourceNode {
1818
public:
1919
explicit AudioBufferSourceNode(BaseAudioContext *context, bool pitchCorrection);
20-
~AudioBufferSourceNode();
20+
~AudioBufferSourceNode() override;
2121

2222
[[nodiscard]] bool getLoop() const;
2323
[[nodiscard]] double getLoopStart() const;

packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ namespace audioapi {
1010

1111
AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
1212
: AudioNode(context),
13-
playbackState_(PlaybackState::UNSCHEDULED),
1413
startTime_(-1.0),
15-
stopTime_(-1.0) {
14+
stopTime_(-1.0),
15+
playbackState_(PlaybackState::UNSCHEDULED) {
1616
numberOfInputs_ = 0;
1717
}
1818

packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class AudioScheduledSourceNode : public AudioNode {
5656

5757
void handleStopScheduled();
5858

59-
uint64_t onEndedCallbackId_ = 0;
59+
uint64_t onEndedCallbackId_ = 0;
6060
};
6161

6262
} // namespace audioapi

packages/react-native-audio-api/common/cpp/audioapi/events/AudioEventHandlerRegistry.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ class AudioEventHandlerRegistry {
4949
"volumeChange",
5050
};
5151

52-
static constexpr std::array<std::string_view, 4> AUDIO_API_EVENT_NAMES = {
52+
static constexpr std::array<std::string_view, 5> AUDIO_API_EVENT_NAMES = {
5353
"ended",
5454
"audioReady",
55+
"positionChanged",
5556
"audioError",
5657
"systemStateChanged"
5758
};

packages/react-native-audio-api/src/core/AudioBufferQueueSourceNode.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import BaseAudioContext from './BaseAudioContext';
44
import AudioBuffer from './AudioBuffer';
55
import AudioParam from './AudioParam';
66
import { InvalidStateError, RangeError } from '../errors';
7+
import { OnPositionChangedEventType } from '../events/types';
78

89
export default class AudioBufferQueueSourceNode extends AudioScheduledSourceNode {
910
readonly playbackRate: AudioParam;
@@ -48,4 +49,23 @@ export default class AudioBufferQueueSourceNode extends AudioScheduledSourceNode
4849
this.hasBeenStarted = true;
4950
(this.node as IAudioBufferQueueSourceNode).start(when, offset);
5051
}
52+
53+
// eslint-disable-next-line accessor-pairs
54+
public set onPositionChanged(
55+
callback: (event: OnPositionChangedEventType) => void
56+
) {
57+
const subscription = this.audioEventEmitter.addAudioEventListener(
58+
'positionChanged',
59+
callback
60+
);
61+
62+
(this.node as IAudioBufferQueueSourceNode).onPositionChanged =
63+
subscription.subscriptionId;
64+
}
65+
66+
// eslint-disable-next-line accessor-pairs
67+
public set onPositionChangedInterval(value: number) {
68+
(this.node as IAudioBufferQueueSourceNode).onPositionChangedInterval =
69+
value;
70+
}
5171
}

packages/react-native-audio-api/src/core/AudioScheduledSourceNode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { AudioEventEmitter } from '../events';
66

77
export default class AudioScheduledSourceNode extends AudioNode {
88
protected hasBeenStarted: boolean = false;
9-
private readonly audioEventEmitter = new AudioEventEmitter(
9+
protected readonly audioEventEmitter = new AudioEventEmitter(
1010
global.AudioEventEmitter
1111
);
1212

packages/react-native-audio-api/src/events/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ export interface OnEndedEventType {
1212
bufferId: number | undefined;
1313
}
1414

15+
export interface OnPositionChangedEventType {
16+
value: number;
17+
bufferId: number;
18+
}
19+
1520
interface OnInterruptionEventType {
1621
type: 'ended' | 'began';
1722
shouldResume: boolean;
@@ -48,6 +53,7 @@ export interface OnAudioReadyEventType {
4853
interface AudioAPIEvents {
4954
ended: OnEndedEventType;
5055
audioReady: OnAudioReadyEventType;
56+
positionChanged: OnPositionChangedEventType;
5157
audioError: EventEmptyType; // to change
5258
systemStateChanged: EventEmptyType; // to change
5359
}

packages/react-native-audio-api/src/interfaces.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ export interface IAudioBufferQueueSourceNode extends IAudioScheduledSourceNode {
120120
isLastBuffer: boolean
121121
) => void;
122122
start: (when?: number, offset?: number) => void;
123+
124+
// passing subscriptionId(uint_64 in cpp, string in js) to the cpp
125+
onPositionChanged: string;
126+
// set how often the onPositionChanged event is called
127+
onPositionChangedInterval: number;
123128
}
124129

125130
export interface IAudioBuffer {

0 commit comments

Comments
 (0)