diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..699672521 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,316 @@ +name: build + +on: + push: + branches: + - '*' + pull_request: + branches: + - '*' +env: + DEBIAN_FRONTEND: noninteractive + HOMEBREW_NO_AUTO_UPDATE: 1 + PAWPAW_VERSION: 8c69660ab10b75cd7a488f41386dbcb4c8802c5a + +jobs: + # macOS native intel build + macos: + runs-on: macos-10.15 + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Set up cache + uses: actions/cache@v2 + with: + path: | + ~/PawPawBuilds/builds + ~/PawPawBuilds/downloads + ~/PawPawBuilds/targets + key: macos + - name: Set up dependencies + run: | + brew install cmake jq meson + - name: Bootstrap macOS intel + shell: bash + run: | + if [ ! -d PawPaw ]; then + git clone https://github.com/DISTRHO/PawPaw.git + git -C PawPaw checkout ${PAWPAW_VERSION} + fi + ./PawPaw/bootstrap-jack2.sh macos && ./PawPaw/.cleanup.sh macos + - name: Build jack2 + shell: bash + run: | + pushd PawPaw && source local.env macos && popd + python ./waf configure --platform=darwin --prefix=/usr/local + python ./waf build -j $(sysctl -n hw.logicalcpu) + python ./waf install --destdir=$(pwd)/destdir + - name: Set sha8 + id: slug + run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + - name: Generate macOS package + shell: bash + run: | + ./macosx/generate-pkg.sh $(pwd)/destdir/usr/local ${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + - uses: actions/upload-artifact@v2 + with: + name: jack2-macOS-intel-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + path: macosx/jack2-osx-*.pkg + + # macOS native universal build + macos_universal: + runs-on: macos-10.15 + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Set up cache + uses: actions/cache@v2 + with: + path: | + ~/PawPawBuilds/builds + ~/PawPawBuilds/downloads + ~/PawPawBuilds/targets + key: macos-universal + - name: Set up dependencies + run: | + brew install cmake jq meson + - name: Fix up Xcode + run: | + sudo rm -Rf /Library/Developer/CommandLineTools/SDKs/* + sudo xcode-select -s /Applications/Xcode_12.3.app + - name: Bootstrap macOS universal + shell: bash + run: | + if [ ! -d PawPaw ]; then + git clone https://github.com/DISTRHO/PawPaw.git + git -C PawPaw checkout ${PAWPAW_VERSION} + fi + ./PawPaw/bootstrap-jack2.sh macos-universal && ./PawPaw/.cleanup.sh macos-universal + - name: Build jack2 + shell: bash + run: | + pushd PawPaw && source local.env macos-universal && popd + python ./waf configure --platform=darwin --prefix=/usr/local + python ./waf build -j $(sysctl -n hw.logicalcpu) + python ./waf install --destdir=$(pwd)/destdir + - name: Set sha8 + id: slug + run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + - name: Generate macOS package + shell: bash + run: | + ./macosx/generate-pkg.sh $(pwd)/destdir/usr/local ${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + - uses: actions/upload-artifact@v2 + with: + name: jack2-macOS-universal-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + path: macosx/jack2-osx-*.pkg + + # linux with win32 cross-compilation + win32: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Set up cache + uses: actions/cache@v2 + with: + path: | + ~/PawPawBuilds/builds + ~/PawPawBuilds/debs + ~/PawPawBuilds/downloads + ~/PawPawBuilds/targets + key: win32 + - name: Restore debian packages cache + run: | + if [ -d ~/PawPawBuilds/debs ] && [ "$(ls ~/PawPawBuilds/debs | wc -l)" -ne 0 ]; then \ + sudo cp ~/PawPawBuilds/debs/*.deb /var/cache/apt/archives/; \ + fi + - name: Set up dependencies + run: | + wget -qO- https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add - + sudo dpkg --add-architecture i386 + sudo apt-add-repository -y 'deb https://dl.winehq.org/wine-builds/ubuntu/ focal main' + sudo apt-get install -y autopoint build-essential curl cmake jq llvm mingw-w64 qttools5-dev-tools winehq-stable xvfb \ + binutils-mingw-w64-i686 g++-mingw-w64-i686 + - name: Cache debian packages + run: | + mkdir -p ~/PawPawBuilds/debs && \ + sudo mv /var/cache/apt/archives/*.deb ~/PawPawBuilds/debs/ + - name: Bootstrap win32 cross-compiled + shell: bash + run: | + if [ ! -d PawPaw ]; then + git clone https://github.com/DISTRHO/PawPaw.git + git -C PawPaw checkout ${PAWPAW_VERSION} + fi + ./PawPaw/bootstrap-jack2.sh win32 && ./PawPaw/.cleanup.sh win32 + - name: Build jack2 + shell: bash + run: | + pushd PawPaw && source local.env win32 && popd + ./waf configure --platform=win32 --prefix=$(pwd)/destdir --static + ./waf build -j $(nproc) + ./waf install + - name: Generate MSVC lib files + shell: bash + run: | + pushd $(pwd)/destdir/lib + llvm-dlltool -m i386 -D libjack.dll -d libjack.def -l libjack.lib + llvm-dlltool -m i386 -D libjacknet.dll -d libjacknet.def -l libjacknet.lib + llvm-dlltool -m i386 -D libjackserver.dll -d libjackserver.def -l libjackserver.lib + popd + - name: Set sha8 + id: slug + run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + - name: Generate Windows installer + shell: bash + run: | + # Setup wine + export WINEPREFIX=$(pwd)/innosetup + wineboot -u + # Download and install innosetup + curl -L https://jrsoftware.org/download.php/is.exe?site=2 -o is.exe + xvfb-run wine is.exe /allusers /dir=C:\\InnoSeup /nocancel /norestart /verysilent + # create installer + ln -sf $(pwd)/destdir windows/inno/win32 + pushd windows/inno + echo "#define VERSION \"${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}\"" > version.iss + xvfb-run wine ${WINEPREFIX}/drive_c/InnoSeup/ISCC.exe win32-mini.iss + popd + - uses: actions/upload-artifact@v2 + with: + name: jack2-win32-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + path: windows/inno/jack2-*.exe + + # linux with win64 cross-compilation + win64: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Set up cache + uses: actions/cache@v2 + with: + path: | + ~/PawPawBuilds/builds + ~/PawPawBuilds/debs + ~/PawPawBuilds/downloads + ~/PawPawBuilds/targets + key: win64 + - name: Restore debian packages cache + run: | + if [ -d ~/PawPawBuilds/debs ] && [ "$(ls ~/PawPawBuilds/debs | wc -l)" -ne 0 ]; then \ + sudo cp ~/PawPawBuilds/debs/*.deb /var/cache/apt/archives/; \ + fi + - name: Set up dependencies + run: | + wget -qO- https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add - + sudo dpkg --add-architecture i386 + sudo apt-add-repository -y 'deb https://dl.winehq.org/wine-builds/ubuntu/ focal main' + sudo apt-get install -y autopoint build-essential curl cmake jq llvm mingw-w64 qttools5-dev-tools winehq-stable xvfb \ + binutils-mingw-w64-x86-64 g++-mingw-w64-x86-64 + - name: Cache debian packages + run: | + mkdir -p ~/PawPawBuilds/debs && \ + sudo mv /var/cache/apt/archives/*.deb ~/PawPawBuilds/debs/ + - name: Bootstrap win64 cross-compiled + shell: bash + run: | + if [ ! -d PawPaw ]; then + git clone https://github.com/DISTRHO/PawPaw.git + git -C PawPaw checkout ${PAWPAW_VERSION} + fi + ./PawPaw/bootstrap-jack2.sh win64 && ./PawPaw/.cleanup.sh win64 + - name: Build jack2 + shell: bash + run: | + pushd PawPaw && source local.env win64 && popd + export PATH+=":/usr/i686-w64-mingw32/bin" + export LDFLAGS+="-L~/PawPawBuilds/targets/win64/lib32" + ./waf configure --platform=win32 --prefix=$(pwd)/destdir --static --mixed + ./waf build -j $(nproc) + ./waf install + - name: Generate MSVC lib files + shell: bash + run: | + # 32bit + pushd $(pwd)/destdir/lib32 + llvm-dlltool -m i386 -D libjack.dll -d libjack.def -l libjack.lib + popd + # 64bit + pushd $(pwd)/destdir/lib + llvm-dlltool -m i386:x86-64 -D libjack64.dll -d libjack64.def -l libjack64.lib + llvm-dlltool -m i386:x86-64 -D libjacknet64.dll -d libjacknet64.def -l libjacknet64.lib + llvm-dlltool -m i386:x86-64 -D libjackserver64.dll -d libjackserver64.def -l libjackserver64.lib + popd + - name: Set sha8 + id: slug + run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + - name: Generate Windows installer + shell: bash + run: | + # Setup wine + export WINEPREFIX=$(pwd)/innosetup + wineboot -u + # Download and install innosetup + curl -L https://jrsoftware.org/download.php/is.exe?site=2 -o is.exe + xvfb-run wine64 is.exe /allusers /dir=C:\\InnoSeup /nocancel /norestart /verysilent + # create installer + ln -sf $(pwd)/destdir windows/inno/win64 + pushd windows/inno + echo "#define VERSION \"${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}\"" > version.iss + xvfb-run wine64 ${WINEPREFIX}/drive_c/InnoSeup/ISCC.exe win64-mini.iss + popd + - uses: actions/upload-artifact@v2 + with: + name: jack2-win64-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + path: windows/inno/jack2-*.exe + + # ubuntu-20.04 + ubuntu_20_04: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Set up cache + uses: actions/cache@v2 + with: + path: | + ~/debs + key: ubuntu-20.04 + - name: Restore debian packages cache + run: | + if [ -d ~/debs ] && [ "$(ls ~/debs | wc -l)" -ne 0 ]; then \ + sudo cp ~/debs/*.deb /var/cache/apt/archives/; \ + fi + - name: Set up dependencies + run: | + sudo add-apt-repository -y ppa:ubuntustudio-ppa/backports + sudo sed -i "s/# deb-src/deb-src/" /etc/apt/sources.list /etc/apt/sources.list.d/*.list + sudo apt-get update -qq + sudo apt-get build-dep jackd2 + sudo apt-get install devscripts + - name: Cache debian packages + run: | + mkdir -p ~/debs && \ + sudo mv /var/cache/apt/archives/*.deb ~/debs/ + - name: Set sha8 + id: slug + run: echo "::set-output name=sha8::$(echo ${{ github.sha }} | cut -c1-8)" + - name: Build jack2 packages + shell: bash + run: | + apt-get source -d jackd2 + tar xf *.debian.tar.xz + rm -rf debian/source + dch -M -b -v "$(cat wscript | awk 'sub("VERSION=","")' | tr -d "'")~$(date +"%Y%m%d")git${{ github.event.pull_request.number || steps.slug.outputs.sha8 }}" -D focal "automated build" + debuild -rfakeroot --no-lintian || true + - uses: actions/upload-artifact@v2 + with: + name: jack2-ubuntu-20.04-${{ github.event.pull_request.number || steps.slug.outputs.sha8 }} + path: ~/work/jack2/*.deb diff --git a/.gitignore b/.gitignore index 143396fe5..45bbd237b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ -build/ -man/*.1 .lock* .stamp_* .DS_Store @@ -7,15 +5,22 @@ __pycache__ *.dll *.pyc *.pkg -android/.server/ -android/.client/ codeBlocks +/android/.server/ +/android/.client/ +/build/ +/man/*.1 + +# common release files +/destdir/ # macos release files -macos/package.xml -macos/package-welcome.txt +/macos/package.xml +/macos/package-welcome.txt # windows release files -windows/inno/version.iss -windows/inno/win32 -windows/inno/win64 +/innosetup/ +/is.exe +/windows/inno/version.iss +/windows/inno/win32 +/windows/inno/win64 diff --git a/AUTHORS.rst b/AUTHORS.rst index 7266fd003..7b7185ec0 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -72,6 +72,7 @@ Nedko Arnaudov Olaf Hering Olivier Humbert Paul Davis +Peter Bridgman Peter L Jones Pieter Palmers Ricardo Crudo diff --git a/ChangeLog.rst b/ChangeLog.rst index df7d68316..cb67a8538 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -1,9 +1,13 @@ ChangeLog ######### +* 1.9.20 (2021-10-15) + + * WIP + * Fix incomplete ASIO support on Windows + * 1.9.19 (2021-07-15) - * WIP (note to write asking CI help) * Add jack_position_t::tick_double, and flags around it * Add zalsa "-w" argument to wait for soundcard to be available * Bump internal protocol version to 9 (due to struct alignment) diff --git a/android/JackOpenSLESDriver.cpp b/android/JackOpenSLESDriver.cpp index f4e8608a5..8f863a46e 100644 --- a/android/JackOpenSLESDriver.cpp +++ b/android/JackOpenSLESDriver.cpp @@ -30,7 +30,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include #include -#include #include "opensl_io.h" #define JACK_OPENSLES_DEFAULT_SAMPLERATE 48000 diff --git a/android/opensl_io.c b/android/opensl_io.c index 38b6ec0ce..4a2c7ad83 100644 --- a/android/opensl_io.c +++ b/android/opensl_io.c @@ -28,6 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opensl_io.h" +#include +#include //#define CONV16BIT 32768 //#define CONVMYFLT (1./32768.) #define CONV16BIT 32640 @@ -116,12 +118,12 @@ static SLresult openSLPlayOpen(OPENSL_STREAM *p) const SLInterfaceID ids[] = {SL_IID_VOLUME}; const SLboolean req[] = {SL_BOOLEAN_FALSE}; result = (*p->engineEngine)->CreateOutputMix(p->engineEngine, &(p->outputMixObject), 1, ids, req); - if(result != SL_RESULT_SUCCESS) goto end_openaudio; + if(result != SL_RESULT_SUCCESS) return result; // realize the output mix result = (*p->outputMixObject)->Realize(p->outputMixObject, SL_BOOLEAN_FALSE); - int speakers; + SLuint32 speakers; if(channels > 1) speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; else speakers = SL_SPEAKER_FRONT_CENTER; @@ -225,7 +227,7 @@ static SLresult openSLRecOpen(OPENSL_STREAM *p){ SLDataSource audioSrc = {&loc_dev, NULL}; // configure audio sink - int speakers; + SLuint32 speakers; if(channels > 1) speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; else speakers = SL_SPEAKER_FRONT_CENTER; @@ -316,7 +318,11 @@ OPENSL_STREAM *android_OpenAudioDevice(int sr, int inchannels, int outchannels, p->outchannels = outchannels; p->sr = sr; p->inlock = createThreadLock(); + if (p->inlock == NULL) + return NULL; p->outlock = createThreadLock(); + if (p->outlock == NULL) + return NULL; if((p->outBufSamples = bufferframes*outchannels) != 0) { if((p->outputBuffer[0] = (short *) calloc(p->outBufSamples, sizeof(short))) == NULL || @@ -336,6 +342,10 @@ OPENSL_STREAM *android_OpenAudioDevice(int sr, int inchannels, int outchannels, p->currentInputIndex = 0; p->currentOutputBuffer = 0; + p->outputBufferSize[0] = 0; + p->outputBufferSize[1] = 0; + p->inputBufferSize[0] = 0; + p->inputBufferSize[1] = 0; p->currentInputIndex = p->inBufSamples; p->currentInputBuffer = 0; @@ -358,6 +368,17 @@ OPENSL_STREAM *android_OpenAudioDevice(int sr, int inchannels, int outchannels, notifyThreadLock(p->inlock); p->time = 0.; + + if (p->bqPlayerBufferQueue) + (*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, + p->outputBuffer[0], p->outBufSamples*sizeof(short)); + + if (p->recorderBufferQueue) + (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, + p->inputBuffer[0], p->inBufSamples*sizeof(short)); + + + return p; } @@ -414,39 +435,66 @@ double android_GetTimestamp(OPENSL_STREAM *p){ void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { OPENSL_STREAM *p = (OPENSL_STREAM *) context; + + while ((p->inputBufferSize[0] > 0) && (p->inputBufferSize[1] > 0)) + usleep(1000); + + p->currentInputBuffer = (p->currentInputBuffer ? 0 : 1); + int queueInputBuffer = (p->currentInputBuffer ? 0 : 1); + int size = p->inBufSamples; + short *inBuffer = p->inputBuffer[queueInputBuffer]; + + (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, + inBuffer, size * sizeof(short)); + + p->inputBufferSize[queueInputBuffer] = size; notifyThreadLock(p->inlock); } // gets a buffer of size samples from the device int android_AudioIn(OPENSL_STREAM *p,float *buffer,int size){ + short *inBuffer; int i, bufsamps, index; if(p == NULL) return 0; bufsamps = p->inBufSamples; + if(bufsamps == 0) return 0; - index = p->currentInputIndex; + if (size > bufsamps) return 0; + if (p->inputBufferSize[p->currentInputBuffer] == 0) + waitThreadLock(p->inlock); + + index = 0; inBuffer = p->inputBuffer[p->currentInputBuffer]; + for(i=0; i < size; i++){ - if (index >= bufsamps) { - waitThreadLock(p->inlock); - (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, - inBuffer,bufsamps*sizeof(short)); - p->currentInputBuffer = (p->currentInputBuffer ? 0 : 1); - index = 0; - inBuffer = p->inputBuffer[p->currentInputBuffer]; - } buffer[i] = (float) inBuffer[index++]*CONVMYFLT; } - p->currentInputIndex = index; + + p->inputBufferSize[p->currentInputBuffer] = 0; if(p->outchannels == 0) p->time += (double) size/(p->sr*p->inchannels); - return i; + + return size; } // this callback handler is called every time a buffer finishes playing void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { OPENSL_STREAM *p = (OPENSL_STREAM *) context; + + while ((p->outputBufferSize[0] == 0) && (p->outputBufferSize[1] == 0)) + usleep(1000); + + p->currentOutputBuffer = (p->currentOutputBuffer ? 0 : 1); + int queueOutputBuffer = (p->currentOutputBuffer ? 0 : 1); + int size = p->outputBufferSize[queueOutputBuffer]; + short *outBuffer = p->outputBuffer[queueOutputBuffer]; + + (*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, + outBuffer, size * sizeof(short)); + + p->outputBufferSize[queueOutputBuffer] = 0; notifyThreadLock(p->outlock); } @@ -457,24 +505,26 @@ int android_AudioOut(OPENSL_STREAM *p, float *buffer,int size){ int i, bufsamps, index; if(p == NULL) return 0; bufsamps = p->outBufSamples; + if(bufsamps == 0) return 0; - index = p->currentOutputIndex; + if (size > bufsamps) return 0; + + + if (p->outputBufferSize[p->currentOutputBuffer] != 0) + waitThreadLock(p->outlock); + + index = 0; outBuffer = p->outputBuffer[p->currentOutputBuffer]; + for(i=0; i < size; i++){ outBuffer[index++] = (short) (buffer[i]*CONV16BIT); - if (index >= p->outBufSamples) { - waitThreadLock(p->outlock); - (*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, - outBuffer,bufsamps*sizeof(short)); - p->currentOutputBuffer = (p->currentOutputBuffer ? 0 : 1); - index = 0; - outBuffer = p->outputBuffer[p->currentOutputBuffer]; - } } - p->currentOutputIndex = index; + + p->outputBufferSize[p->currentOutputBuffer] = size; + p->time += (double) size/(p->sr*p->outchannels); - return i; + return size; } //---------------------------------------------------------------------- @@ -507,12 +557,12 @@ int waitThreadLock(void *lock) int retval = 0; p = (threadLock*) lock; pthread_mutex_lock(&(p->m)); + p->s = (unsigned char) 0; while (!p->s) { pthread_cond_wait(&(p->c), &(p->m)); } - p->s = (unsigned char) 0; pthread_mutex_unlock(&(p->m)); - return NULL; + return retval; } void notifyThreadLock(void *lock) diff --git a/android/opensl_io.h b/android/opensl_io.h index 501f0361c..fcb7c6a7c 100644 --- a/android/opensl_io.h +++ b/android/opensl_io.h @@ -72,10 +72,12 @@ typedef struct opensl_stream { // current buffer half (0, 1) int currentOutputBuffer; int currentInputBuffer; - + // buffers short *outputBuffer[2]; short *inputBuffer[2]; + int outputBufferSize[2]; + int inputBufferSize[2]; // size of buffers int outBufSamples; diff --git a/common/JackConstants.h b/common/JackConstants.h index 0cf62ebc6..a0b94a579 100644 --- a/common/JackConstants.h +++ b/common/JackConstants.h @@ -24,7 +24,7 @@ #include "config.h" #endif -#define VERSION "1.9.19" +#define VERSION "1.9.20" #define BUFFER_SIZE_MAX 8192 diff --git a/common/memops.c b/common/memops.c index 6c5ad2f9b..725c49e17 100644 --- a/common/memops.c +++ b/common/memops.c @@ -137,6 +137,15 @@ (d) = f_round ((s) * SAMPLE_24BIT_SCALING) << 8;\ } +#define float_24l32(s, d) \ + if ((s) <= NORMALIZED_FLOAT_MIN) {\ + (d) = SAMPLE_24BIT_MIN; \ + } else if ((s) >= NORMALIZED_FLOAT_MAX) {\ + (d) = SAMPLE_24BIT_MAX; \ + } else {\ + (d) = f_round ((s) * SAMPLE_24BIT_SCALING); \ + } + /* call this when "s" has already been scaled (e.g. when dithering) */ @@ -267,6 +276,8 @@ void sample_move_dS_floatLE (char *dst, jack_default_audio_sample_t *src, unsign Ss - like S but reverse endian from the host CPU 32u24 - sample is an signed 32 bit integer value, but data is in upper 24 bits only 32u24s - like 32u24 but reverse endian from the host CPU + 32l24 - sample is an signed 32 bit integer value, but data is in lower 24 bits only + 32l24s - like 32l24 but reverse endian from the host CPU 24 - sample is an signed 24 bit integer value 24s - like 24 but reverse endian from the host CPU 16 - sample is an signed 16 bit integer value @@ -546,6 +557,273 @@ void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigne } } +void sample_move_d32l24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) +{ +#if defined (__ARM_NEON__) || defined (__ARM_NEON) + unsigned long unrolled = nsamples / 4; + nsamples = nsamples & 3; + + while (unrolled--) { + float32x4_t samples = vld1q_f32(src); + int32x4_t converted = float_24_neon(samples); + converted = vreinterpretq_s32_u8(vrev32q_u8(vreinterpretq_u8_s32(converted))); + + switch(dst_skip) { + case 4: + vst1q_s32((int32_t*)dst, converted); + break; + default: + vst1q_lane_s32((int32_t*)(dst), converted, 0); + vst1q_lane_s32((int32_t*)(dst+dst_skip), converted, 1); + vst1q_lane_s32((int32_t*)(dst+2*dst_skip), converted, 2); + vst1q_lane_s32((int32_t*)(dst+3*dst_skip), converted, 3); + break; + } + dst += 4*dst_skip; + src+= 4; + } +#endif + + int32_t z; + + while (nsamples--) { + + float_24l32 (*src, z); + +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(z>>24); + dst[1]=(char)(z>>16); + dst[2]=(char)(z>>8); + dst[3]=(char)(z); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(z); + dst[1]=(char)(z>>8); + dst[2]=(char)(z>>16); + dst[3]=(char)(z>>24); +#endif + dst += dst_skip; + src++; + } +} + +void sample_move_d32l24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) +{ +#if defined (__SSE2__) && !defined (__sun__) + __m128 int_max = _mm_set1_ps(SAMPLE_24BIT_MAX_F); + __m128 int_min = _mm_sub_ps(_mm_setzero_ps(), int_max); + __m128 factor = int_max; + + unsigned long unrolled = nsamples / 4; + nsamples = nsamples & 3; + + while (unrolled--) { + __m128 in = _mm_load_ps(src); + __m128 scaled = _mm_mul_ps(in, factor); + __m128 clipped = clip(scaled, int_min, int_max); + + __m128i shifted = _mm_cvttps_epi32(clipped); + +#ifdef __SSE4_1__ + *(int32_t*)dst = _mm_extract_epi32(shifted, 0); + *(int32_t*)(dst+dst_skip) = _mm_extract_epi32(shifted, 1); + *(int32_t*)(dst+2*dst_skip) = _mm_extract_epi32(shifted, 2); + *(int32_t*)(dst+3*dst_skip) = _mm_extract_epi32(shifted, 3); +#else + __m128i shuffled1 = _mm_shuffle_epi32(shifted, _MM_SHUFFLE(0, 3, 2, 1)); + __m128i shuffled2 = _mm_shuffle_epi32(shifted, _MM_SHUFFLE(1, 0, 3, 2)); + __m128i shuffled3 = _mm_shuffle_epi32(shifted, _MM_SHUFFLE(2, 1, 0, 3)); + + _mm_store_ss((float*)dst, (__m128)shifted); + + _mm_store_ss((float*)(dst+dst_skip), (__m128)shuffled1); + _mm_store_ss((float*)(dst+2*dst_skip), (__m128)shuffled2); + _mm_store_ss((float*)(dst+3*dst_skip), (__m128)shuffled3); +#endif + dst += 4*dst_skip; + + src+= 4; + } + + while (nsamples--) { + __m128 in = _mm_load_ss(src); + __m128 scaled = _mm_mul_ss(in, factor); + __m128 clipped = _mm_min_ss(int_max, _mm_max_ss(scaled, int_min)); + + int y = _mm_cvttss_si32(clipped); + *((int *) dst) = y<<8; + + dst += dst_skip; + src++; + } +#elif defined (__ARM_NEON__) || defined (__ARM_NEON) + unsigned long unrolled = nsamples / 4; + nsamples = nsamples & 3; + + while (unrolled--) { + float32x4_t samples = vld1q_f32(src); + int32x4_t converted = float_24_neon(samples); + + switch(dst_skip) { + case 4: + vst1q_s32((int32_t*)dst, converted); + break; + default: + vst1q_lane_s32((int32_t*)(dst), converted, 0); + vst1q_lane_s32((int32_t*)(dst+dst_skip), converted, 1); + vst1q_lane_s32((int32_t*)(dst+2*dst_skip), converted, 2); + vst1q_lane_s32((int32_t*)(dst+3*dst_skip), converted, 3); + break; + } + dst += 4*dst_skip; + + src+= 4; + } +#endif + +#if !defined (__SSE2__) + while (nsamples--) { + float_24l32 (*src, *((int32_t*) dst)); + dst += dst_skip; + src++; + } +#endif +} + +void sample_move_dS_s32l24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) +{ +#if defined (__ARM_NEON__) || defined (__ARM_NEON) + float32x4_t factor = vdupq_n_f32(1.0 / SAMPLE_24BIT_SCALING); + unsigned long unrolled = nsamples / 4; + while (unrolled--) { + uint32x4_t src128; + switch(src_skip) + { + case 4: + src128 = vld1q_u32((uint32_t*)src); + break; + case 8: + src128 = vld2q_u32((uint32_t*)src).val[0]; + break; + default: + src128 = vld1q_lane_u32((uint32_t*)src, src128, 0); + src128 = vld1q_lane_u32((uint32_t*)(src+src_skip), src128, 1); + src128 = vld1q_lane_u32((uint32_t*)(src+2*src_skip), src128, 2); + src128 = vld1q_lane_u32((uint32_t*)(src+3*src_skip), src128, 3); + break; + } + src128 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(src128))); + uint32x4_t toupper = vshlq_n_u32(src128, 8); + int32x4_t shifted = vshrq_n_s32((int32x4_t)toupper, 8); + float32x4_t as_float = vcvtq_f32_s32(shifted); + float32x4_t divided = vmulq_f32(as_float, factor); + vst1q_f32(dst, divided); + + src += 4*src_skip; + dst += 4; + } + nsamples = nsamples & 3; +#endif + + /* ALERT: signed sign-extension portability !!! */ + + const jack_default_audio_sample_t scaling = 1.0/SAMPLE_24BIT_SCALING; + + while (nsamples--) { + int32_t x; +#if __BYTE_ORDER == __LITTLE_ENDIAN + x = (unsigned char)(src[0]); + x <<= 8; + x |= (unsigned char)(src[1]); + x <<= 8; + x |= (unsigned char)(src[2]); + x <<= 8; + x |= (unsigned char)(src[3]); +#elif __BYTE_ORDER == __BIG_ENDIAN + x = (unsigned char)(src[3]); + x <<= 8; + x |= (unsigned char)(src[2]); + x <<= 8; + x |= (unsigned char)(src[1]); + x <<= 8; + x |= (unsigned char)(src[0]); +#endif + *dst = (x >> 0) * scaling; + dst++; + src += src_skip; + } +} + +void sample_move_dS_s32l24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) +{ +#if defined (__SSE2__) && !defined (__sun__) + unsigned long unrolled = nsamples / 4; + static float inv_sample_max_24bit = 1.0 / SAMPLE_24BIT_SCALING; + __m128 factor = _mm_set1_ps(inv_sample_max_24bit); + while (unrolled--) + { + int i1 = *((int *) src); + src+= src_skip; + int i2 = *((int *) src); + src+= src_skip; + int i3 = *((int *) src); + src+= src_skip; + int i4 = *((int *) src); + src+= src_skip; + + __m128i shifted = _mm_set_epi32(i4, i3, i2, i1); + + __m128 as_float = _mm_cvtepi32_ps(shifted); + __m128 divided = _mm_mul_ps(as_float, factor); + + _mm_storeu_ps(dst, divided); + + dst += 4; + } + nsamples = nsamples & 3; +#elif defined (__ARM_NEON__) || defined (__ARM_NEON) + unsigned long unrolled = nsamples / 4; + float32x4_t factor = vdupq_n_f32(1.0 / SAMPLE_24BIT_SCALING); + while (unrolled--) { + uint32x4_t src128; + switch(src_skip) { + case 4: + src128 = vld1q_u32((uint32_t*)src); + break; + case 8: + src128 = vld2q_u32((uint32_t*)src).val[0]; + break; + default: + src128 = vld1q_lane_u32((uint32_t*)src, src128, 0); + src128 = vld1q_lane_u32((uint32_t*)(src+src_skip), src128, 1); + src128 = vld1q_lane_u32((uint32_t*)(src+2*src_skip), src128, 2); + src128 = vld1q_lane_u32((uint32_t*)(src+3*src_skip), src128, 3); + break; + } + // Sign extension by moving to upper as unsigned, then down + uint32x4_t toupper = vshlq_n_u32(src128, 8); + int32x4_t shifted = vshrq_n_s32((int32x4_t)toupper, 8); + float32x4_t as_float = vcvtq_f32_s32(shifted); + float32x4_t divided = vmulq_f32(as_float, factor); + vst1q_f32(dst, divided); + + src += 4*src_skip; + dst += 4; + } + nsamples = nsamples & 3; +#endif + + /* ALERT: signed sign-extension portability !!! */ + + const jack_default_audio_sample_t scaling = 1.0/SAMPLE_24BIT_SCALING; + while (nsamples--) { + uint32_t val=(*((uint32_t*)src)); + if (val & 0x800000u) val|=0xFF000000u; + *dst = (*((int32_t *) &val)) * scaling; + dst++; + src += src_skip; + } +} + void sample_move_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { #if defined (__ARM_NEON__) || defined (__ARM_NEON) @@ -1189,4 +1467,3 @@ memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, src_bytes -= 4; } } - diff --git a/common/memops.h b/common/memops.h index c027e4d6f..a69087ff4 100644 --- a/common/memops.h +++ b/common/memops.h @@ -55,6 +55,8 @@ void sample_move_dS_floatLE (char *dst, jack_default_audio_sample_t *src, unsign /* integer functions */ void sample_move_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_d32l24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_d32l24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); @@ -81,6 +83,8 @@ void sample_move_dither_shaped_d16_sS (char *dst, jack_default_audio_sample_ void sample_move_dS_s32u24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); +void sample_move_dS_s32l24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); +void sample_move_dS_s32l24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s16s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); diff --git a/common/wscript b/common/wscript index 114eb0a2b..24f024ec2 100644 --- a/common/wscript +++ b/common/wscript @@ -117,6 +117,7 @@ def build(bld): '../posix/JackPosixMutex.cpp', '../macosx/JackMachThread.mm', '../macosx/JackMachSemaphore.mm', + '../macosx/JackMachSemaphoreServer.mm', '../posix/JackSocket.cpp', '../macosx/JackMachTime.c', ] diff --git a/example-clients/simdtests.cpp b/example-clients/simdtests.cpp index dc50be625..40b30e90d 100644 --- a/example-clients/simdtests.cpp +++ b/example-clients/simdtests.cpp @@ -118,6 +118,26 @@ test_case_data_t test_cases[] = { origerated::sample_move_dS_s32u24, NULL, "32u24" }, + { + 4, + 3, + true, + accelerated::sample_move_d32l24_sSs, + origerated::sample_move_d32l24_sSs, + accelerated::sample_move_dS_s32l24s, + origerated::sample_move_dS_s32l24s, + NULL, + "32l24s" }, + { + 4, + 3, + false, + accelerated::sample_move_d32l24_sS, + origerated::sample_move_d32l24_sS, + accelerated::sample_move_dS_s32l24, + origerated::sample_move_dS_s32l24, + NULL, + "32l24" }, { 3, 3, @@ -283,7 +303,8 @@ int main(int argc, char *argv[]) #else test_cases[testcase].reverse); #endif - if(intval_accel != intval_orig) { + // allow a deviation of 1 + if(intval_accel>intval_orig+1 || intval_orig>intval_accel+1) { if(int_error_countwrite_via_copy = driver->quirk_bswap? - sample_move_d32u24_sSs: - sample_move_d32u24_sS; + sample_move_d32l24_sSs: + sample_move_d32l24_sS; break; default: @@ -344,8 +344,8 @@ alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) break; case 4: driver->read_via_copy = driver->quirk_bswap? - sample_move_dS_s32u24s: - sample_move_dS_s32u24; + sample_move_dS_s32l24s: + sample_move_dS_s32l24; break; } } diff --git a/macosx/JackMachSemaphore.h b/macosx/JackMachSemaphore.h index 10406847a..20465a096 100644 --- a/macosx/JackMachSemaphore.h +++ b/macosx/JackMachSemaphore.h @@ -22,6 +22,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "JackCompilerDeps.h" #include "JackSynchro.h" + +#include "JackMachThread.h" +#include "JackMachSemaphoreServer.h" + #include #include #include @@ -38,13 +42,24 @@ class SERVER_EXPORT JackMachSemaphore : public detail::JackSynchro private: + /*! \brief A mach send right to the mach semaphore, or MACH_PORT_NULL if not yet Allocate()d + * (server) or Connect()ed (client). */ semaphore_t fSemaphore; + + /*! \brief The bootstrap port for this task, or MACH_PORT_NULL if not yet obtained. */ mach_port_t fBootPort; - int fSharedMem; - char* fSharedName; + /*! \brief The IPC port used to pass the semaphore port from the server to the client, and + * for the client to request that this occurs. MACH_PORT_NULL if not yet created (server) or + * looked up (client). */ + mach_port_t fServicePort; + + /*! \brief On the server, if allocated, a runnable semaphore server which listens for IPC + * messages and replies with a send right for a semaphore port. */ + JackMachSemaphoreServer* fSemServer; - bool recursiveBootstrapRegister(int counter); + /*! \brief On the server, if allocated, a thread that runs \ref fSemServer. */ + JackMachThread* fThreadSemServer; protected: @@ -52,7 +67,13 @@ class SERVER_EXPORT JackMachSemaphore : public detail::JackSynchro public: - JackMachSemaphore():JackSynchro(), fSemaphore(0), fBootPort(0), fSharedMem(0), fSharedName(NULL) + JackMachSemaphore(): + JackSynchro(), + fSemaphore(MACH_PORT_NULL), + fBootPort(MACH_PORT_NULL), + fServicePort(MACH_PORT_NULL), + fSemServer(NULL), + fThreadSemServer(NULL) {} bool Signal(); diff --git a/macosx/JackMachSemaphore.mm b/macosx/JackMachSemaphore.mm index 7b7f4e2e2..1905e04cb 100644 --- a/macosx/JackMachSemaphore.mm +++ b/macosx/JackMachSemaphore.mm @@ -18,12 +18,18 @@ */ #include "JackMachSemaphore.h" +#include "JackMachUtils.h" #include "JackConstants.h" #include "JackTools.h" #include "JackError.h" -#include -#include -#include + +#include + +#define jack_mach_error(kern_result, message) \ + jack_mach_error_uncurried("JackMachSemaphore", kern_result, message) + +#define jack_mach_bootstrap_err(kern_result, message, name) \ + jack_mach_bootstrap_err_uncurried("JackMachSemaphore", kern_result, message, name) namespace Jack { @@ -42,7 +48,7 @@ bool JackMachSemaphore::Signal() { - if (!fSemaphore) { + if (fSemaphore == MACH_PORT_NULL) { jack_error("JackMachSemaphore::Signal name = %s already deallocated!!", fName); return false; } @@ -60,7 +66,7 @@ bool JackMachSemaphore::SignalAll() { - if (!fSemaphore) { + if (fSemaphore == MACH_PORT_NULL) { jack_error("JackMachSemaphore::SignalAll name = %s already deallocated!!", fName); return false; } @@ -79,7 +85,7 @@ bool JackMachSemaphore::Wait() { - if (!fSemaphore) { + if (fSemaphore == MACH_PORT_NULL) { jack_error("JackMachSemaphore::Wait name = %s already deallocated!!", fName); return false; } @@ -93,7 +99,7 @@ bool JackMachSemaphore::TimedWait(long usec) { - if (!fSemaphore) { + if (fSemaphore == MACH_PORT_NULL) { jack_error("JackMachSemaphore::TimedWait name = %s already deallocated!!", fName); return false; } @@ -109,132 +115,199 @@ return (res == KERN_SUCCESS); } -bool JackMachSemaphore::recursiveBootstrapRegister(int counter) +/*! \brief Server side: create semaphore and publish IPC primitives to make it accessible. + * + * This method; + * - Allocates a mach semaphore + * - Allocates a new mach IPC port and obtains a send right for it + * - Publishes IPC port send right to the bootstrap server + * - Starts a new JackMachSemaphoreServer thread, which listens for messages on the IPC port and + * replies with a send right to the mach semaphore. + * + * \returns false if any of the above steps fails, or true otherwise. + */ +bool JackMachSemaphore::Allocate(const char* client_name, const char* server_name, int value) { - if (counter == 99) - return false; - - kern_return_t res; - - if ((res = bootstrap_register(fBootPort, fSharedName, fSemaphore)) != KERN_SUCCESS) { - switch (res) { - case BOOTSTRAP_SUCCESS : - break; - - case BOOTSTRAP_NOT_PRIVILEGED : - case BOOTSTRAP_NAME_IN_USE : - case BOOTSTRAP_UNKNOWN_SERVICE : - case BOOTSTRAP_SERVICE_ACTIVE : - // try again with next suffix - snprintf(fSharedName, sizeof(fName), "%s-%d", fName, ++counter); - return recursiveBootstrapRegister(counter); - break; - - default : - jack_log("bootstrap_register() err = %i:%s", res, bootstrap_strerror(res)); - break; - } - - jack_error("Allocate: can't check in mach semaphore name = %s err = %i:%s", fName, res, bootstrap_strerror(res)); + if (fSemaphore != MACH_PORT_NULL) { + jack_error("JackMachSemaphore::Allocate: Semaphore already allocated; called twice? [%s]", fName); return false; } - return true; -} + BuildName(client_name, server_name, fName, sizeof(fName)); -// Server side : publish the semaphore in the global namespace -bool JackMachSemaphore::Allocate(const char* name, const char* server_name, int value) -{ - BuildName(name, server_name, fName, sizeof(fName)); mach_port_t task = mach_task_self(); kern_return_t res; - if (fBootPort == 0) { + if (fBootPort == MACH_PORT_NULL) { if ((res = task_get_bootstrap_port(task, &fBootPort)) != KERN_SUCCESS) { - jack_error("Allocate: Can't find bootstrap mach port err = %s", mach_error_string(res)); + jack_mach_error(res, "can't find bootstrap mach port"); return false; } } - if ((fSharedMem = shm_open(fName, O_CREAT | O_RDWR, 0777)) < 0) { - jack_error("Allocate: can't check in mach shared name = %s err = %s", fName, strerror(errno)); + if ((res = semaphore_create(task, &fSemaphore, SYNC_POLICY_FIFO, value)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to create semaphore"); return false; } - struct stat st; - if (fstat(fSharedMem, &st) != -1 && st.st_size == 0) { - if (ftruncate(fSharedMem, SYNC_MAX_NAME_SIZE+1) != 0) { - jack_error("Allocate: can't set shared memory size in mach shared name = %s err = %s", fName, strerror(errno)); - return false; - } + if ((res = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &fServicePort)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to allocate IPC port"); + + // Cleanup created semaphore + this->Destroy(); + + return false; } - char* const sharedName = (char*)mmap(NULL, SYNC_MAX_NAME_SIZE+1, PROT_READ|PROT_WRITE, MAP_SHARED, fSharedMem, 0); + if ((res = mach_port_insert_right(mach_task_self(), fServicePort, fServicePort, MACH_MSG_TYPE_MAKE_SEND)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to obtain send right for IPC port"); + + // Cleanup created semaphore & mach port + this->Destroy(); - if (sharedName == NULL || sharedName == MAP_FAILED) { - jack_error("Allocate: can't check in mach shared name = %s err = %s", fName, strerror(errno)); - close(fSharedMem); - fSharedMem = -1; - shm_unlink(fName); return false; } - fSharedName = sharedName; - strcpy(fSharedName, fName); + if ((res = bootstrap_register(fBootPort, fName, fServicePort)) != KERN_SUCCESS) { + jack_mach_bootstrap_err(res, "can't register IPC port with bootstrap server", fName); + + // Cleanup created semaphore & mach port + this->Destroy(); + + return false; + } + + fSemServer = new JackMachSemaphoreServer(fSemaphore, fServicePort, fName); + fThreadSemServer = new JackMachThread(fSemServer); + + if (fThreadSemServer->Start() < 0) { + jack_error("JackMachSemaphore::Allocate: failed to start semaphore IPC server thread [%s]", fName); + + // Cleanup created semaphore, mach port (incl. service registration), and server + this->Destroy(); - if ((res = semaphore_create(task, &fSemaphore, SYNC_POLICY_FIFO, value)) != KERN_SUCCESS) { - jack_error("Allocate: can create semaphore err = %i:%s", res, mach_error_string(res)); return false; } - jack_log("JackMachSemaphore::Allocate name = %s", fName); - return recursiveBootstrapRegister(1); + jack_log("JackMachSemaphore::Allocate: OK, name = %s", fName); + return true; } -// Client side : get the published semaphore from server -bool JackMachSemaphore::ConnectInput(const char* name, const char* server_name) +/*! \brief Client side: Obtain semaphore from server via published IPC port. + * + * This method; + * - Looks up the service port for the jackd semaphore server for this client by name + * - Sends a message to that server asking for a semaphore port send right + * - Receives a semaphore send right in return and stores it locally + * + * \returns False if any of the above steps fails, or true otherwise. + */ +bool JackMachSemaphore::ConnectInput(const char* client_name, const char* server_name) { - BuildName(name, server_name, fName, sizeof(fName)); + BuildName(client_name, server_name, fName, sizeof(fName)); + + mach_port_t task = mach_task_self(); kern_return_t res; - // Temporary... - if (fSharedName) { - jack_log("Already connected name = %s", name); + if (fSemaphore != MACH_PORT_NULL) { + jack_log("JackMachSemaphore::Connect: Already connected name = %s", fName); return true; } - if (fBootPort == 0) { - if ((res = task_get_bootstrap_port(mach_task_self(), &fBootPort)) != KERN_SUCCESS) { - jack_error("Connect: can't find bootstrap port err = %s", mach_error_string(res)); + if (fBootPort == MACH_PORT_NULL) { + if ((res = task_get_bootstrap_port(task, &fBootPort)) != KERN_SUCCESS) { + jack_mach_error(res, "can't find bootstrap port"); return false; } } - if ((fSharedMem = shm_open(fName, O_RDWR, 0)) < 0) { - jack_error("Connect: can't connect mach shared name = %s err = %s", fName, strerror(errno)); + if ((res = bootstrap_look_up(fBootPort, fName, &fServicePort)) != KERN_SUCCESS) { + jack_mach_bootstrap_err(res, "can't find IPC service port to request semaphore", fName); return false; } - char* const sharedName = (char*)mmap(NULL, SYNC_MAX_NAME_SIZE+1, PROT_READ|PROT_WRITE, MAP_SHARED, fSharedMem, 0); + mach_port_t semaphore_req_port; + + if ((res = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &semaphore_req_port)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to allocate request port"); + + if ((res = mach_port_deallocate(task, fServicePort)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to deallocate IPC service port during cleanup"); + } else { + fServicePort = MACH_PORT_NULL; + } - if (sharedName == NULL || sharedName == MAP_FAILED) { - jack_error("Connect: can't connect mach shared name = %s err = %s", fName, strerror(errno)); - close(fSharedMem); - fSharedMem = -1; return false; } - if ((res = bootstrap_look_up(fBootPort, sharedName, &fSemaphore)) != KERN_SUCCESS) { - jack_error("Connect: can't find mach semaphore name = %s, sname = %s, err = %s", fName, sharedName, bootstrap_strerror(res)); - close(fSharedMem); - fSharedMem = -1; + // Prepare a message buffer on the stack. We'll use it for both sending and receiving a message. + struct { + mach_msg_header_t hdr; + mach_msg_trailer_t trailer; + } msg; + + /* + * Configure the message to consume the destination port we give it (_MOVE_SEND), and to + * transmute the local port receive right we give it into a send_once right at the destination. + * The server will use that send_once right to reply to us. + */ + msg.hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); + msg.hdr.msgh_local_port = semaphore_req_port; + msg.hdr.msgh_remote_port = fServicePort; + + mach_msg_return_t send_err = mach_msg( + &msg.hdr, + MACH_SEND_MSG, + sizeof(msg.hdr), // no trailer on send + 0, + MACH_PORT_NULL, + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL); + + if (send_err != MACH_MSG_SUCCESS) { + jack_mach_error(send_err, "failed to send semaphore port request IPC"); + + if ((res = mach_port_deallocate(task, fServicePort)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to deallocate IPC service port during cleanup"); + } else { + fServicePort = MACH_PORT_NULL; + } + + if ((res = mach_port_destroy(task, semaphore_req_port)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to destroy IPC request port during cleanup"); + } + return false; + } else { + fServicePort = MACH_PORT_NULL; // We moved it into the message and away to the destination } - fSharedName = sharedName; + mach_msg_return_t recv_err = mach_msg( + &msg.hdr, + MACH_RCV_MSG, + 0, + sizeof(msg), + semaphore_req_port, + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL + ); + + /* Don't leak ports: irrespective of if we succeeded to read or not, destroy the port we created + * to send/receive the request as we have no further use for it either way. */ + if ((res = mach_port_destroy(task, semaphore_req_port)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to destroy semaphore_req_port"); + // This isn't good, but doesn't actually stop the semaphore from working... don't bail + } - jack_log("JackMachSemaphore::Connect name = %s ", fName); - return true; + if (recv_err != MACH_MSG_SUCCESS) { + jack_mach_error(recv_err, "failed to receive semaphore port"); + return false; + } else { + fSemaphore = msg.hdr.msgh_remote_port; + + jack_log("JackMachSemaphore::Connect: OK, name = %s ", fName); + return true; + } } bool JackMachSemaphore::Connect(const char* name, const char* server_name) @@ -249,49 +322,75 @@ bool JackMachSemaphore::Disconnect() { - if (fSemaphore > 0) { - jack_log("JackMachSemaphore::Disconnect name = %s", fName); - fSemaphore = 0; - } - - if (!fSharedName) { + if (fSemaphore == MACH_PORT_NULL) { return true; } - munmap(fSharedName, SYNC_MAX_NAME_SIZE+1); - fSharedName = NULL; + mach_port_t task = mach_task_self(); + kern_return_t res; - close(fSharedMem); - fSharedMem = -1; - return true; + jack_log("JackMachSemaphore::Disconnect name = %s", fName); + + if (fServicePort != MACH_PORT_NULL) { + // If we're still holding onto a service port send right for some reason, deallocate it + if ((res = mach_port_deallocate(task, fServicePort)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to deallocate stray service port"); + // Continue cleanup even if this fails; don't bail + } else { + fServicePort = MACH_PORT_NULL; + } + } + + if ((res = mach_port_deallocate(task, fSemaphore)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to deallocate semaphore port"); + return false; + } else { + fSemaphore = MACH_PORT_NULL; + return true; + } } // Server side : destroy the JackGlobals void JackMachSemaphore::Destroy() { kern_return_t res; + mach_port_t task = mach_task_self(); - if (fSemaphore > 0) { - jack_log("JackMachSemaphore::Destroy name = %s", fName); - if ((res = semaphore_destroy(mach_task_self(), fSemaphore)) != KERN_SUCCESS) { - jack_error("JackMachSemaphore::Destroy can't destroy semaphore err = %s", mach_error_string(res)); + if (fSemaphore == MACH_PORT_NULL) { + jack_error("JackMachSemaphore::Destroy semaphore is MACH_PORT_NULL; already destroyed?"); + return; + } + + if (fThreadSemServer) { + if (fThreadSemServer->Kill() < 0) { + jack_error("JackMachSemaphore::Destroy failed to kill semaphore server thread..."); + // Oh dear. How sad. Never mind. } - fSemaphore = 0; - } else { - jack_error("JackMachSemaphore::Destroy semaphore < 0"); + + JackMachThread* thread = fThreadSemServer; + fThreadSemServer = NULL; + delete thread; } - if (!fSharedName) { - return; + if (fSemServer) { + JackMachSemaphoreServer* server = fSemServer; + fSemServer = NULL; + delete server; } - munmap(fSharedName, SYNC_MAX_NAME_SIZE+1); - fSharedName = NULL; + if ((res = mach_port_destroy(task, fServicePort)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to destroy IPC port"); + } else { + fServicePort = MACH_PORT_NULL; + } - close(fSharedMem); - fSharedMem = -1; + if ((res = semaphore_destroy(mach_task_self(), fSemaphore)) != KERN_SUCCESS) { + jack_mach_error(res, "failed to destroy semaphore"); + } else { + fSemaphore = MACH_PORT_NULL; + } - shm_unlink(fName); + jack_log("JackMachSemaphore::Destroy: OK, name = %s", fName); } } // end of namespace diff --git a/macosx/JackMachSemaphoreServer.h b/macosx/JackMachSemaphoreServer.h new file mode 100644 index 000000000..85f3522fb --- /dev/null +++ b/macosx/JackMachSemaphoreServer.h @@ -0,0 +1,56 @@ +/* +Copyright (C) 2021 Peter Bridgman + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMachSemaphoreServer__ +#define __JackMachSemaphoreServer__ + +#include "JackCompilerDeps.h" +#include "JackMachThread.h" + +#include +#include + +namespace Jack +{ + +/*! \brief A runnable thread which listens for IPC messages and replies with a semaphore send right. */ +class SERVER_EXPORT JackMachSemaphoreServer : public JackRunnableInterface +{ + private: + /*! \brief The semaphore send right that will be dispatched to clients. */ + semaphore_t fSemaphore; + + /*! \brief The port on which we will listen for IPC messages. */ + mach_port_t fServerReceive; + + /*! \brief A pointer to a null-terminated string buffer that will be read to obtain the + * server name for reporting purposes. Not managed at all by this type. */ + char* fName; + + public: + JackMachSemaphoreServer(semaphore_t semaphore, mach_port_t server_recv, char* name): + fSemaphore(semaphore), fServerReceive(server_recv), fName(name) + {} + + bool Execute() override; +}; + +} // end of namespace + +#endif diff --git a/macosx/JackMachSemaphoreServer.mm b/macosx/JackMachSemaphoreServer.mm new file mode 100644 index 000000000..21f159b06 --- /dev/null +++ b/macosx/JackMachSemaphoreServer.mm @@ -0,0 +1,87 @@ +/* +Copyright (C) 2021 Peter Bridgman + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackMachSemaphoreServer.h" +#include "JackMachUtils.h" +#include "JackConstants.h" +#include "JackTools.h" +#include "JackError.h" + +#include + +#define jack_mach_error(kern_result, message) \ + jack_mach_error_uncurried("JackMachSemaphoreServer", kern_result, message) + +namespace Jack +{ + +bool JackMachSemaphoreServer::Execute() { + jack_log("JackMachSemaphoreServer::Execute: %s", fName); + + /* Setup a message struct in our local stack frame which we can receive messages into and send + * messages from. */ + struct { + mach_msg_header_t hdr; + mach_msg_trailer_t trailer; + } msg; + + // Block until we receive a message on the fServerReceive port. + mach_msg_return_t recv_err = mach_msg( + &msg.hdr, + MACH_RCV_MSG, + 0, + sizeof(msg), + fServerReceive, + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL + ); + + if (recv_err != MACH_MSG_SUCCESS) { + jack_mach_error(recv_err, "receive error"); + return true; // Continue processing more connections + } + + /* We're going to reuse the message struct that we received the message into to send a reply. + * Setup the semaphore send port that we want to give to the client as the local port... */ + msg.hdr.msgh_local_port = fSemaphore; + + /* + * ... to be returned by copy (_COPY_SEND), to a destination that is _SEND_ONCE that we no + * longer require. That destination will have been set by the client as their local_port, so + * will now already be the remote_port in the message we received (nifty, eh?). + */ + msg.hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, MACH_MSG_TYPE_COPY_SEND); + + mach_msg_return_t send_err = mach_msg( + &msg.hdr, + MACH_SEND_MSG, + sizeof(msg.hdr), // no trailer on send + 0, + MACH_PORT_NULL, + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL); + + if (send_err != MACH_MSG_SUCCESS) { + jack_mach_error(send_err, "send error"); + } + + return true; +} + +} // end of namespace diff --git a/macosx/JackMachUtils.h b/macosx/JackMachUtils.h new file mode 100644 index 000000000..b9cbf59ff --- /dev/null +++ b/macosx/JackMachUtils.h @@ -0,0 +1,36 @@ +/* +Copyright (C) 2021 Peter Bridgman + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMachUtils__ +#define __JackMachUtils__ + +#define jack_mach_error_uncurried(type_name, kern_return, message) \ + jack_error(type_name "::%s: " message " - %i:%s", \ + __FUNCTION__, \ + kern_return, \ + mach_error_string(kern_return)) + +#define jack_mach_bootstrap_err_uncurried(type_name, kern_return, message, service_name) \ + jack_error(type_name "::%s: " message " [%s] - %i:%s", \ + __FUNCTION__, \ + service_name, \ + kern_return, \ + bootstrap_strerror(kern_return)) + +#endif diff --git a/macosx/generate-pkg.sh b/macosx/generate-pkg.sh index a64a5ea0e..79647cd2b 100755 --- a/macosx/generate-pkg.sh +++ b/macosx/generate-pkg.sh @@ -15,7 +15,11 @@ fi # --------------------------------------------------------------------------------------------------------------------- -VERSION=$(cat ../wscript | awk 'sub("VERSION=","")' | tr -d "'") +if [ -n "${2}" ]; then + VERSION="${2}" +else + VERSION=$(cat ../wscript | awk 'sub("VERSION=","")' | tr -d "'") +fi rm -f jack2-osx-root.pkg rm -f jack2-osx-${VERSION}.pkg diff --git a/posix/JackNetUnixSocket.cpp b/posix/JackNetUnixSocket.cpp index 528c95880..af7bf8802 100644 --- a/posix/JackNetUnixSocket.cpp +++ b/posix/JackNetUnixSocket.cpp @@ -143,7 +143,7 @@ namespace Jack } char host_name[32]; - gethostname(host_name, sizeof(host_name)); + GetHostName(host_name, sizeof(host_name)); struct hostent* host = gethostbyname(host_name); if (host) { diff --git a/tools/alsa_in.c b/tools/alsa_in.c index 99d27d13d..a52f06e4d 100644 --- a/tools/alsa_in.c +++ b/tools/alsa_in.c @@ -97,7 +97,7 @@ alsa_format_t formats[] = { { SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" }, { SND_PCM_FORMAT_S32, 4, sample_move_d32u24_sS, sample_move_dS_s32u24, "32bit" }, { SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" }, - { SND_PCM_FORMAT_S24, 4, sample_move_d24_sS, sample_move_dS_s24, "24bit" }, + { SND_PCM_FORMAT_S24, 4, sample_move_d32l24_sS, sample_move_dS_s32l24, "24bit" }, { SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" } #ifdef __ANDROID__ ,{ SND_PCM_FORMAT_S16_LE, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit little-endian" } diff --git a/tools/alsa_out.c b/tools/alsa_out.c index 0c9a8b26c..40cdce3cc 100644 --- a/tools/alsa_out.c +++ b/tools/alsa_out.c @@ -98,7 +98,7 @@ alsa_format_t formats[] = { { SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" }, { SND_PCM_FORMAT_S32, 4, sample_move_d32u24_sS, sample_move_dS_s32u24, "32bit" }, { SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" }, - { SND_PCM_FORMAT_S24, 4, sample_move_d24_sS, sample_move_dS_s24, "24bit" }, + { SND_PCM_FORMAT_S24, 4, sample_move_d32l24_sS, sample_move_dS_s32l24, "24bit" }, { SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" } #ifdef __ANDROID__ ,{ SND_PCM_FORMAT_S16_LE, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit little-endian" } diff --git a/tools/wscript b/tools/wscript index a6a60f5c6..4192a4c8e 100644 --- a/tools/wscript +++ b/tools/wscript @@ -21,6 +21,7 @@ example_tools = { def configure(conf): conf.env['BUILD_TOOL_ALSA_IO'] = conf.env['SAMPLERATE'] and conf.env['BUILD_DRIVER_ALSA'] conf.env['BUILD_TOOL_CLIENT_TRANSPORT'] = conf.env['READLINE'] + conf.env['BUILD_TOOL_CLIENT_NETSOURCE'] = conf.env['CELT'] or conf.env['OPUS'] conf.env['BUILD_TOOL_ZALSA'] = conf.env['ZALSA'] def build(bld): @@ -66,7 +67,7 @@ def build(bld): prog.env['LIB_PTHREAD'] = [':libwinpthread.a'] prog.target = 'jack_transport' - if bld.env['IS_LINUX'] or bld.env['IS_MACOSX']: + if bld.env['BUILD_TOOL_CLIENT_NETSOURCE']: prog = bld(features = 'c cprogram') prog.includes = os_incdir + ['.', '..', '../common/jack', '../common'] prog.source = ['netsource.c', '../common/netjack_packet.c'] diff --git a/windows/JackTypes_os.h b/windows/JackTypes_os.h index 3a5f4dc43..903274933 100644 --- a/windows/JackTypes_os.h +++ b/windows/JackTypes_os.h @@ -31,9 +31,5 @@ typedef UInt64 uint64_t; typedef unsigned short uint16_t; typedef DWORD jack_tls_key; -#if defined(__MINGW32__) -#define PRIu64 "llu" -#endif - #endif diff --git a/windows/inno/win32-mini.iss b/windows/inno/win32-mini.iss new file mode 100644 index 000000000..d5ae49c3d --- /dev/null +++ b/windows/inno/win32-mini.iss @@ -0,0 +1,49 @@ +#include "version.iss" + +[Setup] +AppName=JACK2 +AppPublisher=jackaudio.org +AppPublisherURL=https://github.com/jackaudio/jack2/ +AppSupportURL=https://github.com/jackaudio/jack2/issues/ +AppUpdatesURL=https://github.com/jackaudio/jack2-releases/releases/ +AppVersion={#VERSION} +DefaultDirName={commonpf32}\JACK2 +DisableDirPage=yes +DisableWelcomePage=no +LicenseFile=..\..\COPYING +OutputBaseFilename=jack2-win32-{#VERSION} +OutputDir=. +UsePreviousAppDir=no + +[Types] +Name: "full"; Description: "Full installation"; +Name: "custom"; Description: "Custom installation"; Flags: iscustom; + +[Components] +Name: jackserver; Description: "JACK Server and tools"; Types: full custom; Flags: fixed; +Name: dev; Description: "Developer resources"; Types: full; + +[Files] +; icon +Source: "jack.ico"; DestDir: "{app}"; Components: jackserver; Flags: ignoreversion; +; jackd and server libs +Source: "win32\bin\jackd.exe"; DestDir: "{app}"; Components: jackserver; Flags: ignoreversion; +Source: "win32\lib\libjacknet.dll"; DestDir: "{app}"; Components: jackserver; Flags: ignoreversion; +Source: "win32\lib\libjackserver.dll"; DestDir: "{app}"; Components: jackserver; Flags: ignoreversion; +; drivers +Source: "win32\lib\jack\*.dll"; DestDir: "{app}\jack"; Components: jackserver; Flags: ignoreversion; +; tools +Source: "win32\bin\jack_*.exe"; DestDir: "{app}\tools"; Components: jackserver; Flags: ignoreversion; +; jack client lib (NOTE goes into windir) +Source: "win32\lib\libjack.dll"; DestDir: "{win}"; Components: jackserver; Flags: ignoreversion; +; dev +Source: "win32\include\jack\*.h"; DestDir: "{app}\include\jack"; Components: dev; Flags: ignoreversion; +Source: "win32\lib\*.a"; DestDir: "{app}\lib"; Components: dev; Flags: ignoreversion; +Source: "win32\lib\*.def"; DestDir: "{app}\lib"; Components: dev; Flags: ignoreversion; +Source: "win32\lib\*.lib"; DestDir: "{app}\lib"; Components: dev; Flags: ignoreversion; +Source: "win32\lib\jack\*.a"; DestDir: "{app}\lib\jack"; Components: dev; Flags: ignoreversion; + +[Registry] +Root: HKLM; Subkey: "Software\JACK"; Flags: deletevalue uninsdeletekeyifempty uninsdeletevalue; ValueType: string; ValueName: "ServerExecutable"; ValueData: "{app}\jackd.exe" +Root: HKLM; Subkey: "Software\JACK"; Flags: deletevalue uninsdeletekeyifempty uninsdeletevalue; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}" +Root: HKLM; Subkey: "Software\JACK"; Flags: deletevalue uninsdeletekeyifempty uninsdeletevalue; ValueType: string; ValueName: "Version"; ValueData: "{#VERSION}" diff --git a/windows/inno/win64-mini.iss b/windows/inno/win64-mini.iss new file mode 100644 index 000000000..b089d5f07 --- /dev/null +++ b/windows/inno/win64-mini.iss @@ -0,0 +1,58 @@ +#include "version.iss" + +[Setup] +ArchitecturesInstallIn64BitMode=x64 +AppName=JACK2 +AppPublisher=jackaudio.org +AppPublisherURL=https://github.com/jackaudio/jack2/ +AppSupportURL=https://github.com/jackaudio/jack2/issues/ +AppUpdatesURL=https://github.com/jackaudio/jack2-releases/releases/ +AppVersion={#VERSION} +DefaultDirName={commonpf64}\JACK2 +DisableDirPage=yes +DisableWelcomePage=no +LicenseFile=..\..\COPYING +OutputBaseFilename=jack2-win64-{#VERSION} +OutputDir=. +UsePreviousAppDir=no + +[Types] +Name: "full"; Description: "Full installation"; +Name: "custom"; Description: "Custom installation"; Flags: iscustom; + +[Components] +Name: jackserver; Description: "JACK Server and tools"; Types: full custom; Flags: fixed; +Name: dev; Description: "Developer resources"; Types: full; + +[Files] +; icon +Source: "jack.ico"; DestDir: "{app}"; Components: jackserver; Flags: ignoreversion; +; jackd and server libs +Source: "win64\bin\jackd.exe"; DestDir: "{app}"; Components: jackserver; Flags: ignoreversion; +Source: "win64\lib\libjacknet64.dll"; DestDir: "{app}"; Components: jackserver; Flags: ignoreversion; +Source: "win64\lib\libjackserver64.dll"; DestDir: "{app}"; Components: jackserver; Flags: ignoreversion; +; drivers +Source: "win64\lib\jack\*.dll"; DestDir: "{app}\jack"; Components: jackserver; Flags: ignoreversion; +; tools +Source: "win64\bin\jack_*.exe"; DestDir: "{app}\tools"; Components: jackserver; Flags: ignoreversion; +; jack client lib (NOTE goes into windir) +Source: "win64\lib\libjack64.dll"; DestDir: "{win}"; Components: jackserver; Flags: ignoreversion; +Source: "win64\lib32\libjack.dll"; DestDir: "{win}"; Components: jackserver; Flags: ignoreversion; +; dev +Source: "win64\include\jack\*.h"; DestDir: "{app}\include\jack"; Components: dev; Flags: ignoreversion; +Source: "win64\lib\*.a"; DestDir: "{app}\lib"; Components: dev; Flags: ignoreversion; +Source: "win64\lib\*.def"; DestDir: "{app}\lib"; Components: dev; Flags: ignoreversion; +Source: "win64\lib\*.lib"; DestDir: "{app}\lib"; Components: dev; Flags: ignoreversion; +Source: "win64\lib32\*.a"; DestDir: "{app}\lib32"; Components: dev; Flags: ignoreversion; +Source: "win64\lib32\*.def"; DestDir: "{app}\lib32"; Components: dev; Flags: ignoreversion; +Source: "win64\lib32\*.lib"; DestDir: "{app}\lib32"; Components: dev; Flags: ignoreversion; +Source: "win64\lib\jack\*.a"; DestDir: "{app}\lib\jack"; Components: dev; Flags: ignoreversion; + +[Registry] +Root: HKLM; Subkey: "Software\JACK"; Flags: deletevalue uninsdeletekeyifempty uninsdeletevalue; ValueType: string; ValueName: "ServerExecutable"; ValueData: "{app}\jackd.exe" +Root: HKLM; Subkey: "Software\JACK"; Flags: deletevalue uninsdeletekeyifempty uninsdeletevalue; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}" +Root: HKLM; Subkey: "Software\JACK"; Flags: deletevalue uninsdeletekeyifempty uninsdeletevalue; ValueType: string; ValueName: "Version"; ValueData: "{#VERSION}" +; 32bit compat keys +Root: HKLM; Subkey: "Software\WOW6432Node\JACK"; Flags: deletevalue uninsdeletekeyifempty uninsdeletevalue; ValueType: string; ValueName: "ServerExecutable"; ValueData: "{app}\jackd.exe" +Root: HKLM; Subkey: "Software\WOW6432Node\JACK"; Flags: deletevalue uninsdeletekeyifempty uninsdeletevalue; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}" +Root: HKLM; Subkey: "Software\WOW6432Node\JACK"; Flags: deletevalue uninsdeletekeyifempty uninsdeletevalue; ValueType: string; ValueName: "Version"; ValueData: "{#VERSION}" diff --git a/windows/portaudio/JackPortAudioDevices.h b/windows/portaudio/JackPortAudioDevices.h index 93af2541d..fa1fd3bb8 100644 --- a/windows/portaudio/JackPortAudioDevices.h +++ b/windows/portaudio/JackPortAudioDevices.h @@ -24,7 +24,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include #include + +#if defined(HAVE_ASIO) #include +#endif /*! \brief A PortAudio Devices manager. diff --git a/wscript b/wscript index e4494ffe3..e0d32c8de 100644 --- a/wscript +++ b/wscript @@ -11,7 +11,7 @@ import sys from waflib import Logs, Options, Task, Utils from waflib.Build import BuildContext, CleanContext, InstallContext, UninstallContext -VERSION='1.9.19' +VERSION='1.9.20' APPNAME='jack' JACK_API_VERSION = '0.1.0' @@ -218,12 +218,11 @@ def configure(conf): if conf.env['IS_WINDOWS']: conf.env.append_unique('CCDEFINES', '_POSIX') conf.env.append_unique('CXXDEFINES', '_POSIX') - if Options.options.platform == 'msys': + if Options.options.platform in ('msys', 'win32'): conf.env.append_value('INCLUDES', ['/mingw64/include']) conf.check( - header_name='asio.h', - includes='/opt/asiosdk/common', - msg='Checking for ASIO SDK', + header_name='pa_asio.h', + msg='Checking for PortAudio ASIO support', define_name='HAVE_ASIO', mandatory=False) @@ -388,7 +387,7 @@ def configure(conf): # existing install paths that use ADDON_DIR rather than have to # have special cases for windows each time. conf.env['ADDON_DIR'] = conf.env['LIBDIR'] + '/jack' - if Options.options.platform == 'msys': + if Options.options.platform in ('msys', 'win32'): conf.define('ADDON_DIR', 'jack') conf.define('__STDC_FORMAT_MACROS', 1) # for PRIu64 else: