Skip to content

Instantly share code, notes, and snippets.

@C0nsultant
Last active January 19, 2021 17:34
Show Gist options
  • Save C0nsultant/fd5ad36728209d2888e87220d4731cec to your computer and use it in GitHub Desktop.
Save C0nsultant/fd5ad36728209d2888e87220d4731cec to your computer and use it in GitHub Desktop.
JACK2 SEGFAULT with repeated client names
#!/usr/bin/env zsh
brew install --build-from-source ./jack2.rb
clang++ ./Reproducer.cpp ./JackClient.cpp -I. -ljack -L/usr/local/Cellar/jack2/1.9.16/lib/ -std=c++14 -O2 -openmp -o Reproducer
# launch "x64 Native Tools Command Prompt for VS 2019"
cl /c .\Reproducer.cpp .\JackClient.cpp /I"C:\Program Files\JACK2\include" /EHsc /O2 /openmp /std:c++14
link /OUT:".\Reproducer.exe" "C:\Program Files\JACK2\lib\libjack64.lib" /SUBSYSTEM:CONSOLE /MACHINE:X64 .\Reproducer.obj .\JackClient.obj
class Jack2 < Formula
desc "JACK Audio Connection Kit"
homepage "http://jackaudio.org"
version "1.9.16"
revision 0
url "https://github.com/jackaudio/jack2/archive/v1.9.16.zip"
sha256 "f3d00e42d184505a340cffd573372ef19663bc91d2551c78427e79cf428c6bb4"
head "https://github.com/jackaudio/jack2.git"
uses_from_macos "util-linux"
depends_on "aften" => :recommended
depends_on "berkeley-db" => :recommended
depends_on "eigen" => :recommended
depends_on "libsamplerate" => :recommended
depends_on "libsndfile" => :recommended
depends_on "opus" => :recommended
depends_on "pkg-config" => :build
depends_on "portaudio" => :recommended
depends_on "readline" => :recommended
def install
system "./waf", "configure", "--prefix=#{prefix}"
system "./waf", "build"
system "./waf", "install"
end
plist_options :manual => "jackd -R -X coremidi -d coreaudio"
def plist
<<~EOS
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>#{plist_name}</string>
<key>WorkingDirectory</key>
<string>#{opt_prefix}</string>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/bin:/bin:/usr/sbin:/sbin:#{HOMEBREW_PREFIX}/bin</string>
</dict>
<key>ProgramArguments</key>
<array>
<string>#{opt_bin}/jackd</string>
<string>-R</string>
<string>-X</string>
<string>coremidi</string>
<string>-d</string>
<string>coreaudio</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
EOS
end
end
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <vector>
#include "JackClient.h"
JackClient::JackClient(
std::string name,
jack_options_t options,
std::string serverName
)
: m_isActive{ false }
{
if (name.length() > jack_client_name_size())
{
std::cerr << "JACK client name length ("
<< name.length()
<< ") exceeds allowed size ("
<< jack_client_name_size()
<< "). Truncating name accordingly."
<< std::endl;
name.resize(jack_client_name_size());
}
options = static_cast<jack_options_t>(options | JackServerName | JackNoStartServer | JackUseExactName);
jack_status_t status;
jack_client_t* client = jack_client_open(name.c_str(), options, &status, serverName.c_str());
auto deleter = [](jack_client_t* client) {
if (client != nullptr)
{
jack_deactivate(client);
jack_client_close(client);
}
};
m_client = decltype(m_client)(client, deleter);
if (m_client == nullptr)
{
std::cerr << "Could not open JACK client (status " << status << ").";
if (status & JackServerFailed)
std::cerr << " Unable to connect to JACK server.";
std::cerr << std::endl;
}
}
JackClient::~JackClient() = default;
bool
JackClient::activate()
{
if (m_isActive)
return false;
int status = jack_activate(m_client.get());
if (status != 0)
{
std::cerr << "Failed to activate client (status " << status << ")." << std::endl;
return false;
}
m_isActive = true;
return m_isActive;
}
bool
JackClient::deactivate()
{
if (!m_isActive)
return false;
int status = jack_deactivate(m_client.get());
if (status != 0)
{
std::cerr << "Failed to deactivate client (status " << status << ")." << std::endl;
return false;
}
m_isActive = false;
return true;
}
jack_port_t*
JackClient::registerPort(std::string name, bool isInput)
{
if (name.length() > jack_port_name_size())
{
std::cerr << "JACK port name length ("
<< name.length()
<< ") exceeds allowed size ("
<< jack_port_name_size()
<< "). Truncating name accordingly."
<< std::endl;
name.resize(jack_port_name_size());
}
std::string fullName = std::string(jack_get_client_name(m_client.get())) + ":" + name;
auto exists = [&fullName](jack_port_t* port) -> bool {
return 0 == std::strncmp(jack_port_name(port), fullName.c_str(), fullName.length());
};
if (std::any_of(inputPorts.cbegin(), inputPorts.cend(), exists))
{
std::cerr << "Input Port with name '" << name << "' already exists.";
return nullptr;
}
if (std::any_of(outputPorts.cbegin(), outputPorts.cend(), exists))
{
std::cerr << "Output Port with name '" << name << "' already exists.";
return nullptr;
}
unsigned long flags = (isInput == true) ? JackPortIsInput : JackPortIsOutput;
flags |= JackPortIsPhysical;
jack_port_t* port = jack_port_register(
m_client.get(),
name.c_str(),
JACK_DEFAULT_AUDIO_TYPE, //mono, f32, PCM
flags,
0
);
if (port == nullptr)
std::cerr << "Could not register JACK port." << std::endl;
if (isInput)
inputPorts.push_back(port);
else
outputPorts.push_back(port);
return port;
}
void
JackClient::setProcessCallback(JackProcessCallback processCallback, void* arg)
{
if (m_isActive)
{
std::cerr << "Can not set JACK process callback on an active Client." << std::endl;
}
int status = jack_set_process_callback(m_client.get(), processCallback, arg);
if (status != 0)
{
std::cerr << "Failed to set client process callback (status " << status << ")." << std::endl;
}
}
#pragma once
// JACK-Windows compatability has not seen much love, avoid erroneous redefinitions
#include <cstdint>
#define _STDINT_H
#include <jack/jack.h>
#include <functional>
#include <memory>
#include <string>
#include <vector>
class JackClient
{
public:
explicit JackClient(std::string name,
jack_options_t options = JackNullOption,
std::string serverName = "default");
~JackClient();
bool activate();
bool deactivate();
jack_port_t* registerPort(std::string name, bool isInput);
void setProcessCallback(JackProcessCallback processCallback, void* arg);
private:
std::vector< jack_port_t* > inputPorts, outputPorts;
std::shared_ptr< jack_client_t > m_client;
bool m_isActive;
};
diff --git a/build-jack2.sh b/build-jack2.sh
index f595199..8e42302 100755
--- a/build-jack2.sh
+++ b/build-jack2.sh
@@ -39,7 +39,7 @@ fi
# ---------------------------------------------------------------------------------------------------------------------
# jack2
-jack2_args="--prefix=${jack2_prefix}"
+jack2_args="--prefix=${jack2_prefix} --debug"
if [ "${CROSS_COMPILING}" -eq 1 ]; then
if [ "${LINUX}" -eq 1 ]; then
diff --git a/setup/env.sh b/setup/env.sh
index 10bae13..6d0ed65 100644
--- a/setup/env.sh
+++ b/setup/env.sh
@@ -47,9 +47,9 @@ PAWPAW_TMPDIR="/tmp"
## build flags
-BUILD_FLAGS="-O2 -pipe -I${PAWPAW_PREFIX}/include"
+BUILD_FLAGS="-O0 -g -pipe -I${PAWPAW_PREFIX}/include"
BUILD_FLAGS+=" -mtune=generic -msse -msse2 -ffast-math"
-BUILD_FLAGS+=" -fPIC -DPIC -DNDEBUG -D_FORTIFY_SOURCE=2"
+BUILD_FLAGS+=" -fPIC -DPIC -D_FORTIFY_SOURCE=2"
BUILD_FLAGS+=" -fdata-sections -ffunction-sections -fno-common -fstack-protector -fvisibility=hidden"
if [ "${MACOS_UNIVERSAL}" -eq 0 ]; then
@@ -90,7 +90,7 @@ if [ "${MACOS}" -eq 1 ]; then
LINK_FLAGS+=" -mmacosx-version-min=10.8 -stdlib=libc++ -arch x86_64"
fi
else
- LINK_FLAGS+=" -Wl,-O1 -Wl,--as-needed -Wl,--gc-sections -Wl,--no-undefined -Wl,--strip-all"
+ LINK_FLAGS+=" -Wl,-O0 -Wl,--as-needed -Wl,--gc-sections -Wl,--no-undefined"
if [ "${WIN32}" -eq 1 ]; then
LINK_FLAGS+=" -static -Wl,-Bstatic"
if [ "${CROSS_COMPILING}" -eq 0 ] && [ -e "/usr/lib/libssp.a" ]; then
#include <memory>
#include <vector>
#include "JackClient.h"
int main(int argc, char* argv[]) {
int num_clients = 100;
auto callback = [](uint32_t nframes, void* arg) -> int {
int tmp = 0;
for (uint32_t i = 0; i < nframes; ++i)
++tmp;
return 0;
};
int it = 0;
while (true){
std::vector< std::shared_ptr< JackClient > > clients(num_clients);
#pragma omp parallel for
for (int i = 0; i < num_clients; ++i) {
clients[i] = std::make_shared< JackClient >("ClientName" + std::to_string(i) + " (suffx)");
clients[i]->registerPort("input_0", false);
clients[i]->registerPort("input_1", false);
clients[i]->registerPort("output_0", true);
clients[i]->registerPort("output_1", true);
clients[i]->setProcessCallback(callback, nullptr);
}
#pragma omp parallel for
for (int i = 0; i < num_clients; ++i) {
clients[i]->activate();
}
#pragma omp parallel for
for (int i = 0; i < num_clients; ++i) {
clients[i]->deactivate();
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment