--- /dev/null
+*
+!docs
+!meson*
+!container
+!src
+!subprojects
+!linux
+!win
\ No newline at end of file
--- /dev/null
+# JackTrip container image using Redhat Universal Base Image ubi-init
+#
+# Copyright (c) 2023-2024 JackTrip Labs, Inc.
+# MIT License.
+#
+# To build this from repository root: "podman build -t jacktrip/jacktrip ."
+
+# container image versions
+ARG FEDORA_VERSION=34
+ARG JACK_VERSION=latest
+
+
+###############
+# STAGE BUILDER
+###############
+# use a temporary container to build jacktrip
+FROM registry.fedoraproject.org/fedora:${FEDORA_VERSION} AS builder
+
+# install tools require to build jacktrip
+RUN dnf install -y --nodocs gcc gcc-c++ meson python3-pyyaml python3-jinja2 qt5-qtbase-devel jack-audio-connection-kit-devel
+
+# copy files from repository to build container
+COPY . /root
+
+# configure and run the build
+RUN cd /root \
+ && PKG_CONFIG_PATH=/usr/local/lib/pkgconfig meson setup -Ddefault_library=static -Dnogui=true --buildtype release builddir \
+ && meson compile -C builddir
+
+# stage files in INSTALLDIR
+ENV INSTALLDIR=/opt
+RUN mkdir -p ${INSTALLDIR}/usr/local/bin/ ${INSTALLDIR}/usr/lib64/ ${INSTALLDIR}/etc/systemd/system/ \
+ && cp /lib64/libQt5Core.so.5 /lib64/libQt5Network.so.5 ${INSTALLDIR}/usr/lib64/ \
+ && cp /root/builddir/jacktrip ${INSTALLDIR}/usr/local/bin/ \
+ && strip ${INSTALLDIR}/usr/local/bin/jacktrip
+COPY linux/container/jacktrip.service ${INSTALLDIR}/etc/systemd/system/
+
+
+########################
+# STAGE JACKTRIP (FINAL)
+########################
+# use the jack ubi-init container
+FROM jacktrip/jack:${JACK_VERSION}
+
+# install libraries that we need for things to run
+RUN dnf install -y --nodocs libicu pcre libstdc++ compat-openssl11 pcre2-utf16
+
+# add jacktrip user, enable service and allow access to jackd
+RUN useradd -r -m -N -G audio -s /usr/sbin/nologin jacktrip \
+ && chown -R jacktrip.audio /home/jacktrip \
+ && chmod g+rwx /home/jacktrip \
+ && ln -s /etc/systemd/system/jacktrip.service /etc/systemd/system/multi-user.target.wants \
+ && sed -i 's,PassEnvironment=.*,PassEnvironment=SAMPLE_RATE BUFFER_SIZE JACK_OPTS JACKTRIP_OPTS,' /etc/systemd/system/defaults.service \
+ && sed -i 's,WantedBy=.*,WantedBy=multi-user.target jack.service jacktrip.service,' /etc/systemd/system/defaults.service \
+ && echo 'if [[ -z "$JACKTRIP_OPTS" ]]; then JACKTRIP_OPTS="-S -t -z --hubpatch 4 --bufstrategy 4 -q auto"; fi' >> /usr/sbin/defaults.sh \
+ && echo 'echo "JACKTRIP_OPTS=\"$JACKTRIP_OPTS\"" > /etc/default/jacktrip' >> /usr/sbin/defaults.sh
+
+# copy the artifacts we built into the final container image
+COPY --from=builder /opt /
+
+# jacktrip hub server listens on 4464 and uses 61000+ for clients
+EXPOSE 4464/tcp
+EXPOSE 61000-61100/udp
\ No newline at end of file
+- Version: "2.2.3"
+ Date: 2024-03-04
+ Description:
+ - (added) New container images for JackTrip hub server
+ - (fixed) Support for audio interfaces on OSX with multiple channels
+ - (fixed) Hub server crashes when trying to rebind ports
+ - (fixed) VS Mode blacklisted Generic Low Latency ASIO Driver
+ - (fixed) VS Mode inconsistent initial connection state
- Version: "2.2.2"
Date: 2024-02-09
Description:
--- /dev/null
+# Run a JackTrip Server in a Container
+
+Copyright (c) 2023-2024 JackTrip Labs, Inc.
+See [MIT License](../../LICENSES/MIT.txt)
+
+This repository provides the source code for building a container image to
+run your own JackTrip hub server. It uses the
+[Jack base container](https://github.com/jacktriplabs/jack-container)
+and runs the [Jack Audio Connection Kit](https://jackaudio.org/)
+(`jackd`) and JackTrip servers as systemd services. The `jackd` server
+is configued to use the `dummy` audio backend so that no audio interface
+is required.
+
+New container images are built automatically for each release of JackTrip
+and made freely available on
+[Docker Hub](https://hub.docker.com/repository/docker/jacktrip/jacktrip/general).
+
+To build a container image using `podman`:
+
+```bash
+podman build -t jacktrip/jacktrip .
+```
+
+To run a JackTrip container using `podman`:
+
+```bash
+podman run --name jacktrip --network=host --shm-size=128M -d jacktrip/jacktrip
+```
+
+`jackd` requires the ability to lock about 128MB of shared memory, and
+both `jackd` and `jacktrip` will try to run realtime priority threads.
+Be sure that your memory limits (`ulimit`) are set appropriately.
+
+```
+ulimit -l 128000000
+ulimit -r 10
+```
+
+If using `docker`, you will need to run this as a privileged container:
+
+```bash
+docker run --name jacktrip --network=host --shm-size=128M --privileged -d jacktrip/jacktrip
+```
+
+Docker Desktop users on Mac and Windows computers may prefer to specify
+a port range instead of using host networking:
+
+```bash
+docker run --name jacktrip -p 4464:4464/tcp -p 61000-61100:61000-61100/udp --shm-size=128M --privileged -d jacktrip/jacktrip
+```
+
+By default, the servers will run using a sample rate of 48Khz and buffer
+size of 128. You can override these using the following environment
+variables:
+
+* __SAMPLE_RATE__: use this to set the sample rate for the `jackd` server.
+Note that all clients connecting to the server must use the same setting.
+The default is 48000.
+
+* __BUFFER_SIZE__: use this to set the buffer size, also known as frames
+per period, for the `jackd` server. The default is 128.
+
+* __JACK_OPTS__: use this to override all of the options passed to the
+`jackd` server. __SAMPLE_RATE__ and __BUFFER_SIZE__ will be ignored
+if this is defined.
+
+* __JACKTRIP_OPTS__: use this to override all of the options passed to the
+`jacktrip` server. The default options are:
+`-S -t -z --hubpatch 4 --bufstrategy 4 -q auto`
--- /dev/null
+[Unit]
+Description=JackTrip-Server
+After=network.target jack.service defaults.service
+Wants=jack.service defaults.service
+
+[Service]
+Type=simple
+User=jacktrip
+Group=audio
+NoNewPrivileges=true
+ProtectSystem=true
+ProtectHome=true
+Nice=-20
+#IOSchedulingClass=realtime
+#IOSchedulingPriority=0
+Environment="JACK_NO_AUDIO_RESERVATION=1"
+Environment="JACK_NO_START_SERVER=1"
+Environment="JACK_PROMISCUOUS_SERVER=audio"
+EnvironmentFile=/etc/default/jacktrip
+ExecStartPre=/usr/local/bin/jack_wait -w -t 5
+ExecStart=/usr/local/bin/jacktrip $JACKTRIP_OPTS
+Restart=always
+RestartSec=5
+StandardOutput=journal
+StandardError=inherit
+SyslogIdentifier=jacktrip
+LimitMEMLOCK=infinity
+LimitRTPRIO=99
+LimitNOFILE=200000
+LimitNPROC=200000
+
+[Install]
+WantedBy=multi-user.target
{
"app_name": "JackTrip",
"releases": [
+ {
+ "version": "2.2.2",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v2.2.2",
+ "download": {
+ "date": "2024-02-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v2.2.2-macOS-x64-signed-installer.pkg",
+ "downloadSize": "177374348",
+ "sha256": "80048be618c272c108fd9a45fb77167ca09686406a24065dba20edf05aabd088"
+ }
+ },
{
"version": "2.2.1",
"changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v2.2.1",
{
"app_name": "JackTrip",
"releases": [
+ {
+ "version": "2.2.2",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v2.2.2",
+ "download": {
+ "date": "2024-02-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v2.2.2-Windows-x64-signed-installer.msi",
+ "downloadSize": "108511232",
+ "sha256": "f2ea2d2ea1b40607e1fc6fc22cac4f51630b66da4e8f1925f529396bb57e6010"
+ }
+ },
{
"version": "2.2.1",
"changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v2.2.1",
{
"app_name": "JackTrip",
"releases": [
+ {
+ "version": "2.2.2",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v2.2.2",
+ "download": {
+ "date": "2024-02-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v2.2.2-Linux-x64-binary.zip",
+ "downloadSize": "1239713",
+ "sha256": "d0c7e3291d3b1753968a52812a6cae9b926ed1d5c17c23e2a87c1a09f14f10ea"
+ }
+ },
{
"version": "2.2.1",
"changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v2.2.1",
{
"app_name": "JackTrip",
"releases": [
+ {
+ "version": "2.2.2",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v2.2.2",
+ "download": {
+ "date": "2024-02-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v2.2.2-macOS-x64-signed-installer.pkg",
+ "downloadSize": "177374348",
+ "sha256": "80048be618c272c108fd9a45fb77167ca09686406a24065dba20edf05aabd088"
+ }
+ },
{
"version": "2.2.1",
"changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v2.2.1",
{
"app_name": "JackTrip",
"releases": [
+ {
+ "version": "2.2.2",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v2.2.2",
+ "download": {
+ "date": "2024-02-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v2.2.2-Windows-x64-signed-installer.msi",
+ "downloadSize": "108511232",
+ "sha256": "f2ea2d2ea1b40607e1fc6fc22cac4f51630b66da4e8f1925f529396bb57e6010"
+ }
+ },
{
"version": "2.2.1",
"changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v2.2.1",
//*******************************************************************************
bool Regulator::getStats(RingBuffer::IOStat* stat, bool reset)
{
+ if (!mFPPratioIsSet) {
+ return false;
+ }
+
if (reset) { // all are unused, this is copied from superclass
mUnderruns = 0;
mOverflows = 0;
public:
Settings(bool guiEnabled = false, QObject* parent = nullptr)
- : QObject(parent)
+ : QObject(parent), mGuiEnabled(guiEnabled), mAudioTester(new AudioTester)
+ {
#ifdef NO_GUI
- , mGuiEnabled(false)
-#else
- , mGuiEnabled(guiEnabled)
+ mGuiEnabled = false;
#endif
- , mAudioTester(new AudioTester)
- {
}
/// \brief Parses command line input
, mBindPort(bind_port)
, mPeerPort(peer_port)
, mRunMode(runmode)
+#if defined(_WIN32)
+ , mSocket(INVALID_SOCKET)
+#else
+ , mSocket(-1)
+#endif
, mAudioPacket(NULL)
, mFullPacket(NULL)
, mUdpRedundancyFactor(udp_redundancy_factor)
{
delete[] mAudioPacket;
delete[] mFullPacket;
- if (mRunMode == RECEIVER) {
-#ifdef _WIN32
+ closeSocket();
+ wait();
+}
+
+//*******************************************************************************
+void UdpDataProtocol::stop()
+{
+ closeSocket();
+ DataProtocol::stop();
+}
+
+//*******************************************************************************
+void UdpDataProtocol::closeSocket()
+{
+ if (mRunMode != RECEIVER) {
+ return;
+ }
+#if defined(_WIN32)
+ if (mSocket != INVALID_SOCKET) {
closesocket(mSocket);
+ mSocket = INVALID_SOCKET;
+ }
#else
+ if (mSocket != -1) {
::close(mSocket);
-#endif
+ mSocket = -1;
}
- wait();
+#endif
}
//*******************************************************************************
*/
virtual ~UdpDataProtocol();
+ /// \brief Stops the execution of the Thread
+ virtual void stop();
+
/** \brief Set the Peer address to connect to
* \param peerHostOrIP IPv4 number or host name
*/
int full_packet_size);
private:
+ void closeSocket();
bool datagramAvailable();
int mBindPort; ///< Local Port number to Bind
}
Item {
+ visible: isUsingRtAudio
Layout.preferredWidth: 40 * virtualstudio.uiScale
Layout.preferredHeight: 64 * virtualstudio.uiScale
Layout.bottomMargin: 5 * virtualstudio.uiScale
Button {
id: changeDevicesButton
- visible: isUsingRtAudio
width: 36 * virtualstudio.uiScale
height: 36 * virtualstudio.uiScale
anchors.top: parent.top
}
enabled: !Boolean(audio.devicesError) && audio.backendAvailable && audio.audioReady
onClicked: {
+ audio.stopAudio(true);
virtualstudio.studioToJoin = virtualstudio.currentStudio.id;
virtualstudio.windowState = "connected";
virtualstudio.saveSettings();
property string serverLocation: "Germany - Berlin"
property string flagImage: "flags/DE.svg"
- property string hostname: "app.jacktrip.org"
+ property string hostname: "app.jacktrip.com"
property string studioName: "Test Studio"
property string studioId: ""
property string inviteKeyString: ""
onClicked: {
inviteCopied = true;
if (virtualstudio.testMode) {
- hostname = "test.jacktrip.org";
+ hostname = "test.jacktrip.com";
}
if (!inviteKeyString) {
clipboard.setText(qsTr("https://" + hostname + "/studios/" + studioId + "?invited=true"));
query.addQueryItem(QStringLiteral("client_id"), AUTH_CLIENT_ID);
if (m_testMode) {
query.addQueryItem(QStringLiteral("returnTo"),
- QStringLiteral("https://test.jacktrip.org/"));
+ QStringLiteral("https://next-test.jacktrip.com/"));
} else {
query.addQueryItem(QStringLiteral("returnTo"),
- QStringLiteral("https://app.jacktrip.org/"));
+ QStringLiteral("https://www.jacktrip.com/"));
}
logoutURL.setQuery(query);
#ifdef _WIN32
// Realtek ASIO: seems to crash any computer that tries to use it
QString::fromUtf8("Realtek ASIO"),
+ QString::fromUtf8("Generic Low Latency ASIO Driver"),
#endif
// JackRouter: crashes if not running; use Jack backend instead
QString::fromUtf8("JackRouter"),
const QString AUTH_TOKEN_URI = QStringLiteral("https://auth.jacktrip.org/oauth/token");
const QString AUTH_AUDIENCE = QStringLiteral("https://api.jacktrip.org");
const QString AUTH_CLIENT_ID = QStringLiteral("cROUJag0UVKDaJ6jRAKRzlVjKVFNU39I");
-const QString PROD_API_HOST = QStringLiteral("app.jacktrip.org");
-const QString TEST_API_HOST = QStringLiteral("test.jacktrip.org");
+const QString PROD_API_HOST = QStringLiteral("app.jacktrip.com");
+const QString TEST_API_HOST = QStringLiteral("test.jacktrip.com");
const QString AUTH_SERVER_HOST = QStringLiteral("auth.jacktrip.org");
#endif // VSCONSTANTS_H
};
// Add stats to heartbeat body
- if (!m_pinger.isNull()) {
+ if (!m_pinger.isNull() && m_pinger->active()) {
VsPinger::PingStat stats = m_pinger->getPingStats();
// API server expects RTTs to be in int64 nanoseconds, so we must convert
// Virtual Studio
QString host = studioInfo.sessionId();
host.append(QString::fromStdString(".jacktrip.cloud"));
- m_pinger.reset(new VsPinger(QString::fromStdString("wss"), host,
- QString::fromStdString("/ping")));
+ if (studioInfo.isManaged()) {
+ m_pinger.reset(new VsPinger(QString::fromStdString("wss"), host,
+ QString::fromStdString("/ping")));
+ }
}
// stopJackTrip stops the current jacktrip process if applicable
// We have a heartbeat from which we can read the studio auth token
// Use it to set up and start the pinger connection
QString token = newState["authToken"].toString();
- if (!m_pinger.isNull() && !m_pinger->active()) {
+ if (!m_pinger.isNull() && !m_pinger->active() && !token.isEmpty()) {
m_pinger->setToken(token);
m_pinger->start();
}
req.setRawHeader(QByteArray("Upgrade"), QByteArray("websocket"));
req.setRawHeader(QByteArray("Connection"), QByteArray("Upgrade"));
req.setRawHeader(QByteArray("Authorization"), authVal.toUtf8());
- req.setRawHeader(QByteArray("Origin"), QByteArray("https://app.jacktrip.org"));
+ req.setRawHeader(QByteArray("Origin"), QByteArray("http://jacktrip.local"));
req.setRawHeader(QByteArray("APIPrefix"), m_apiPrefix.toUtf8());
req.setRawHeader(QByteArray("APISecret"), m_apiSecret.toUtf8());
#include "AudioInterface.h"
-constexpr const char* const gVersion = "2.2.2"; ///< JackTrip version
+constexpr const char* const gVersion = "2.2.3"; ///< JackTrip version
//*******************************************************************************
/// \name Default Values
--- /dev/null
+--- a/RtAudio.cpp 2024-02-11 15:05:31
++++ b/RtAudio.cpp 2024-02-11 15:07:49
+@@ -1782,7 +1782,7 @@
+ stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
+
+ if ( streamCount == 1 )
+- stream_.nDeviceChannels[mode] = description.mChannelsPerFrame;
++ stream_.nDeviceChannels[mode] = streamChannels;
+ else // multiple streams
+ stream_.nDeviceChannels[mode] = channels;
+ stream_.nUserChannels[mode] = channels;
source_url = https://github.com/thestk/rtaudio/archive/refs/tags/6.0.1.tar.gz
source_filename = 6.0.1.tar.gz
source_hash = 7206c8b6cee43b474f43d64988fefaadfdcfc4264ed38d8de5f5d0e6ddb0a123
-diff_files = rtaudio-remove-input-disconnect-listener.patch
+diff_files = rtaudio-remove-input-disconnect-listener.patch,rtaudio-coreaudio-stream-channels.patch
[provide]
dependency_names = rtaudio