Skip to content
This repository was archived by the owner on Jun 27, 2022. It is now read-only.

Commit ba38b2c

Browse files
committed
Make Js callback synchronous with PortAudio callback
This greatly reduces memory operations, and negates the need for a mutex. It will eliminate the need for extra, complicated, code to implement paFramesPerBufferUnspecified.
1 parent 1afc64a commit ba38b2c

File tree

4 files changed

+48
-104
lines changed

4 files changed

+48
-104
lines changed

examples/pa_api_callback_sine.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ function callbackSine () {
8787
// log what we're doing
8888
console.log(`Play for ${numSeconds} seconds.\n`)
8989
// stop stream when timeout fires
90-
//setTimeout(() => {
91-
//JsAudio.closeStream(stream)
92-
//}, numSeconds * 1000)
90+
setTimeout(() => {
91+
JsAudio.closeStream(stream)
92+
}, numSeconds * 1000)
9393
}
9494

9595
// Run it

src/callback.cc

+39-90
Original file line numberDiff line numberDiff line change
@@ -15,40 +15,16 @@ JsPaStreamCallbackBridge::JsPaStreamCallbackBridge(Callback *callback_,
1515
, UVCallback
1616
);
1717
async->data = this;
18-
uv_mutex_init(&async_lock);
18+
uv_barrier_init(&async_barrier, 2);
1919

2020
// Save userData to persistent object
2121
SaveToPersistent(ToLocString("userData"), userData);
2222
}
2323

2424
JsPaStreamCallbackBridge::~JsPaStreamCallbackBridge() {
25-
uv_mutex_destroy(&async_lock);
25+
uv_barrier_destroy(&async_barrier);
2626
uv_close((uv_handle_t*)async, NULL);
2727

28-
//free buffer memory
29-
if(m_inputBuffer != nullptr)
30-
free(m_inputBuffer);
31-
if(m_outputBuffer != nullptr)
32-
free(m_outputBuffer);
33-
}
34-
35-
int JsPaStreamCallbackBridge::sendToCallback(const void* input, unsigned long frameCount) {
36-
uv_mutex_lock(&async_lock);
37-
m_frameCount = frameCount;
38-
39-
if(m_inputBuffer != nullptr)
40-
free(m_inputBuffer);
41-
m_inputBuffer = malloc(sizeof(float) * frameCount * 2);
42-
43-
memmove(
44-
m_inputBuffer,
45-
input,
46-
m_bytesPerFrameIn * frameCount
47-
);
48-
uv_mutex_unlock(&async_lock);
49-
50-
uv_async_send(async);
51-
return 0;
5228
}
5329

