Skip to content

Commit 47d8f71

Browse files
authored
Add libpa_shim to libportaudio (#339)
* Update `libportaudio` with `libpa_shim` * Remove duplicate `PortAudio` recipe * Install to `${prefix}/lib` alongside `libportaudio` * Don't ship debug info with `libpa_ringbuffer` Also enable optimizations * Add RingBuffer symbols to export list, for windows * Fix compiler warning
1 parent fd4436e commit 47d8f71

File tree

4 files changed

+133
-39
lines changed

4 files changed

+133
-39
lines changed

L/libportaudio/build_tarballs.jl

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@ version = v"19.6.0"
99
# are used for all platforms.
1010
sources = [
1111
"http://portaudio.com/archives/pa_stable_v190600_20161030.tgz" =>
12-
"f5a21d7dcd6ee84397446fa1fa1a0675bb2e8a4a6dceb4305a8404698d8d1513",
12+
"f5a21d7dcd6ee84397446fa1fa1a0675bb2e8a4a6dceb4305a8404698d8d1513",
13+
14+
# This includes the sources for libpa_shim
15+
"./bundled",
1316

1417
# uncomment the following lines to include ASIO support. To distribute the
1518
# resulting binaries you'll need to sign the licence agreement included with
1619
# the SDK at: https://www.steinberg.net/en/company/developers.html
1720

1821
# "http://www.steinberg.net/sdk_downloads/ASIOSDK2.3.1.zip" =>
1922
# "31074764475059448a9b7a56f103f4723ed60465e0e9d1a9446ca03dcf840f04"
20-
]
23+
]
2124

2225
# Bash recipe for building across all platforms
2326
script = raw"""
@@ -28,6 +31,17 @@ if [ -d "asiosdk2.3.1" ]; then
2831
mv "asiosdk2.3.1 svnrev312937/ASIOSDK2.3.1" asiosdk2.3.1
2932
fi
3033
34+
# Add the ringbuffer symbols needed by `pa_shim.c` to the windows export lists:
35+
IDX=80
36+
for SYM in PaUtil_GetRingBufferWriteAvailable \
37+
PaUtil_GetRingBufferReadAvailable \
38+
PaUtil_WriteRingBuffer \
39+
PaUtil_ReadRingBuffer; do
40+
echo "${SYM} @${IDX}" >> ${WORKSPACE}/srcdir/portaudio/cmake_support/template_portaudio.def
41+
IDX=$((IDX+1))
42+
done
43+
44+
# First, build libportaudio
3145
mkdir build
3246
cd build
3347
cmake -DCMAKE_INSTALL_PREFIX=$prefix \
@@ -37,17 +51,27 @@ cmake -DCMAKE_INSTALL_PREFIX=$prefix \
3751
make
3852
make install
3953
install_license "${WORKSPACE}/srcdir/portaudio/LICENSE.txt"
54+
55+
# Next, build libpa_shim. Note that we explicitly install to `${prefix}/lib` since that's
56+
# what `portaudio` does, and we need to be together to get auto-moved.
57+
cd ${WORKSPACE}/srcdir
58+
SOURCEHASH=$(sha256sum pa_shim.c | awk '{print $1}')
59+
${CC} -O2 -fPIC '-DSOURCEHASH="${SOURCEHASH}"' -I${WORKSPACE}/srcdir/portaudio/include -I${WORKSPACE}/srcdir/portaudio/src/common pa_shim.c -lportaudio -o ${prefix}/lib/libpa_shim.${dlext} -shared
4060
"""
4161

4262
# These are the platforms we will build for by default, unless further
4363
# platforms are passed in on the command line
4464
platforms = supported_platforms()
4565

4666
# The products that we will ensure are always built
47-
products = [ LibraryProduct("libportaudio", :libportaudio) ]
67+
products = [
68+
LibraryProduct("libportaudio", :libportaudio),
69+
LibraryProduct("libpa_shim", :libpa_shim),
70+
]
4871

4972
# Dependencies that must be installed before this package can be built
50-
dependencies = []
73+
dependencies = [
74+
]
5175

5276
# Build the tarballs, and possibly a `build.jl` as well.
5377
build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies)