5430
void JsPaStreamCallbackBridge::dispatchJSCallback() {
@@ -58,74 +34,47 @@ void JsPaStreamCallbackBridge::dispatchJSCallback() {
5834
v8::Local<v8::ArrayBuffer> output;
5935
v8::Local<v8::Value> callbackReturn;
6036

61-
uv_mutex_lock(&async_lock);
62-
63-
frameCount = m_frameCount;
64-
65-
// Setup ArrayBuffer for input audio data
66-
input = v8::ArrayBuffer::New(
67-
v8::Isolate::GetCurrent(),
68-
m_bytesPerFrameIn * frameCount
69-
);
70-
// Copy input audio data from bridge buffer to ArrayBuffer
71-
memmove(
72-
input->GetContents().Data(),
73-
m_inputBuffer,
74-
input->ByteLength()
75-
);
7637

77-
// Setup ArrayBuffer for output audio data
78-
output = v8::ArrayBuffer::New(
79-
v8::Isolate::GetCurrent(),
80-
m_bytesPerFrameOut * frameCount
81-
);
82-
83-
// Create array of arguments and call the javascript callback
84-
LocalValue argv[] = {
85-
input,
86-
output,
87-
New<Number>(frameCount),
88-
GetFromPersistent(ToLocString("userData"))
89-
};
90-
callbackReturn = callback->Call(4, argv);
91-
92-
if(m_outputBuffer != nullptr)
93-
free(m_outputBuffer);
94-
m_outputBuffer = malloc(output->ByteLength());
95-
// Copy output audio data from bridge buffer to ArrayBuffer
96-
memmove(
97-
m_outputBuffer,
98-
output->GetContents().Data(),
99-
output->ByteLength()
100-
);
101-
102-
// Store the return result of the javascript callback
103-
// so it be sent to the PaStreamCallback function
104-
m_callbackResult = LocalizeInt(callbackReturn);
105-
106-
uv_mutex_unlock(&async_lock);
38+
frameCount = m_frameCount;
39+
40+
// Setup ArrayBuffer for input audio data
41+
input = v8::ArrayBuffer::New(
42+
v8::Isolate::GetCurrent(),
43+
const_cast<void*>(m_inputBuffer),
44+
m_bytesPerFrameIn * frameCount
45+
);
46+
47+
// Setup ArrayBuffer for output audio data
48+
output = v8::ArrayBuffer::New(
49+
v8::Isolate::GetCurrent(),
50+
m_outputBuffer,
51+
m_bytesPerFrameOut * frameCount
52+
);
53+
54+
// Create array of arguments and call the javascript callback
55+
LocalValue argv[] = {
56+
input,
57+
output,
58+
New<Number>(frameCount),
59+
GetFromPersistent(ToLocString("userData"))
60+
};
61+
m_callbackResult = LocalizeInt(callback->Call(4, argv));
10762

63+
uv_barrier_wait(&async_barrier);
10864
}
65+
66+
int JsPaStreamCallbackBridge::Execute(const void* input, void* output, unsigned long frameCount) {
67+
m_frameCount = frameCount;
68+
69+
m_inputBuffer = input;
70+
m_outputBuffer = output;
71+
72+
// Dispatch the asyncronous callback
73+
uv_async_send(async);
10974

110-
void JsPaStreamCallbackBridge::consumeAudioData(void* output, unsigned long frameCount) {
75+
// Wait for the asyncronous callback
76+
uv_barrier_wait(&async_barrier);
11177

112-
if(m_outputBuffer != nullptr) {
113-
memmove(
114-
output,
115-
m_outputBuffer,
116-
m_bytesPerFrameOut * frameCount
117-
);
118-
119-
// Free the output buffer and set it to nullptr to prevent it from sending the same output data twice
120-
free(m_outputBuffer);
121-
m_outputBuffer = nullptr;
122-
}
78+
return m_callbackResult;
12379
}
12480

125-
int JsPaStreamCallbackBridge::getCallbackResult() {
126-
int ret;
127-
uv_mutex_lock(&async_lock);
128-
ret = m_callbackResult;
129-
uv_mutex_unlock(&async_lock);
130-
return ret;
131-
}

src/callback.h

+4-7
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,8 @@ class JsPaStreamCallbackBridge : public AsyncWorker {
1515

1616
~JsPaStreamCallbackBridge();
1717

18-
int sendToCallback(const void* input, unsigned long frameCount);
19-
void dispatchJSCallback();
20-
void consumeAudioData(void* output, unsigned long frameCount);
21-
int getCallbackResult();
22-
18+
void dispatchJSCallback();
19+
int Execute(const void* input, void* output, unsigned long frameCount);
2320

2421
private:
2522
NAN_INLINE static NAUV_WORK_CB(UVCallback) {
@@ -31,11 +28,11 @@ class JsPaStreamCallbackBridge : public AsyncWorker {
3128
void Execute() {}
3229

3330
uv_async_t *async;
34-
uv_mutex_t async_lock;
31+
uv_barrier_t async_barrier;
3532
unsigned long m_frameCount;
3633
size_t m_bytesPerFrameIn;
3734
size_t m_bytesPerFrameOut;
38-
void* m_inputBuffer;
35+
const void* m_inputBuffer;
3936
void* m_outputBuffer;
4037
int m_callbackResult;
4138

src/jsaudio.cc

+2-4
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,8 @@ static int StreamCallbackDispatcher (
181181
) {
182182
JsPaStreamCallbackBridge* bridge = static_cast<JsPaStreamCallbackBridge*>(userData);
183183

184-
bridge->sendToCallback(input, frameCount);
185-
bridge->consumeAudioData(output, frameCount);
186-
187-
return bridge->getCallbackResult();
184+
// Call Js callback
185+
return bridge->Execute(input, output, frameCount);
188186
}
189187

190188
void StreamFinishedCallback (void* userData) {

0 commit comments

Comments
 (0)