L/libportaudio/bundled/pa_shim.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include "portaudio.h"
2+
#include <pa_ringbuffer.h>
3+
#include <stdio.h>
4+
#include <unistd.h>
5+
#include <string.h>
6+
7+
#define MIN(x, y) ((x) < (y) ? (x) : (y))
8+
9+
typedef enum {
10+
PA_SHIM_ERRMSG_OVERFLOW, // input overflow
11+
PA_SHIM_ERRMSG_UNDERFLOW, // output underflow
12+
PA_SHIM_ERRMSG_ERR_OVERFLOW, // error buffer overflowed
13+
} pa_shim_errmsg_t;
14+
15+
// this callback type is used to notify the Julia side that the portaudio
16+
// callback has run
17+
typedef void (*pa_shim_notifycb_t)(void *userdata);
18+
19+
// This struct is shared between the Julia side and C
20+
typedef struct {
21+
PaUtilRingBuffer *inputbuf; // ringbuffer for input
22+
PaUtilRingBuffer *outputbuf; // ringbuffer for output
23+
PaUtilRingBuffer *errorbuf; // ringbuffer to send error notifications
24+
int sync; // keep input/output ring buffers synchronized (0/1)
25+
pa_shim_notifycb_t notifycb; // Julia callback to notify conditions
26+
void *inputhandle; // condition to notify on new input
27+
void *outputhandle; // condition to notify when ready for output
28+
void *errorhandle; // condition to notify on new error
29+
} pa_shim_info_t;
30+
31+
void senderr(pa_shim_info_t *info, pa_shim_errmsg_t msg) {
32+
if(PaUtil_GetRingBufferWriteAvailable(info->errorbuf) < 2) {
33+
// we've overflowed our error buffer! notify the host.
34+
msg = PA_SHIM_ERRMSG_ERR_OVERFLOW;
35+
}
36+
PaUtil_WriteRingBuffer(info->errorbuf, &msg, 1);
37+
if(info->notifycb) {
38+
info->notifycb(info->errorhandle);
39+
}
40+
}
41+
42+
// return the sha256 hash of the shim source so we can make sure things are in sync
43+
const char *pa_shim_getsourcehash(void)
44+
{
45+
// defined on the command-line at build-time
46+
return SOURCEHASH;
47+
}
48+
49+
/*
50+
* This routine will be called by the PortAudio engine when audio is needed.
51+
* It may called at interrupt level on some machines so don't do anything that
52+
* could mess up the system like calling malloc() or free().
53+
*/
54+
int pa_shim_processcb(const void *input, void *output,
55+
unsigned long frameCount,
56+
const PaStreamCallbackTimeInfo* timeInfo,
57+
PaStreamCallbackFlags statusFlags,
58+
void *userData)
59+
{
60+
pa_shim_info_t *info = (pa_shim_info_t *)userData;
61+
if(info->notifycb == NULL) {
62+
fprintf(stderr, "pa_shim ERROR: notifycb is NULL\n");
63+
}
64+
int nwrite;
65+
if(info->inputbuf) {
66+
nwrite = PaUtil_GetRingBufferWriteAvailable(info->inputbuf);
67+
nwrite = MIN(frameCount, nwrite);
68+
}
69+
int nread;
70+
if(info->outputbuf) {
71+
nread = PaUtil_GetRingBufferReadAvailable(info->outputbuf);
72+
nread = MIN(frameCount, nread);
73+
}
74+
if(info->inputbuf && info->outputbuf && info->sync) {
75+
// to keep the buffers synchronized, set readable and writable to
76+
// their minimum value
77+
nread = MIN(nread, nwrite);
78+
nwrite = nread;
79+
}
80+
// read/write from the ringbuffers
81+
if(info->inputbuf) {
82+
PaUtil_WriteRingBuffer(info->inputbuf, input, nwrite);
83+
if(info->notifycb) {
84+
info->notifycb(info->inputhandle);
85+
}
86+
if(nwrite < frameCount) {
87+
senderr(info, PA_SHIM_ERRMSG_OVERFLOW);
88+
}
89+
}
90+
if(info->outputbuf) {
91+
PaUtil_ReadRingBuffer(info->outputbuf, output, nread);
92+
if(info->notifycb) {
93+
info->notifycb(info->outputhandle);
94+
}
95+
if(nread < frameCount) {
96+
senderr(info, PA_SHIM_ERRMSG_UNDERFLOW);
97+
// we didn't fill the whole output buffer, so zero it out
98+
memset(output+nread*info->outputbuf->elementSizeBytes, 0,
99+
(frameCount - nread)*info->outputbuf->elementSizeBytes);
100+
}
101+
}
102+
103+
return paContinue;
104+
}

L/libportaudio_ringbuffer/build_tarballs.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ sources = [
1616
script = raw"""
1717
cd $WORKSPACE/srcdir/portaudio*
1818
mkdir -p ${libdir} ${prefix}/include
19-
${CC} -g -fPIC src/common/pa_ringbuffer.c -o ${libdir}/libpa_ringbuffer.${dlext} -shared
19+
${CC} -O2 -fPIC src/common/pa_ringbuffer.c -o ${libdir}/libpa_ringbuffer.${dlext} -shared
2020
install -m644 src/common/pa_ringbuffer.h ${prefix}/include/
2121
"""
2222

P/PortAudio/build_tarballs.jl

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)