--- /dev/null
+# QtCreator user files
+*.pro.user
+*.pro.user.*
+---
+master
+
+---
+1.2 (release candidate, not yet tagged)
+- (added) jack patching modes (-p) for Hub Mode server (-S)
+- (fixed) Compilation under ubuntu
+- (removed) setRealtimeProcessPriority()
+- (removed) Rtaudio mode (but still has dependencies)
+- (fixed) IPv4-mapped IPv6 addressing bug
+...
+- (fixed) Fixed compilation for MacOSX10.11.sdk.
+- (update) Updated to RtAudio 4.1.1, and using shared lib in linux.
+
---
1.1
- (added) Support for RtAudio. Jacktrip can now be used without Jack
---
1.0.3
-- (added) Redundancy Algorithm for UDP Packets to to avoid glitches with packet losses
+- (added) Redundancy Algorithm for UDP Packets to avoid glitches with packet losses
- (fixed) Now compiles on 64bits machines
- (fixed) Improved exceptions handling
- (added) Basic Karplus-Strong model added as Plug-in
-- (added) Some functionality reimplemented using signals and slots for
+- (added) Some functionality reimplemented using signals and slots for
more flexibility
- (added) Multiple-Client-Server in alpha testing, expect it working in the next release
JackTrip: A System for High-Quality Audio Network Performance over the Internet.\r
\r
---\r
-MacOS X (10.9 or higher) Installation:\r
+MacOS X (10.9 or higher) installation:\r
\r
-If you are installing on MacOS X, a binary is provided. You just need to have JackOSX installed on your machine\r
-http://www.jackosx.com/\r
+If you are installing on MacOS X, a binary is provided with each release (download the latest release from https://github.com/jacktrip/jacktrip/releases before proceeding).\r
+You need to have a working jack installation on your machine (see below).\r
+\r
+To install (using Terminal):\r
+\r
+$ git clone https://github.com/jacktrip/jacktrip.git\r
+$ cd jacktrip/src\r
+$ sudo cp jacktrip /usr/local/bin/\r
+ (enter your password when prompted)\r
\r
-To install (using Terminal): go to bin/ directory and type:\r
+$ sudo chmod 755 /usr/local/bin/jacktrip\r
+ (now you can run jacktrip from any directory using Terminal)\r
\r
- sudo cp jacktrip /usr/bin/\r
- (enter your password when prompted)\r
\r
- sudo chmod 755 /usr/bin/jacktrip\r
- (now you can run jacktrip from any directory using Terminal)\r
+\r
+To build using QtCreator (tested using QtCreator 4.11 and macOS 10.13.6):\r
+\r
+ * Open jacktrip.pro using QtCreator\r
+ * Choose a correctly configured Kit\r
+ * Install Jack:\r
+ brew install jack\r
+ brew install qjackctl\r
+\r
+\r
+---\r
+Fedora installation (also tested on Ubuntu Studio):\r
+\r
+To install on Fedora (and possibly other Linux distributions), you need qt5, jack-audio-connection-kit-devel, and rtaudio.\r
+\r
+How to install qt5 and other needed tools on Fedora: \r
+dnf install qt5-devel\r
+dnf groupinstall "C Development Tools and Libraries"\r
+dnf groupinstall "Development Tools"\r
+dnf install jack-audio-connection-kit-devel alsa-lib-devel iperf qjackctl audacity git\r
+\r
+Ubuntu Studio already comes with jack and qjackctl but you may have to install libjack-dev. Other basic tools can be installed on Ubuntu with:\r
+\r
+sudo apt install build-essential\r
+\r
+\r
+For rtaudio, if you don’t have the latest package, install from source:\r
+\r
+$ git clone https://github.com/thestk/rtaudio\r
+$ cd rtaudio\r
+$ bash autogen.sh\r
+$ ./configure --with-jack\r
+$ make\r
+$ sudo make install\r
+$ sudo ln -s /usr/local/lib/librtaudio.so.6 /lib64/\r
+\r
+Then to install jacktrip:\r
+\r
+$ git clone https://github.com/jacktrip/jacktrip.git\r
+$ cd jacktrip/src\r
+$ ./build\r
+$ sudo make install\r
\r
\r
---\r
You need to have installed the libraries in your system:\r
Qt 5.3 or higher\r
jack-audio-connection-kit-devel\r
+rtaudio\r
\r
-If you are using yum (in Fedora 8 or later) you can just install them (as root) with:\r
- yum install jack-audio-connection-kit-devel
+If you are using yum you can just install them (as root) with:\r
+ yum install jack-audio-connection-kit-devel\r
and install qt from the qt site.\r
\r
If you want to build on MacOS X, you need JackOSX\r
http://www.jackosx.com/\r
-and Qt 5.3 or higher. \r
-
+and Qt 5.3 or higher.\r
+\r
It is also possible to build without jack, see below.\r
\r
+\r
---\r
Build:\r
\r
./build nojack\r
\r
If the previous script doesn't work on a different Linux flavor, try building\r
-the Makfiles yourself. You'd need qmake (e.g., on Fedora, this command is called\r
-qmake-qt4). Then you can build by:\r
- qmake jacktrip.pro\r
- make release\r
+the Makefiles yourself. You'd need qmake. Then you can build by:\r
+$ qmake jacktrip.pro\r
+$ make release\r
\r
Or without Jack support:\r
- qmake -config nojack jacktrip.pro\r
- make release\r
+$ qmake -config nojack jacktrip.pro\r
+$ make release\r
+\r
\r
+If you want to install (using Terminal): on the /src directory type:\r
\r
-If you want to install install (using Terminal): on the /src directory type:\r
+$ sudo cp jacktrip /usr/local/bin/\r
+ (enter your password when prompted)\r
\r
- sudo cp jacktrip /usr/bin/\r
- (enter your password when prompted)\r
+$ sudo chmod 755 /usr/local/bin/jacktrip\r
+ (now you can run jacktrip from any directory using Terminal)\r
\r
- sudo chmod 755 /usr/bin/jacktrip\r
- (now you can run jacktrip from any directory using Terminal)\r
\r
------------------------------\r
-WINDOWS (XP and later) \r
+---\r
+WINDOWS (XP and later)\r
\r
Dependencies:\r
\r
The installer also adds the executable Jacktrip.exe in the System32 directory, so that it can be executed\r
from a command prompt from any working directory.\r
\r
-This executable (jacktrip.exe) can be found in the bin directory, along with the Dynamic \r
+This executable (jacktrip.exe) can be found in the bin directory, along with the Dynamic\r
Link Libraries (DLLs) it links to.\r
\r
\r
Building:\r
\r
-The easiest way to build is to download the free Qt Creator IDE from http://qt.nokia.com/products/ \r
+The easiest way to build is to download the free Qt Creator IDE from https://www.qt.io/download since the jacktrip buildscript is written in qmake.\r
+\r
+Use `git clone https://github.com/jacktrip/jacktrip.git` to download a fresh copy of the repo.\r
+Open the `src/jacktrip.pro` and configure the project.\r
+\r
+Make sure to select the MinGW compiler (for example the one shipped with QtCreator).\r
+Building with Clang or Microsoft Visual Studio Compilers is currently not supported!\r
\r
-Make a copy of the src and externals directories into a new directory of your choice, open the jacktrip.pro \r
-file in src, and build the project.\r
\r
-You can alternatively download the MinGW (Minimalist GNU for Windows), a Windows port of the GNU\r
-compiler from http://www.mingw.org/ and use mingw32-make from a command terminal to build the makefile.\r
+Download Jack2 from https://jackaudio.org/downloads/\r
+Make sure to install Jack into `C:\Program Files (x86)\Jack` (as this is the path where the jacktrip build script will look for it).\r
\r
-Building is not supported with Microsoft Visual Studio Compilers.\r
+Hit build in QtCreator.\r
\r
-Note: compiling with modifications in the .pro file (like adding a new source or header file) requires \r
+Note: compiling with modifications in the .pro file (like adding a new source or header file) requires\r
qmake which is only available in the Qt Creator package.\r
\r
---\r
\r
-BUILD WARNING \r
+BUILD WARNING\r
\r
Always keep the /src and /externals directories under the same directory.\r
\r
---\r
Post Configuration\r
-Detailed instructions at \r
+Detailed instructions at\r
http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/\r
\r
\r
---\r
Using JackTrip\r
-Detailed instructions at \r
+Detailed instructions at\r
http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/\r
--- /dev/null
+/*
+ JMess: A simple utility so save your jack-audio mess.
+
+ Copyright (C) 2007-2010 Juan-Pablo Caceres.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+/*
+ * JMess.cpp
+ */
+
+#include "JMess.h"
+#include "JackTrip.h"
+#include "jacktrip_globals.h"
+#include <QDebug>
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Constructs a JMess object that has a jack client.
+ *
+ */
+//-------------------------------------------------------------------------------
+JMess::JMess()
+{
+ //Open a client connection to the JACK server. Starting a
+ //new server only to list its ports seems pointless, so we
+ //specify JackNoStartServer.
+ mClient = jack_client_open ("lsp", JackNoStartServer, &mStatus);
+ if (mClient == NULL) {
+ if (mStatus & JackServerFailed) {
+ cerr << "JACK server not running" << endl;
+ } else {
+ cerr << "jack_client_open() failed, "
+ << "status = 0x%2.0x\n" << mStatus << endl;
+ }
+ exit(1);
+ }
+}
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Distructor closes the jmess jack audio client.
+ *
+ */
+//-------------------------------------------------------------------------------
+JMess::~JMess()
+{
+ if (jack_client_close(mClient))
+ cerr << "ERROR: Could not close the hidden jmess jack client." << endl;
+}
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Write an XML file with the name specified at xmlOutFile.
+ *
+ */
+//-------------------------------------------------------------------------------
+void JMess::writeOutput(QString xmlOutFile)
+{
+ // QDomDocument jmess_xml; QDomElement root;
+ // QDomElement connection; QDomElement output;
+ // QDomElement input; QDomText output_name;
+ // QDomText input_name;
+
+ // QVector<QString> OutputInput(2);
+
+ // this->setConnectedPorts();
+
+ // root = jmess_xml.createElement("jmess");
+ // for (QVector<QVector<QString> >::iterator it = mConnectedPorts.begin();
+ // it != mConnectedPorts.end(); ++it) {
+ // OutputInput = *it;
+ // //cout << "Output ===> " <<qPrintable(OutputInput[0]) << endl;
+ // //cout << "Input ===> " <<qPrintable(OutputInput[1]) << endl;
+
+ // //Initialize XML elements
+ // connection = jmess_xml.createElement("connection");
+ // output = jmess_xml.createElement("output");
+ // input = jmess_xml.createElement("input");
+ // output_name = jmess_xml.createTextNode(OutputInput[0]);
+ // input_name = jmess_xml.createTextNode(OutputInput[1]);
+
+ // jmess_xml.appendChild(root); root.appendChild(connection);
+ // connection.appendChild(output); connection.appendChild(input);
+ // output.appendChild(output_name); input.appendChild(input_name);
+ // }
+
+ // //Write output file
+ // QFile file(xmlOutFile);
+ // string answer = "";
+ // //Check for existing file first, and confirm before overwriting
+ // if (file.exists()) {
+ // while ((answer != "yes") && (answer != "no")) {
+ // cout << "WARNING: The File " <<qPrintable(xmlOutFile)
+ // << " exists. Do you want to overwrite it? (yes/no): ";
+ // cin >> answer;
+ // }
+ // }
+ // else {
+ // answer = "yes";
+ // }
+
+ // if (answer == "yes") {
+ // if (!file.open(QIODevice::WriteOnly)) {
+ // cerr << "Cannot open file for writing: "
+ // << qPrintable(file.errorString()) << endl;
+ // exit(1);
+ // }
+
+ // QTextStream out(&file);
+ // jmess_xml.save(out, Indent);
+ // cout << qPrintable(xmlOutFile) << " written." << endl;
+ // }
+}
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Set list of ouput ports that have connections.
+ *
+ */
+//-------------------------------------------------------------------------------
+void JMess::setConnectedPorts()
+{
+ mConnectedPorts.clear();
+
+ const char **ports, **connections; //vector of ports and connections
+ QVector<QString> OutputInput(2); //helper variable
+
+ //Get active output ports.
+ ports = jack_get_ports (mClient, NULL, NULL, JackPortIsOutput);
+
+ for (unsigned int out_i = 0; ports[out_i]; ++out_i) {
+ if ((connections = jack_port_get_all_connections
+ (mClient, jack_port_by_name(mClient, ports[out_i]))) != 0) {
+ for (unsigned int in_i = 0; connections[in_i]; ++in_i) {
+ OutputInput[0] = ports[out_i];
+ // cout << "Output ===> " <<qPrintable(OutputInput[0]) << endl;
+ OutputInput[1] = connections[in_i];
+ // cout << "Input ===> " << qPrintable(OutputInput[1]) << endl;
+ mConnectedPorts.append(OutputInput);
+ }
+ }
+ }
+
+ free(ports);
+}
+//*******************************************************************************
+void JMess::connectSpawnedPorts(int nChans, int hubPatch)
+// called from UdpMasterListener::connectMesh
+{
+ QString IPS[gMAX_WAIRS];
+ int ctr = 0;
+
+ const char **ports, **connections; //vector of ports and connections
+ QVector<QString> OutputInput(2); //helper variable
+
+ //Get active output ports.
+ ports = jack_get_ports (mClient, NULL, NULL, JackPortIsOutput);
+
+ for (unsigned int out_i = 0; ports[out_i]; ++out_i) {
+ // qDebug() << QString(ports[out_i]);
+ bool systemPort = QString(ports[out_i]).contains(QString("system"));
+
+ QString str = QString(ports[out_i]);
+ // for example "171.64.197.121:receive_1"
+ QString s = str.section(':', 0, 0);
+ // qDebug() << s << systemPort;
+ // for example "171.64.197.121"
+
+ bool newOne = !systemPort;
+ for (int i = 0; i<ctr; i++) if (newOne && (IPS[i]==s)) newOne = false;
+ if (newOne)
+ {
+ IPS[ctr] = s;
+ ctr++;
+ // qDebug() << ports[out_i] << systemPort << s;
+ }
+ }
+ for (int i = 0; i<ctr; i++) qDebug() << IPS[i];
+ disconnectAll();
+
+ int k = 0;
+ int jLimit = 1;
+
+ // FULLMIX is the union of CLIENTFOFI, CLIENTECHO
+
+ // implements CLIENTFOFI, CLIENTECHO -- also FULLMIX part which is CLIENTECHO
+ for (int i = 0; i<ctr; i++) {
+ if (hubPatch == JackTrip::CLIENTFOFI) jLimit = (ctr-1);
+ for (int j = 0; j<jLimit; j++) {
+ if ((hubPatch == JackTrip::CLIENTECHO)||(hubPatch == JackTrip::FULLMIX)) k = i;
+ else if (hubPatch == JackTrip::CLIENTFOFI) k = (j+(i+1))%ctr;
+ for (int l = 1; l<=nChans; l++) { // chans are 1-based
+ qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
+ <<"with " << IPS[k]+":send_"+QString::number(l);
+
+ QString left = IPS[i] +
+ ":receive_" + QString::number(l);
+ QString right = IPS[k] +
+ ":send_" + QString::number(l);
+
+ if (0 !=
+ jack_connect(mClient, left.toStdString().c_str(), right.toStdString().c_str())) {
+ qDebug() << "WARNING: port: " << left
+ << "and port: " << right
+ << " could not be connected.";
+ }
+ }
+ }
+ }
+
+ // do it again to implement the FULLMIX part which is CLIENTFOFI
+ if (hubPatch == JackTrip::FULLMIX) {
+ jLimit = (ctr-1); // same as CLIENTFOFI
+ /*************/
+ // todo: the next block should be in a method, it's a repeat of the above
+ for (int i = 0; i<ctr; i++) {
+ for (int j = 0; j<jLimit; j++) {
+ k = (j+(i+1))%ctr;
+ for (int l = 1; l<=nChans; l++) { // chans are 1-based
+ qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
+ <<"with " << IPS[k]+":send_"+QString::number(l);
+
+ QString left = IPS[i] +
+ ":receive_" + QString::number(l);
+ QString right = IPS[k] +
+ ":send_" + QString::number(l);
+
+ if (0 !=
+ jack_connect(mClient, left.toStdString().c_str(), right.toStdString().c_str())) {
+ qDebug() << "WARNING: port: " << left
+ << "and port: " << right
+ << " could not be connected.";
+ }
+ }
+ }
+ }
+ }
+
+ free(ports);
+}
+
+//*******************************************************************************
+// connectTUB is called when in hubpatch mode 4 = RESERVEDMATRIX
+// TU Berlin Raspberry Pi ensemble, Winter 2019
+// this gets run on the ensemble's hub server with
+// ./jacktrip -S -p3
+// it connects a set of client jacktrips with known hardwired IP addresses
+// to a known hardwired audio process with known hardwired audio port names
+// when clients connect / disconnect dynamically this just runs through the
+// audio connection sequence bruteforce at every new connection change
+// those that are preexisting won't change
+// a new one will connect accordingly and
+// those that fail because they don't exist will fail, no worries
+
+// setting the connections tested with jacktrip_globals.h
+// const QString gDOMAIN_TRIPLE = QString("130.149.23"); // for TUB multiclient hub
+// const int gMIN_TUB = 215; // lowest client address
+// const int gMAX_TUB = 215; // highest client address
+
+///////////////////////////////
+// test NUC as server
+//#define HARDWIRED_AUDIO_PROCESS_ON_SERVER "par20straightWire"
+//#define ENUMERATE ""
+//#define HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN ":in_"
+//#define HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT ":out_"
+
+///////////////////////////////
+// test Riviera as server
+// for deployment change jacktrip_globals.h to
+// const QString gDOMAIN_TRIPLE = QString("192.168.0"); // for TUB multiclient hub
+// const int gMIN_TUB = 11; // lowest client address
+// const int gMAX_TUB = 20; // highest client address
+// and give the proper audio process and connection names
+
+#define HARDWIRED_AUDIO_PROCESS_ON_SERVER "SuperCollider"
+#define HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN ":in_"
+#define HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT ":out_"
+// On server side it is SC jack-clients with indivisual names:
+// POE_0...POE_16
+// and each has (at this moment) one port in/out:
+// receive_1
+// send_1
+// I think it should be extended to 4 in/out ports per client.
+
+// this is brute force, does not look at individual clients, just patches the whole ensemble
+// each time
+void JMess::connectTUB(int /*nChans*/)
+// called from UdpMasterListener::connectPatch
+{
+ for (int i = 0; i<=gMAX_TUB-gMIN_TUB; i++) // last IP decimal octet
+ for (int l = 1; l<=1; l++) // mono for now // chans are 1-based, 1...2
+ {
+ // jacktrip to SC
+ QString client = gDOMAIN_TRIPLE + QString(".") + QString::number(gMIN_TUB+i);
+ QString serverAudio = QString(HARDWIRED_AUDIO_PROCESS_ON_SERVER);
+ int tmp = i + l; // only works for mono... completely wrong for 2 or more chans
+ qDebug() << "connect " << client << ":receive_ " << l
+ <<"with " << serverAudio << HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN << tmp;
+
+ QString left = QString(client + ":receive_" + QString::number(l));
+ QString right = QString(serverAudio + HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN +
+ QString::number(tmp));
+
+ if (0 !=
+ jack_connect(mClient, left.toStdString().c_str(),
+ right.toStdString().c_str())) {
+ qDebug() << "WARNING: port: " << left
+ << "and port: " << right
+ << " could not be connected.";
+ }
+
+ // SC to jacktrip
+ tmp += 4; // increase tmp for port offest
+ qDebug() << "connect " << serverAudio << HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT
+ << tmp <<"with " << client << ":send_" << l;
+
+ left = QString(serverAudio + HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT +
+ QString::number(tmp));
+ right = QString(client + ":send_" + QString::number(l));
+
+ if (0 !=
+ jack_connect(mClient, left.toStdString().c_str(),
+ right.toStdString().c_str())) {
+ qDebug() << "WARNING: port: " << left
+ << "and port: " << right
+ << " could not be connected.";
+ }
+
+ }
+}
+
+//-------------------------------------------------------------------------------
+/*! \brief Disconnect all the clients.
+ *
+ */
+//-------------------------------------------------------------------------------
+void JMess::disconnectAll()
+{
+ QVector<QString> OutputInput(2);
+
+ this->setConnectedPorts();
+
+ for (QVector<QVector<QString> >::iterator it = mConnectedPorts.begin();
+ it != mConnectedPorts.end(); ++it) {
+ OutputInput = *it;
+
+ if (jack_disconnect(mClient, OutputInput[0].toLatin1(), OutputInput[1].toLatin1())) {
+ cerr << "WARNING: port: " << qPrintable(OutputInput[0])
+ << "and port: " << qPrintable(OutputInput[1])
+ << " could not be disconnected.\n";
+ }
+ }
+
+}
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Parse the XML input file.
+ *
+ * Returns 0 on success, or 1 if the file has an incorrect format or cannot
+ * read the file.
+ */
+//-------------------------------------------------------------------------------
+int JMess::parseXML(QString xmlInFile)
+{
+ // mPortsToConnect.clear();
+ // QString errorStr;
+ // int errorLine;
+ // int errorColumn;
+
+ // QFile file(xmlInFile);
+ // if (!file.open(QIODevice::ReadOnly)) {
+ // cerr << "Cannot open file for reading: "
+ // << qPrintable(file.errorString()) << endl;
+ // return 1;
+ // }
+
+ // QDomDocument doc;
+ // if (!doc.setContent(&file, true, &errorStr, &errorLine,
+ // &errorColumn)) {
+ // cerr << "===================================================\n"
+ // << "Error parsing XML input file:\n"
+ // << "Parse error at line " << errorLine
+ // << ", column " << errorColumn << "\n"
+ // << qPrintable(errorStr) << "\n"
+ // << "===================================================\n";
+ // return 1;
+ // }
+
+ // QDomElement jmess = doc.documentElement();
+ // if (jmess.tagName() != "jmess") {
+ // cerr << "Error: Root tag should be <jmess>: "
+ // << qPrintable(jmess.tagName()) << endl;
+ // return 1;
+ // }
+
+
+ // QVector<QString> OutputInput(2);
+ // //First check for <connection> tag
+ // for(QDomNode n_cntn = jmess.firstChild();
+ // !n_cntn.isNull(); n_cntn = n_cntn.nextSibling()) {
+ // QDomElement cntn = n_cntn.toElement();
+ // if (cntn.tagName() == "connection") {
+ // //Now check for ouput & input tag
+ // for(QDomNode n_sck = cntn.firstChild();
+ // !n_sck.isNull(); n_sck = n_sck.nextSibling()) {
+ // QDomElement sck = n_sck.toElement();
+ // //cout << qPrintable(sck.tagName()) << endl;
+ // //cout << qPrintable(sck.text()) << endl;
+ // if (sck.tagName() == "output") {
+ // OutputInput[0] = sck.text();
+ // }
+ // else if (sck.tagName() == "input") {
+ // OutputInput[1] = sck.text();
+ // }
+ // }
+ // mPortsToConnect.append(OutputInput);
+ // }
+ // }
+
+ return 0;
+
+}
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Connect ports specified in input XML file xmlInFile
+ *
+ */
+//-------------------------------------------------------------------------------
+void JMess::connectPorts(QString xmlInFile)
+{
+ QVector<QString> OutputInput(2);
+
+ // if ( !(this->parseXML(xmlInFile)) ) {
+ // for (QVector<QVector<QString> >::iterator it = mPortsToConnect.begin();
+ // it != mPortsToConnect.end(); ++it) {
+ // OutputInput = *it;
+
+ // if (jack_connect(mClient, OutputInput[0].toLatin1(), OutputInput[1].toLatin1())) {
+ // //Display a warining only if the error is not because the ports are already
+ // //connected, in case the program doesn't display anyting.
+ // if (EEXIST !=
+ // jack_connect(mClient, OutputInput[0].toLatin1(), OutputInput[1].toLatin1())) {
+ // cerr << "WARNING: port: " << qPrintable(OutputInput[0])
+ // << "and port: " << qPrintable(OutputInput[1])
+ // << " could not be connected.\n";
+ // }
+ // }
+ // }
+ // }
+
+}
--- /dev/null
+ Copyright (c) 2020 Juan-Pablo Caceres, Chris Chafe.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# JackTrip is a Linux, Mac OSX, or Windows multi-machine audio system used for network music performance over the Internet.
+It supports any number of channels (as many as the computer/network can handle) of bidirectional, high quality, uncompressed audio signal streaming.
+
+You can use it between any combination of machines e.g., one end using Linux can connect to another using Mac OSX.
+
+# Raspberry Pi
+
+[paper](https://lac.linuxaudio.org/2019/doc/chafe2.pdf) accompanying jacktrip demo at [Linux Audio Conference 2019](https://lac.linuxaudio.org/2019/)
+
+# Other Repos
+jacktrip (1.0) was released on google code. When that shut down, it migrated to github (1.05, 1.1).
+It then moved to the CCRMA's cm-gitlab for version 1.2.
+And as of spring 2020 it moved back to GitHub for the current development.
+
+
+## Links ##
+ * Preliminary [Documentation](http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/) and [API](http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/annotated.html).
+ * Subscribe to the [Mailing List](http://groups.google.com/group/jacktrip-users).
+ * [CCRMA](http://ccrma.stanford.edu/) .
+ * [SoundWIRE group](http://ccrma.stanford.edu/groups/soundwire/).
+ * [Juan-Pablo Caceres](https://ccrma.stanford.edu/~jcaceres/).
+
+## Related Software ##
+[JMess](https://github.com/jcacerec/jmess-jack): A utility to save your audio connections (mess).
<footer>
<p> </p>
<font size="1">
-<p>Documentation generated by Doxygen $doxygenversion on $datetime</p>
+<p>Documentation generated by Doxygen $doxygenversion</p>
<p>
© 2008 by Juan-Pablo Caceres (jcaceres <em>at</em> ccrma <em>dot</em> stanford <em>dot</em> edu) and
Chris Chafe<br />
<a href="http://www.stanford.edu/" title="Stanford home">Stanford University</a>
</font>
<p>
-<a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=236811&type=1" width="88" height="31" border="0" alt="SourceForge.net Logo" /></a>
+<a href="http://sourceforge.net">SourceForge</a>
</p>
</center>
</footer>
//*******************************************************************************
AudioInterface::AudioInterface(JackTrip* jacktrip,
int NumInChans, int NumOutChans,
+ #ifdef WAIR // wair
+ int NumNetRevChans,
+ #endif // endwhere
audioBitResolutionT AudioBitResolution) :
-mJackTrip(jacktrip),
-mNumInChans(NumInChans), mNumOutChans(NumOutChans),
-mAudioBitResolution(AudioBitResolution*8),
-mBitResolutionMode(AudioBitResolution),
-mSampleRate(gDefaultSampleRate), mBufferSizeInSamples(gDefaultBufferSizeInSamples),
-mInputPacket(NULL), mOutputPacket(NULL)
+ mJackTrip(jacktrip),
+ mNumInChans(NumInChans), mNumOutChans(NumOutChans),
+ #ifdef WAIR // WAIR
+ mNumNetRevChans(NumNetRevChans),
+ #endif // endwhere
+ mAudioBitResolution(AudioBitResolution*8),
+ mBitResolutionMode(AudioBitResolution),
+ mSampleRate(gDefaultSampleRate), mBufferSizeInSamples(gDefaultBufferSizeInSamples),
+ mInputPacket(NULL), mOutputPacket(NULL)
{
- // Set pointer to NULL
- for (int i = 0; i < mNumInChans; i++) {
- mInProcessBuffer[i] = NULL;
- }
- for (int i = 0; i < mNumOutChans; i++) {
- mOutProcessBuffer[i] = NULL;
- }
+#ifndef WAIR
+ //cc
+ // Initialize and assign memory for ProcessPlugins Buffers
+ mInProcessBuffer.resize(mNumInChans);
+ mOutProcessBuffer.resize(mNumOutChans);
+ // Set pointer to NULL
+ for (int i = 0; i < mNumInChans; i++) {
+ mInProcessBuffer[i] = NULL;
+ }
+ for (int i = 0; i < mNumOutChans; i++) {
+ mOutProcessBuffer[i] = NULL;
+ }
+#else // WAIR
+ int iCnt = (mNumInChans > mNumNetRevChans) ? mNumInChans : mNumNetRevChans;
+ int oCnt = (mNumOutChans > mNumNetRevChans) ? mNumOutChans : mNumNetRevChans;
+ int aCnt = (mNumNetRevChans) ? mNumInChans : 0;
+ for (int i = 0; i < iCnt; i++) {
+ mInProcessBuffer[i] = NULL;
+ }
+ for (int i = 0; i < oCnt; i++) {
+ mOutProcessBuffer[i] = NULL;
+ }
+ for (int i = 0; i < aCnt; i++) {
+ mAPInBuffer[i] = NULL;
+ }
+#endif // endwhere
}
//*******************************************************************************
AudioInterface::~AudioInterface()
{
- delete[] mInputPacket;
- delete[] mOutputPacket;
- for (int i = 0; i < mNumInChans; i++) {
- delete[] mInProcessBuffer[i];
- }
-
- for (int i = 0; i < mNumOutChans; i++) {
- delete[] mOutProcessBuffer[i];
- }
+ delete[] mInputPacket;
+ delete[] mOutputPacket;
+#ifndef WAIR // WAIR
+ for (int i = 0; i < mNumInChans; i++) {
+ delete[] mInProcessBuffer[i];
+ }
+
+ for (int i = 0; i < mNumOutChans; i++) {
+ delete[] mOutProcessBuffer[i];
+ }
+#else // WAIR
+ int iCnt = (mNumInChans > mNumNetRevChans) ? mNumInChans : mNumNetRevChans;
+ int oCnt = (mNumOutChans > mNumNetRevChans) ? mNumOutChans : mNumNetRevChans;
+ int aCnt = (mNumNetRevChans) ? mNumInChans : 0;
+ for (int i = 0; i < iCnt; i++) {
+ delete[] mInProcessBuffer[i];
+ }
+ for (int i = 0; i < oCnt; i++) {
+ delete[] mOutProcessBuffer[i];
+ }
+ for (int i = 0; i < aCnt; i++) {
+ delete[] mAPInBuffer[i];
+ }
+#endif // endwhere
}
//*******************************************************************************
void AudioInterface::setup()
{
- // Allocate buffer memory to read and write
- mSizeInBytesPerChannel = getSizeInBytesPerChannel();
- int size_input = mSizeInBytesPerChannel * getNumInputChannels();
- int size_output = mSizeInBytesPerChannel * getNumOutputChannels();
- mInputPacket = new int8_t[size_input];
- mOutputPacket = new int8_t[size_output];
-
- // Initialize and asign memory for ProcessPlugins Buffers
- mInProcessBuffer.resize(mNumInChans);
- mOutProcessBuffer.resize(mNumOutChans);
-
- int nframes = getBufferSizeInSamples();
- for (int i = 0; i < mNumInChans; i++) {
- mInProcessBuffer[i] = new sample_t[nframes];
- // set memory to 0
- std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * nframes);
- }
- for (int i = 0; i < mNumOutChans; i++) {
- mOutProcessBuffer[i] = new sample_t[nframes];
- // set memory to 0
- std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * nframes);
- }
+ // Allocate buffer memory to read and write
+ mSizeInBytesPerChannel = getSizeInBytesPerChannel();
+
+ int size_input = mSizeInBytesPerChannel * getNumInputChannels();
+ int size_output = mSizeInBytesPerChannel * getNumOutputChannels();
+#ifdef WAIR // WAIR
+ if(mNumNetRevChans) // else don't change sizes
+ {
+ size_input = mSizeInBytesPerChannel * mNumNetRevChans;
+ size_output = mSizeInBytesPerChannel * mNumNetRevChans;
+ }
+#endif // endwhere
+ mInputPacket = new int8_t[size_input];
+ mOutputPacket = new int8_t[size_output];
+
+ // Initialize and asign memory for ProcessPlugins Buffers
+#ifdef WAIR // WAIR
+ if(mNumNetRevChans)
+ {
+ mInProcessBuffer.resize(mNumNetRevChans);
+ mOutProcessBuffer.resize(mNumNetRevChans);
+ mAPInBuffer.resize(mNumInChans);
+ mNetInBuffer.resize(mNumNetRevChans);
+ } else // don't change sizes
+#endif // endwhere
+ {
+ mInProcessBuffer.resize(mNumInChans);
+ mOutProcessBuffer.resize(mNumOutChans);
+ }
+
+ int nframes = getBufferSizeInSamples();
+
+#ifndef WAIR // WAIR
+ for (int i = 0; i < mNumInChans; i++) {
+ mInProcessBuffer[i] = new sample_t[nframes];
+ // set memory to 0
+ std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * nframes);
+ }
+ for (int i = 0; i < mNumOutChans; i++) {
+ mOutProcessBuffer[i] = new sample_t[nframes];
+ // set memory to 0
+ std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * nframes);
+ }
+#else // WAIR
+ for (int i = 0; i < ((mNumNetRevChans)?mNumNetRevChans:mNumInChans); i++) {
+ mInProcessBuffer[i] = new sample_t[nframes];
+ // set memory to 0
+ std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * nframes);
+ }
+ for (int i = 0; i < ((mNumNetRevChans)?mNumNetRevChans:mNumOutChans); i++) {
+ mOutProcessBuffer[i] = new sample_t[nframes];
+ // set memory to 0
+ std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * nframes);
+ }
+ for (int i = 0; i < ((mNumNetRevChans)?mNumInChans:0); i++) {
+ mAPInBuffer[i] = new sample_t[nframes];
+ // set memory to 0
+ std::memset(mAPInBuffer[i], 0, sizeof(sample_t) * nframes);
+ }
+ for (int i = 0; i < mNumNetRevChans; i++) {
+ mNetInBuffer[i] = new sample_t[nframes];
+ // set memory to 0
+ std::memset(mNetInBuffer[i], 0, sizeof(sample_t) * nframes);
+ }
+#endif // endwhere
+
}
//*******************************************************************************
size_t AudioInterface::getSizeInBytesPerChannel() const
{
- return (getBufferSizeInSamples() * getAudioBitResolution()/8);
+ return (getBufferSizeInSamples() * getAudioBitResolution()/8);
}
QVarLengthArray<sample_t*>& out_buffer,
unsigned int n_frames)
{
- // Allocate the Process Callback
- //-------------------------------------------------------------------
- // 1) First, process incoming packets
- // ----------------------------------
- computeProcessFromNetwork(out_buffer, n_frames);
-
- // 2) Dynamically allocate ProcessPlugin processes
- // -----------------------------------------------
- // The processing will be done in order of allocation
- /// \todo Implement for more than one process plugin, now it just works propertely with one.
- /// do it chaining outputs to inputs in the buffers. May need a tempo buffer
- for (int i = 0; i < mNumInChans; i++) {
- std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * n_frames);
- std::memcpy(mInProcessBuffer[i], out_buffer[i], sizeof(sample_t) * n_frames);
- }
- for (int i = 0; i < mNumOutChans; i++) {
- std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * n_frames);
- }
-
- for (int i = 0; i < mProcessPlugins.size(); i++) {
- mProcessPlugins[i]->compute(n_frames, mInProcessBuffer.data(), mOutProcessBuffer.data());
- }
-
- // 3) Finally, send packets to peer
- // --------------------------------
- computeProcessToNetwork(in_buffer, n_frames);
-
-
- ///************PROTORYPE FOR CELT**************************
- ///********************************************************
- /*
+ // Allocate the Process Callback
+ //-------------------------------------------------------------------
+ // 1) First, process incoming packets
+ // ----------------------------------
+
+#ifdef WAIR // WAIR
+ // qDebug() << "--" << mProcessPlugins.size();
+ bool client = (mProcessPlugins.size() == 2);
+#define COMBDSP 1 // client
+#define APDSP 0 // client
+#define DCBDSP 0 // server
+ for (int i = 0; i < mNumNetRevChans; i++) {
+ std::memset(mNetInBuffer[i], 0, sizeof(sample_t) * n_frames);
+ }
+#endif // endwhere
+
+ computeProcessFromNetwork(out_buffer, n_frames);
+#ifdef WAIR // WAIR
+ // nib16 result now in mNetInBuffer
+#endif // endwhere
+
+ // 2) Dynamically allocate ProcessPlugin processes
+ // -----------------------------------------------
+ // The processing will be done in order of allocation
+ /// \todo Implement for more than one process plugin, now it just works propertely with one.
+ /// do it chaining outputs to inputs in the buffers. May need a tempo buffer
+
+#ifndef WAIR // WAIR
+ for (int i = 0; i < mNumInChans; i++) {
+ std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * n_frames);
+ std::memcpy(mInProcessBuffer[i], out_buffer[i], sizeof(sample_t) * n_frames);
+ }
+ for (int i = 0; i < mNumOutChans; i++) {
+ std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * n_frames);
+ }
+
+ for (int i = 0; i < mProcessPlugins.size(); i++) {
+ mProcessPlugins[i]->compute(n_frames, mInProcessBuffer.data(), mOutProcessBuffer.data());
+ }
+#else // WAIR
+ for (int i = 0; i < ((mNumNetRevChans)?mNumNetRevChans:mNumOutChans); i++) {
+ std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * n_frames);
+ }
+ for (int i = 0; i < ((mNumNetRevChans)?mNumNetRevChans:mNumInChans); i++) {
+ std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * n_frames);
+ if (mNumNetRevChans)
+ {
+ if (client)
+ std::memcpy(mInProcessBuffer[i], mNetInBuffer[i], sizeof(sample_t) * n_frames);
+ else
+ std::memcpy(mOutProcessBuffer[i], mNetInBuffer[i], sizeof(sample_t) * n_frames);
+ }
+ }
+ // nib16 to cib16
+
+ if (mNumNetRevChans && client) mProcessPlugins[COMBDSP]->compute(n_frames,
+ mInProcessBuffer.data(), mOutProcessBuffer.data());
+ // compute cob16
+#endif // endwhere
+
+ // 3) Finally, send packets to peer
+ // --------------------------------
+ computeProcessToNetwork(in_buffer, n_frames);
+
+#ifdef WAIR // WAIR
+ // aib2 + cob16 to nob16
+#endif // endwhere
+
+#ifdef WAIR // WAIR
+ if (mNumNetRevChans) // else not wair, so skip all this
+ {
+ ///////////////////////////////////////////////////////////////////////////////
+#define AP
+#ifndef AP
+ // straight to audio out
+ for (int i = 0; i < mNumOutChans; i++) {
+ std::memset(out_buffer[i], 0, sizeof(sample_t) * n_frames);
+ }
+ for (int i = 0; i < mNumNetRevChans; i++) {
+ sample_t* mix_sample = out_buffer[i%mNumOutChans];
+ sample_t* tmp_sample = mNetInBuffer[i]; //mNetInBuffer
+ for (int j = 0; j < (int)n_frames; j++) {mix_sample[j] += tmp_sample[j];}
+ } // nib6 to aob2
+ ///////////////////////////////////////////////////////////////////////////////
+#else // AP
+ ///////////////////////////////////////////////////////////////////////////////
+ // output through all-pass cascade
+ // AP2 is 2 channel, mixes inputs to mono, then splits to two parallel AP chains
+ // AP8 is 2 channel, two parallel AP chains
+ for (int i = 0; i < mNumInChans; i++) {
+ std::memset(mAPInBuffer[i], 0, sizeof(sample_t) * n_frames);
+ }
+ for (int i = 0; i < mNumNetRevChans; i++) {
+ sample_t* mix_sample = mAPInBuffer[i%mNumOutChans];
+ sample_t* tmp_sample = mNetInBuffer[i];
+ for (int j = 0; j < n_frames; j++) {mix_sample[j] += tmp_sample[j];}
+ } // nib16 to apib2
+ for (int i = 0; i < mNumOutChans; i++) {
+ std::memset(out_buffer[i], 0, sizeof(sample_t) * n_frames);
+ }
+ mProcessPlugins[APDSP]->compute(n_frames, mAPInBuffer.data(), out_buffer.data());
+ // compute ap2 into aob2
+
+ //#define ADD_DIRECT
+#ifdef ADD_DIRECT
+ for (int i = 0; i < mNumInChans; i++) {
+ sample_t* mix_sample = out_buffer[i];
+ sample_t* tmp_sample = in_buffer[i];
+ for (int j = 0; j < n_frames; j++) {mix_sample[j] += tmp_sample[j];}
+ }
+ // add aib2 to aob2
+#endif // ADD_DIRECT
+#endif // AP
+ ///////////////////////////////////////////////////////////////////////////////
+ }
+#endif // endwhere
+
+
+ ///************PROTORYPE FOR CELT**************************
+ ///********************************************************
+ /*
CELTMode* mode;
int* error;
mode = celt_mode_create(48000, 2, 64, error);
*/
- //celt_mode_create(48000, 2, 64, NULL);
- //unsigned char* compressed;
- //CELTEncoder* celtEncoder;
- //celt_encode_float(celtEncoder, mInBuffer, NULL, compressed, );
+ //celt_mode_create(48000, 2, 64, NULL);
+ //unsigned char* compressed;
+ //CELTEncoder* celtEncoder;
+ //celt_encode_float(celtEncoder, mInBuffer, NULL, compressed, );
- ///********************************************************
- ///********************************************************
+ ///********************************************************
+ ///********************************************************
}
void AudioInterface::computeProcessFromNetwork(QVarLengthArray<sample_t*>& out_buffer,
unsigned int n_frames)
{
- /// \todo cast *mInBuffer[i] to the bit resolution
- // Output Process (from NETWORK to JACK)
- // ----------------------------------------------------------------
- // Read Audio buffer from RingBuffer (read from incoming packets)
- mJackTrip->receiveNetworkPacket( mOutputPacket );
-
- // Extract separate channels to send to Jack
- for (int i = 0; i < mNumOutChans; i++) {
- //--------
- // This should be faster for 32 bits
- //std::memcpy(mOutBuffer[i], &mOutputPacket[i*mSizeInBytesPerChannel],
- // mSizeInBytesPerChannel);
- //--------
- sample_t* tmp_sample = out_buffer[i]; //sample buffer for channel i
- for (unsigned int j = 0; j < n_frames; j++) {
- // Change the bit resolution on each sample
- fromBitToSampleConversion(
- &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
- &tmp_sample[j], mBitResolutionMode );
- }
- }
+ /// \todo cast *mInBuffer[i] to the bit resolution
+ // Output Process (from NETWORK to JACK)
+ // ----------------------------------------------------------------
+ // Read Audio buffer from RingBuffer (read from incoming packets)
+ mJackTrip->receiveNetworkPacket( mOutputPacket );
+
+#ifdef WAIR // WAIR
+ if (mNumNetRevChans)
+ // Extract separate channels
+ for (int i = 0; i < mNumNetRevChans; i++) {
+ sample_t* tmp_sample = mNetInBuffer[i]; //sample buffer for channel i
+ for (unsigned int j = 0; j < n_frames; j++) {
+ // Change the bit resolution on each sample
+ fromBitToSampleConversion(
+ &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ &tmp_sample[j], mBitResolutionMode );
+ }
+ }
+ else // not wair
+#endif // endwhere
+
+ // Extract separate channels to send to Jack
+ for (int i = 0; i < mNumOutChans; i++) {
+ //--------
+ // This should be faster for 32 bits
+ //std::memcpy(mOutBuffer[i], &mOutputPacket[i*mSizeInBytesPerChannel],
+ // mSizeInBytesPerChannel);
+ //--------
+ sample_t* tmp_sample = out_buffer[i]; //sample buffer for channel i
+ for (unsigned int j = 0; j < n_frames; j++) {
+ // Change the bit resolution on each sample
+ fromBitToSampleConversion(
+ &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ &tmp_sample[j], mBitResolutionMode );
+ }
+ }
}
void AudioInterface::computeProcessToNetwork(QVarLengthArray<sample_t*>& in_buffer,
unsigned int n_frames)
{
- // Input Process (from JACK to NETWORK)
- // ----------------------------------------------------------------
- // Concatenate all the channels from jack to form packet
- for (int i = 0; i < mNumInChans; i++) {
- //--------
- // This should be faster for 32 bits
- //std::memcpy(&mInputPacket[i*mSizeInBytesPerChannel], mInBuffer[i],
- // mSizeInBytesPerChannel);
- //--------
- sample_t* tmp_sample = in_buffer[i]; //sample buffer for channel i
- sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
- sample_t tmp_result;
- for (unsigned int j = 0; j < n_frames; j++) {
- // Change the bit resolution on each sample
- // Add the input jack buffer to the buffer resulting from the output process
- tmp_result = tmp_sample[j] + tmp_process_sample[j];
- fromSampleToBitConversion(
- &tmp_result,
- &mInputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
- mBitResolutionMode );
- }
- }
- // Send Audio buffer to Network
- mJackTrip->sendNetworkPacket( mInputPacket );
+ // Input Process (from JACK to NETWORK)
+ // ----------------------------------------------------------------
+ // Concatenate all the channels from jack to form packet
+
+#ifdef WAIR // WAIR
+ if (mNumNetRevChans)
+ for (int i = 0; i < mNumNetRevChans; i++) {
+ sample_t* tmp_sample = in_buffer[i%mNumInChans]; //sample buffer for channel i
+ sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
+ sample_t tmp_result;
+ for (unsigned int j = 0; j < n_frames; j++) {
+ // Change the bit resolution on each sample
+ // Add the input jack buffer to the buffer resulting from the output process
+#define INGAIN (0.9999) // 0.9999 because 1.0 can saturate the fixed pt rounding on output
+#define COMBGAIN (1.0)
+ tmp_result = INGAIN*tmp_sample[j] + COMBGAIN*tmp_process_sample[j];
+ fromSampleToBitConversion(
+ &tmp_result,
+ &mInputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ mBitResolutionMode );
+ }
+ }
+ else // not wair
+#endif // endwhere
+
+ for (int i = 0; i < mNumInChans; i++) {
+ //--------
+ // This should be faster for 32 bits
+ //std::memcpy(&mInputPacket[i*mSizeInBytesPerChannel], mInBuffer[i],
+ // mSizeInBytesPerChannel);
+ //--------
+ sample_t* tmp_sample = in_buffer[i]; //sample buffer for channel i
+ sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
+ sample_t tmp_result;
+ for (unsigned int j = 0; j < n_frames; j++) {
+ // Change the bit resolution on each sample
+ // Add the input jack buffer to the buffer resulting from the output process
+ tmp_result = tmp_sample[j] + tmp_process_sample[j];
+ fromSampleToBitConversion(
+ &tmp_result,
+ &mInputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ mBitResolutionMode );
+ }
+ }
+ // Send Audio buffer to Network
+ mJackTrip->sendNetworkPacket( mInputPacket );
}
// This function quantize from 32 bit to a lower bit resolution
// 24 bit is not working yet
void AudioInterface::fromSampleToBitConversion
- (const sample_t* const input,
- int8_t* output,
- const AudioInterface::audioBitResolutionT targetBitResolution)
+(const sample_t* const input,
+ int8_t* output,
+ const AudioInterface::audioBitResolutionT targetBitResolution)
{
- int8_t tmp_8;
- uint8_t tmp_u8; // unsigned to quantize the remainder in 24bits
- int16_t tmp_16;
- sample_t tmp_sample;
- sample_t tmp_sample16;
- sample_t tmp_sample8;
- switch (targetBitResolution)
+ int8_t tmp_8;
+ uint8_t tmp_u8; // unsigned to quantize the remainder in 24bits
+ int16_t tmp_16;
+ sample_t tmp_sample;
+ sample_t tmp_sample16;
+ sample_t tmp_sample8;
+ switch (targetBitResolution)
{
case BIT8 :
- // 8bit integer between -128 to 127
- tmp_sample = floor( (*input) * 128.0 ); // 2^7 = 128.0
- tmp_8 = static_cast<int8_t>(tmp_sample);
- std::memcpy(output, &tmp_8, 1); // 8bits = 1 bytes
- break;
+ // 8bit integer between -128 to 127
+ tmp_sample = floor( (*input) * 128.0 ); // 2^7 = 128.0
+ tmp_8 = static_cast<int8_t>(tmp_sample);
+ std::memcpy(output, &tmp_8, 1); // 8bits = 1 bytes
+ break;
case BIT16 :
- // 16bit integer between -32768 to 32767
- tmp_sample = floor( (*input) * 32768.0 ); // 2^15 = 32768.0
- tmp_16 = static_cast<int16_t>(tmp_sample);
- std::memcpy(output, &tmp_16, 2); // 16bits = 2 bytes
- break;
+ // 16bit integer between -32768 to 32767
+ tmp_sample = floor( (*input) * 32768.0 ); // 2^15 = 32768.0
+ tmp_16 = static_cast<int16_t>(tmp_sample);
+ std::memcpy(output, &tmp_16, 2); // 16bits = 2 bytes
+ break;
case BIT24 :
- // To convert to 24 bits, we first quantize the number to 16bit
- tmp_sample = (*input) * 32768.0; // 2^15 = 32768.0
- tmp_sample16 = floor(tmp_sample);
- tmp_16 = static_cast<int16_t>(tmp_sample16);
-
- // Then we compute the remainder error, and quantize that part into an 8bit number
- // Note that this remainder is always positive, so we use an unsigned integer
- tmp_sample8 = floor ((tmp_sample - tmp_sample16) //this is a positive number, between 0.0-1.0
- * 256.0);
- tmp_u8 = static_cast<uint8_t>(tmp_sample8);
-
- // Finally, we copy the 16bit number in the first 2 bytes,
- // and the 8bit number in the third bite
- std::memcpy(output, &tmp_16, 2); // 16bits = 2 bytes
- std::memcpy(output+2, &tmp_u8, 1); // 8bits = 1 bytes
- break;
+ // To convert to 24 bits, we first quantize the number to 16bit
+ tmp_sample = (*input) * 32768.0; // 2^15 = 32768.0
+ tmp_sample16 = floor(tmp_sample);
+ tmp_16 = static_cast<int16_t>(tmp_sample16);
+
+ // Then we compute the remainder error, and quantize that part into an 8bit number
+ // Note that this remainder is always positive, so we use an unsigned integer
+ tmp_sample8 = floor ((tmp_sample - tmp_sample16) //this is a positive number, between 0.0-1.0
+ * 256.0);
+ tmp_u8 = static_cast<uint8_t>(tmp_sample8);
+
+ // Finally, we copy the 16bit number in the first 2 bytes,
+ // and the 8bit number in the third bite
+ std::memcpy(output, &tmp_16, 2); // 16bits = 2 bytes
+ std::memcpy(output+2, &tmp_u8, 1); // 8bits = 1 bytes
+ break;
case BIT32 :
- std::memcpy(output, input, 4); // 32bit = 4 bytes
- break;
+ std::memcpy(output, input, 4); // 32bit = 4 bytes
+ break;
}
}
//*******************************************************************************
void AudioInterface::fromBitToSampleConversion
- (const int8_t* const input,
- sample_t* output,
- const AudioInterface::audioBitResolutionT sourceBitResolution)
+(const int8_t* const input,
+ sample_t* output,
+ const AudioInterface::audioBitResolutionT sourceBitResolution)
{
- int8_t tmp_8;
- uint8_t tmp_u8;
- int16_t tmp_16;
- sample_t tmp_sample;
- sample_t tmp_sample16;
- sample_t tmp_sample8;
- switch (sourceBitResolution)
+ int8_t tmp_8;
+ uint8_t tmp_u8;
+ int16_t tmp_16;
+ sample_t tmp_sample;
+ sample_t tmp_sample16;
+ sample_t tmp_sample8;
+ switch (sourceBitResolution)
{
case BIT8 :
- tmp_8 = *input;
- tmp_sample = static_cast<sample_t>(tmp_8) / 128.0;
- std::memcpy(output, &tmp_sample, 4); // 4 bytes
- break;
+ tmp_8 = *input;
+ tmp_sample = static_cast<sample_t>(tmp_8) / 128.0;
+ std::memcpy(output, &tmp_sample, 4); // 4 bytes
+ break;
case BIT16 :
- tmp_16 = *( reinterpret_cast<const int16_t*>(input) ); // *((int16_t*) input);
- tmp_sample = static_cast<sample_t>(tmp_16) / 32768.0;
- std::memcpy(output, &tmp_sample, 4); // 4 bytes
- break;
+ tmp_16 = *( reinterpret_cast<const int16_t*>(input) ); // *((int16_t*) input);
+ tmp_sample = static_cast<sample_t>(tmp_16) / 32768.0;
+ std::memcpy(output, &tmp_sample, 4); // 4 bytes
+ break;
case BIT24 :
- // We first extract the 16bit and 8bit number from the 3 bytes
- tmp_16 = *( reinterpret_cast<const int16_t*>(input) );
- tmp_u8 = *( reinterpret_cast<const uint8_t*>(input+2) );
-
- // Then we recover the number
- tmp_sample16 = static_cast<sample_t>(tmp_16);
- tmp_sample8 = static_cast<sample_t>(tmp_u8) / 256.0;
- tmp_sample = (tmp_sample16 + tmp_sample8) / 32768.0;
- std::memcpy(output, &tmp_sample, 4); // 4 bytes
- break;
+ // We first extract the 16bit and 8bit number from the 3 bytes
+ tmp_16 = *( reinterpret_cast<const int16_t*>(input) );
+ tmp_u8 = *( reinterpret_cast<const uint8_t*>(input+2) );
+
+ // Then we recover the number
+ tmp_sample16 = static_cast<sample_t>(tmp_16);
+ tmp_sample8 = static_cast<sample_t>(tmp_u8) / 256.0;
+ tmp_sample = (tmp_sample16 + tmp_sample8) / 32768.0;
+ std::memcpy(output, &tmp_sample, 4); // 4 bytes
+ break;
case BIT32 :
- std::memcpy(output, input, 4); // 4 bytes
- break;
+ std::memcpy(output, input, 4); // 4 bytes
+ break;
}
}
//*******************************************************************************
void AudioInterface::appendProcessPlugin(ProcessPlugin* plugin)
{
- /// \todo check that channels in ProcessPlugins are less or same that jack channels
- if ( plugin->getNumInputs() ) {}
- mProcessPlugins.append(plugin);
+ /// \todo check that channels in ProcessPlugins are less or same that jack channels
+ if ( plugin->getNumInputs() ) {}
+ mProcessPlugins.append(plugin);
}
//*******************************************************************************
AudioInterface::samplingRateT AudioInterface::getSampleRateType() const
{
- uint32_t rate = getSampleRate();
-
- if ( rate == 22050 ) {
- return AudioInterface::SR22; }
- else if ( rate == 32000 ) {
- return AudioInterface::SR32; }
- else if ( rate == 44100 ) {
- return AudioInterface::SR44; }
- else if ( rate == 48000 ) {
- return AudioInterface::SR48; }
- else if ( rate == 88200 ) {
- return AudioInterface::SR88; }
- else if ( rate == 96000 ) {
- return AudioInterface::SR96; }
- else if ( rate == 19200 ) {
- return AudioInterface::SR192; }
-
- return AudioInterface::UNDEF;
+ uint32_t rate = getSampleRate();
+
+ if ( rate == 22050 ) {
+ return AudioInterface::SR22; }
+ else if ( rate == 32000 ) {
+ return AudioInterface::SR32; }
+ else if ( rate == 44100 ) {
+ return AudioInterface::SR44; }
+ else if ( rate == 48000 ) {
+ return AudioInterface::SR48; }
+ else if ( rate == 88200 ) {
+ return AudioInterface::SR88; }
+ else if ( rate == 96000 ) {
+ return AudioInterface::SR96; }
+ else if ( rate == 19200 ) {
+ return AudioInterface::SR192; }
+
+ return AudioInterface::UNDEF;
}
//*******************************************************************************
int AudioInterface::getSampleRateFromType(samplingRateT rate_type)
{
- int sample_rate = 0;
- switch (rate_type)
+ int sample_rate = 0;
+ switch (rate_type)
{
case SR22 :
- sample_rate = 22050;
- return sample_rate;
- break;
+ sample_rate = 22050;
+ return sample_rate;
+ break;
case SR32 :
- sample_rate = 32000;
- return sample_rate;
- break;
+ sample_rate = 32000;
+ return sample_rate;
+ break;
case SR44 :
- sample_rate = 44100;
- return sample_rate;
- break;
+ sample_rate = 44100;
+ return sample_rate;
+ break;
case SR48 :
- sample_rate = 48000;
- return sample_rate;
- break;
+ sample_rate = 48000;
+ return sample_rate;
+ break;
case SR88 :
- sample_rate = 88200;
- return sample_rate;
- break;
+ sample_rate = 88200;
+ return sample_rate;
+ break;
case SR96 :
- sample_rate = 96000;
- return sample_rate;
- break;
+ sample_rate = 96000;
+ return sample_rate;
+ break;
case SR192 :
- sample_rate = 192000;
- return sample_rate;
- break;
+ sample_rate = 192000;
+ return sample_rate;
+ break;
default:
- return sample_rate;
- break;
+ return sample_rate;
+ break;
}
- return sample_rate;
+ return sample_rate;
}
-
-
{
public:
- /// \brief Enum for Audio Resolution in bits
- enum audioBitResolutionT {
- BIT8 = 1, ///< 8 bits
- BIT16 = 2, ///< 16 bits (default)
- BIT24 = 3, ///< 24 bits
- BIT32 = 4 ///< 32 bits
- };
-
- /// \brief Sampling Rates supported by JACK
- enum samplingRateT {
- SR22, ///< 22050 Hz
- SR32, ///< 32000 Hz
- SR44, ///< 44100 Hz
- SR48, ///< 48000 Hz
- SR88, ///< 88200 Hz
- SR96, ///< 96000 Hz
- SR192, ///< 192000 Hz
- UNDEF ///< Undefined
- };
-
- /** \brief The class constructor
+ /// \brief Enum for Audio Resolution in bits
+ enum audioBitResolutionT {
+ BIT8 = 1, ///< 8 bits
+ BIT16 = 2, ///< 16 bits (default)
+ BIT24 = 3, ///< 24 bits
+ BIT32 = 4 ///< 32 bits
+ };
+
+ /// \brief Sampling Rates supported by JACK
+ enum samplingRateT {
+ SR22, ///< 22050 Hz
+ SR32, ///< 32000 Hz
+ SR44, ///< 44100 Hz
+ SR48, ///< 48000 Hz
+ SR88, ///< 88200 Hz
+ SR96, ///< 96000 Hz
+ SR192, ///< 192000 Hz
+ UNDEF ///< Undefined
+ };
+
+ /** \brief The class constructor
* \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
* \param NumInChans Number of Input Channels
* \param NumOutChans Number of Output Channels
* \param AudioBitResolution Audio Sample Resolutions in bits
*/
- AudioInterface(JackTrip* jacktrip,
- int NumInChans, int NumOutChans,
- AudioInterface::audioBitResolutionT AudioBitResolution =
- AudioInterface::BIT16);
- /// \brief The class destructor
- virtual ~AudioInterface();
-
- /** \brief Setup the client. This function should be called just before
+ AudioInterface(JackTrip* jacktrip,
+ int NumInChans, int NumOutChans,
+ #ifdef WAIR // wair
+ int NumNetRevChans,
+ #endif // endwhere
+ AudioInterface::audioBitResolutionT AudioBitResolution =
+ AudioInterface::BIT16);
+ /// \brief The class destructor
+ virtual ~AudioInterface();
+
+ /** \brief Setup the client. This function should be called just before
*
* starting the audio processes, it will setup the audio client with
* the class parameters, like Sampling Rate,
* Packet Size, Bit Resolution, etc... Sub-classes should also call the parent
* method to ensure correct inizialization.
*/
- virtual void setup();
- /// \brief Tell the audio server that we are ready to roll. The
- /// process-callback will start running. This runs on its own thread.
- /// \return 0 on success, otherwise a non-zero error code
- virtual int startProcess() const = 0;
- /// \brief Stops the process-callback thread
- /// \return 0 on success, otherwise a non-zero error code
- virtual int stopProcess() const = 0;
- /** \brief Process callback. Subclass should call this callback after obtaining the
+ virtual void setup();
+ /// \brief Tell the audio server that we are ready to roll. The
+ /// process-callback will start running. This runs on its own thread.
+ /// \return 0 on success, otherwise a non-zero error code
+ virtual int startProcess() const = 0;
+ /// \brief Stops the process-callback thread
+ /// \return 0 on success, otherwise a non-zero error code
+ virtual int stopProcess() const = 0;
+ /** \brief Process callback. Subclass should call this callback after obtaining the
in_buffer and out_buffer pointers.
* \param in_buffer Array of input audio samplers for each channel. The user
* is reponsible to check that each channel has n_frames samplers
* \param in_buffer Array of output audio samplers for each channel. The user
* is reponsible to check that each channel has n_frames samplers
*/
- virtual void callback(QVarLengthArray<sample_t*>& in_buffer,
- QVarLengthArray<sample_t*>& out_buffer,
- unsigned int n_frames);
- /** \brief Append a ProcessPlugin. The order of processing is determined by
+ virtual void callback(QVarLengthArray<sample_t*>& in_buffer,
+ QVarLengthArray<sample_t*>& out_buffer,
+ unsigned int n_frames);
+ /** \brief Append a ProcessPlugin. The order of processing is determined by
* the order by which appending is done.
* \param plugin a ProcesPlugin smart pointer. Create the object instance
* using something like:\n
* <tt>std::tr1::shared_ptr<ProcessPluginName> loopback(new ProcessPluginName);</tt>
*/
- virtual void appendProcessPlugin(ProcessPlugin* plugin);
- virtual void connectDefaultPorts() = 0;
- /** \brief Convert a 32bit number (sample_t) into one of the bit resolution
+ virtual void appendProcessPlugin(ProcessPlugin* plugin);
+ virtual void connectDefaultPorts() = 0;
+ /** \brief Convert a 32bit number (sample_t) into one of the bit resolution
* supported (audioBitResolutionT).
*
* The result is stored in an int_8 array of the
* appropriate size to hold the value. The caller is responsible to allocate
* enough space to store the result.
*/
- static void fromSampleToBitConversion(const sample_t* const input,
- int8_t* output,
- const AudioInterface::audioBitResolutionT targetBitResolution);
- /** \brief Convert a audioBitResolutionT bit resolution number into a
+ static void fromSampleToBitConversion(const sample_t* const input,
+ int8_t* output,
+ const AudioInterface::audioBitResolutionT targetBitResolution);
+ /** \brief Convert a audioBitResolutionT bit resolution number into a
* 32bit number (sample_t)
*
* The result is stored in an sample_t array of the
* appropriate size to hold the value. The caller is responsible to allocate
* enough space to store the result.
*/
- static void fromBitToSampleConversion(const int8_t* const input,
- sample_t* output,
- const AudioInterface::audioBitResolutionT sourceBitResolution);
-
- //--------------SETTERS---------------------------------------------
- virtual void setNumInputChannels(int nchannels)
- { mNumInChans = nchannels; }
- virtual void setNumOutputChannels(int nchannels)
- { mNumOutChans = nchannels; }
- virtual void setSampleRate(uint32_t sample_rate)
- { mSampleRate = sample_rate; }
- virtual void setBufferSizeInSamples(uint32_t buf_size)
- { mBufferSizeInSamples = buf_size; }
- /// \brief Set Client Name to something different that the default (JackTrip)
- virtual void setClientName(const char* ClientName) = 0;
- //------------------------------------------------------------------
-
- //--------------GETTERS---------------------------------------------
- /// \brief Get Number of Input Channels
- virtual int getNumInputChannels() const { return mNumInChans; }
- /// \brief Get Number of Output Channels
- virtual int getNumOutputChannels() const { return mNumOutChans; }
- virtual uint32_t getBufferSizeInSamples() const
- { return mBufferSizeInSamples; }
- virtual size_t getSizeInBytesPerChannel() const;
- /// \brief Get the Jack Server Sampling Rate, in samples/second
- virtual uint32_t getSampleRate() const
- { return mSampleRate; }
- /// \brief Get the Jack Server Sampling Rate Enum Type samplingRateT
- /// \return AudioInterface::samplingRateT enum type
- virtual samplingRateT getSampleRateType() const;
- /** \brief Get the Audio Bit Resolution, in bits
+ static void fromBitToSampleConversion(const int8_t* const input,
+ sample_t* output,
+ const AudioInterface::audioBitResolutionT sourceBitResolution);
+
+ //--------------SETTERS---------------------------------------------
+ virtual void setNumInputChannels(int nchannels)
+ { mNumInChans = nchannels; }
+ virtual void setNumOutputChannels(int nchannels)
+ { mNumOutChans = nchannels; }
+ virtual void setSampleRate(uint32_t sample_rate)
+ { mSampleRate = sample_rate; }
+ virtual void setDeviceID(uint32_t device_id)
+ { mDeviceID = device_id; }
+ virtual void setBufferSizeInSamples(uint32_t buf_size)
+ { mBufferSizeInSamples = buf_size; }
+ /// \brief Set Client Name to something different that the default (JackTrip)
+ virtual void setClientName(const char* ClientName) = 0;
+ //------------------------------------------------------------------
+
+ //--------------GETTERS---------------------------------------------
+ /// \brief Get Number of Input Channels
+ virtual int getNumInputChannels() const { return mNumInChans; }
+ /// \brief Get Number of Output Channels
+ virtual int getNumOutputChannels() const { return mNumOutChans; }
+ virtual uint32_t getBufferSizeInSamples() const
+ { return mBufferSizeInSamples; }
+ virtual uint32_t getDeviceID() const
+ { return mDeviceID; }
+ virtual size_t getSizeInBytesPerChannel() const;
+ /// \brief Get the Jack Server Sampling Rate, in samples/second
+ virtual uint32_t getSampleRate() const
+ { return mSampleRate; }
+ /// \brief Get the Jack Server Sampling Rate Enum Type samplingRateT
+ /// \return AudioInterface::samplingRateT enum type
+ virtual samplingRateT getSampleRateType() const;
+ /** \brief Get the Audio Bit Resolution, in bits
*
* This is one of the audioBitResolutionT set in construction
*/
- virtual int getAudioBitResolution() const { return mAudioBitResolution; }
- /** \brief Helper function to get the sample rate (in Hz) for a
+ virtual int getAudioBitResolution() const { return mAudioBitResolution; }
+ /** \brief Helper function to get the sample rate (in Hz) for a
* JackAudioInterface::samplingRateT
* \param rate_type JackAudioInterface::samplingRateT enum type
* \return Sample Rate in Hz
*/
- static int getSampleRateFromType(samplingRateT rate_type);
- //------------------------------------------------------------------
+ static int getSampleRateFromType(samplingRateT rate_type);
+ //------------------------------------------------------------------
private:
- /// \brief Compute the process to receive packets
- void computeProcessFromNetwork(QVarLengthArray<sample_t*>& out_buffer,
+ /// \brief Compute the process to receive packets
+ void computeProcessFromNetwork(QVarLengthArray<sample_t*>& out_buffer,
+ unsigned int n_frames);
+ /// \brief Compute the process to send packets
+ void computeProcessToNetwork(QVarLengthArray<sample_t*>& in_buffer,
unsigned int n_frames);
- /// \brief Compute the process to send packets
- void computeProcessToNetwork(QVarLengthArray<sample_t*>& in_buffer,
- unsigned int n_frames);
-
- JackTrip* mJackTrip; ///< JackTrip Mediator Class pointer
- int mNumInChans;///< Number of Input Channels
- int mNumOutChans; ///< Number of Output Channels
- int mAudioBitResolution; ///< Bit resolution in audio samples
- AudioInterface::audioBitResolutionT mBitResolutionMode; ///< Bit resolution (audioBitResolutionT) mode
- uint32_t mSampleRate; ///< Sampling Rate
- uint32_t mBufferSizeInSamples; ///< Buffer size in samples
- size_t mSizeInBytesPerChannel; ///< Size in bytes per audio channel
- QVector<ProcessPlugin*> mProcessPlugins; ///< Vector of ProcesPlugin<EM>s</EM>
- QVarLengthArray<sample_t*> mInProcessBuffer;///< Vector of Input buffers/channel for ProcessPlugin
- QVarLengthArray<sample_t*> mOutProcessBuffer;///< Vector of Output buffers/channel for ProcessPlugin
- int8_t* mInputPacket; ///< Packet containing all the channels to read from the RingBuffer
- int8_t* mOutputPacket; ///< Packet containing all the channels to send to the RingBuffer
+
+ JackTrip* mJackTrip; ///< JackTrip Mediator Class pointer
+ int mNumInChans;///< Number of Input Channels
+ int mNumOutChans; ///< Number of Output Channels
+#ifdef WAIR // wair
+ int mNumNetRevChans; ///< Number of Network Audio Channels (net comb filters)
+ QVarLengthArray<sample_t*> mNetInBuffer; ///< Vector of Input buffers/channel read from net
+ QVarLengthArray<sample_t*> mAPInBuffer; ///< Vector of Input buffers/channel for AllPass input
+#endif // endwhere
+ int mAudioBitResolution; ///< Bit resolution in audio samples
+ AudioInterface::audioBitResolutionT mBitResolutionMode; ///< Bit resolution (audioBitResolutionT) mode
+ uint32_t mSampleRate; ///< Sampling Rate
+ uint32_t mDeviceID; ///< RTAudio DeviceID
+ uint32_t mBufferSizeInSamples; ///< Buffer size in samples
+ size_t mSizeInBytesPerChannel; ///< Size in bytes per audio channel
+ QVector<ProcessPlugin*> mProcessPlugins; ///< Vector of ProcesPlugin<EM>s</EM>
+ QVarLengthArray<sample_t*> mInProcessBuffer;///< Vector of Input buffers/channel for ProcessPlugin
+ QVarLengthArray<sample_t*> mOutProcessBuffer;///< Vector of Output buffers/channel for ProcessPlugin
+ int8_t* mInputPacket; ///< Packet containing all the channels to read from the RingBuffer
+ int8_t* mOutputPacket; ///< Packet containing all the channels to send to the RingBuffer
};
#endif // __AUDIOINTERFACE_H__
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//*******************************************************************************
DataProtocol::DataProtocol(JackTrip* jacktrip,
- const runModeT runmode,
- int /*bind_port*/, int /*peer_port*/) :
- mStopped(false), mHasPacketsToReceive(false), mRunMode(runmode), mJackTrip(jacktrip)
+ const runModeT runmode,
+ int /*bind_port*/, int /*peer_port*/) :
+ mStopped(false), mHasPacketsToReceive(false), mRunMode(runmode), mJackTrip(jacktrip)
{}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#define __DATAPROTOCOL_H__
#ifdef __WIN_32__
-#include <winsock.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
#endif
#ifndef __WIN_32__
/** \brief Base class that defines the transmission protocol.
- *
+ *
* This base class defines most of the common method to setup and connect
* sockets using the individual protocols (UDP, TCP, SCTP, etc).
*
*/
class DataProtocol : public QThread
{
- Q_OBJECT;
+ Q_OBJECT;
public:
- //----------ENUMS------------------------------------------
- /// \brief Enum to define packet header types
- enum packetHeaderTypeT {
- DEFAULT, ///< Default application header
- JAMLINK, ///< Header to use with Jamlinks
- EMPTY ///< Empty Header
- };
+ //----------ENUMS------------------------------------------
+ /// \brief Enum to define packet header types
+ enum packetHeaderTypeT {
+ DEFAULT, ///< Default application header
+ JAMLINK, ///< Header to use with Jamlinks
+ EMPTY ///< Empty Header
+ };
- /// \brief Enum to define class modes, SENDER or RECEIVER
- enum runModeT {
- SENDER, ///< Set class as a Sender (send packets)
- RECEIVER ///< Set class as a Receiver (receives packets)
- };
- //---------------------------------------------------------
+ /// \brief Enum to define class modes, SENDER or RECEIVER
+ enum runModeT {
+ SENDER, ///< Set class as a Sender (send packets)
+ RECEIVER ///< Set class as a Receiver (receives packets)
+ };
+ //---------------------------------------------------------
- /** \brief The class constructor
+ /** \brief The class constructor
* \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
* \param runmode Sets the run mode, use either DataProtocol::SENDER or
* DataProtocol::RECEIVER
* \param bind_port Port number to bind for this socket (this is the receive or send port depending on the runmode)
* \param peer_port Peer port number (this is the receive or send port depending on the runmode)
*/
- DataProtocol(JackTrip* jacktrip,
- const runModeT runmode,
- int bind_port, int peer_port);
-
- /// \brief The class destructor
- virtual ~DataProtocol();
-
- /** \brief Implements the thread loop
+ DataProtocol(JackTrip* jacktrip,
+ const runModeT runmode,
+ int bind_port, int peer_port);
+
+ /// \brief The class destructor
+ virtual ~DataProtocol();
+
+ /** \brief Implements the thread loop
*
* Depending on the runmode, with will run a DataProtocol::SENDER thread or
* DataProtocol::RECEIVER thread
*/
- virtual void run() = 0;
+ virtual void run() = 0;
- /// \brief Stops the execution of the Thread
- virtual void stop() {
- QMutexLocker lock(&mMutex);
- mStopped = true;
- }
+ /// \brief Stops the execution of the Thread
+ virtual void stop() {
+ QMutexLocker lock(&mMutex);
+ mStopped = true;
+ }
- /** \brief Sets the size of the audio part of the packets
+ /** \brief Sets the size of the audio part of the packets
* \param size_bytes Size in bytes
*/
- void setAudioPacketSize(const size_t size_bytes){ mAudioPacketSize = size_bytes; }
+ void setAudioPacketSize(const size_t size_bytes){ mAudioPacketSize = size_bytes; }
- /** \brief Get the size of the audio part of the packets
+ /** \brief Get the size of the audio part of the packets
* \return size_bytes Size in bytes
*/
- size_t getAudioPacketSizeInBites() { return(mAudioPacketSize); }
+ size_t getAudioPacketSizeInBites() { return(mAudioPacketSize); }
- /** \brief Set the peer address
+ /** \brief Set the peer address
* \param peerHostOrIP IPv4 number or host name
* \todo implement here instead of in the subclass UDP
*/
- virtual void setPeerAddress(const char* peerHostOrIP) = 0;
+ virtual void setPeerAddress(const char* peerHostOrIP) = 0;
- /** \brief Set the peer incomming (receiving) port number
+ /** \brief Set the peer incomming (receiving) port number
* \param port Port number
* \todo implement here instead of in the subclass UDP
*/
- virtual void setPeerPort(int port) = 0;
+ virtual void setPeerPort(int port) = 0;
- //virtual void getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
- // uint16_t& port) = 0;
+ //virtual void getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
+ // uint16_t& port) = 0;
+#if defined (__WIN_32__)
+ virtual void setSocket(SOCKET &socket) = 0;
+#else
+ virtual void setSocket(int &socket) = 0;
+#endif
signals:
- void signalError(const char* error_message);
- void signalReceivedConnectionFromPeer();
+ void signalError(const char* error_message);
+ void signalReceivedConnectionFromPeer();
protected:
- /** \brief Get the Run Mode of the object
+ /** \brief Get the Run Mode of the object
* \return SENDER or RECEIVER
*/
- runModeT getRunMode() const { return mRunMode; }
+ runModeT getRunMode() const { return mRunMode; }
- /// Boolean stop the execution of the thread
- volatile bool mStopped;
- /// Boolean to indicate if the RECEIVER is waiting to obtain peer address
- volatile bool mHasPeerAddress;
- /// Boolean that indicates if a packet was received
- volatile bool mHasPacketsToReceive;
- QMutex mMutex;
+ /// Boolean stop the execution of the thread
+ volatile bool mStopped;
+ /// Boolean to indicate if the RECEIVER is waiting to obtain peer address
+ volatile bool mHasPeerAddress;
+ /// Boolean that indicates if a packet was received
+ volatile bool mHasPacketsToReceive;
+ QMutex mMutex;
private:
- int mLocalPort; ///< Local Port number to Bind
- int mPeerPort; ///< Peer Port number to Bind
- const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
-
- struct sockaddr_in mLocalIPv4Addr; ///< Local IPv4 Address struct
- struct sockaddr_in mPeerIPv4Addr; ///< Peer IPv4 Address struct
-
- /// Number of clients running to check for ports already used
- /// \note Unimplemented, try to find another way to check for used ports
- static int sClientsRunning;
-
- size_t mAudioPacketSize; ///< Packet audio part size
-
-
- /// \todo check a better way to access the header from the subclasses
+ int mLocalPort; ///< Local Port number to Bind
+ int mPeerPort; ///< Peer Port number to Bind
+ const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
+
+ struct sockaddr_in mLocalIPv4Addr; ///< Local IPv4 Address struct
+ struct sockaddr_in mPeerIPv4Addr; ///< Peer IPv4 Address struct
+
+ /// Number of clients running to check for ports already used
+ /// \note Unimplemented, try to find another way to check for used ports
+ static int sClientsRunning;
+
+ size_t mAudioPacketSize; ///< Packet audio part size
+
+
+ /// \todo check a better way to access the header from the subclasses
protected:
- //PacketHeader* mHeader; ///< Packet Header
- JackTrip* mJackTrip; ///< JackTrip mediator class
+ //PacketHeader* mHeader; ///< Packet Header
+ JackTrip* mJackTrip; ///< JackTrip mediator class
};
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//*******************************************************************************
DataProtocol::DataProtocol(const runModeT runmode,
- const packetHeaderTypeT headertype) :
- mRunMode(runmode), mStopped(false), mHasPacketsToReceive(false), mHeader(NULL)
+ const packetHeaderTypeT headertype) :
+ mRunMode(runmode), mStopped(false), mHasPacketsToReceive(false), mHeader(NULL)
{
- //--------PROTOTYPE-------------------------
- if ( headertype == DEFAULT ) {
- mHeader = new DefaultHeader;
- }
- else if ( headertype == JAMLINK ) {
- mHeader = new JamLinkHeader;
- }
- //------------------------------------------
+ //--------PROTOTYPE-------------------------
+ if ( headertype == DEFAULT ) {
+ mHeader = new DefaultHeader;
+ }
+ else if ( headertype == JAMLINK ) {
+ mHeader = new JamLinkHeader;
+ }
+ //------------------------------------------
- // Base ports gInputPort_0 and gOutputPort_0defined at globals.h
- if (mRunMode == RECEIVER) {
- mLocalPort = gInputPort_0;
- mPeerPort = gOutputPort_0;
- }
- else if (mRunMode == SENDER) {
- mLocalPort = gOutputPort_0;
- mPeerPort = gInputPort_0;
- }
+ // Base ports gInputPort_0 and gOutputPort_0defined at globals.h
+ if (mRunMode == RECEIVER) {
+ mLocalPort = gInputPort_0;
+ mPeerPort = gOutputPort_0;
+ }
+ else if (mRunMode == SENDER) {
+ mLocalPort = gOutputPort_0;
+ mPeerPort = gInputPort_0;
+ }
- this->setLocalIPv4Address();
+ this->setLocalIPv4Address();
}
//*******************************************************************************
DataProtocol::~DataProtocol()
{
- delete mHeader;
+ delete mHeader;
}
//*******************************************************************************
void DataProtocol::stop()
{
- mStopped = true;
+ mStopped = true;
}
//*******************************************************************************
void DataProtocol::setLocalIPv4Address()
{
- bzero(&mLocalIPv4Addr, sizeof(mLocalIPv4Addr));
- mLocalIPv4Addr.sin_family = AF_INET;//AF_INET: IPv4 Protocol
- mLocalIPv4Addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY: let the kernel decide the active address
- mLocalIPv4Addr.sin_port = htons(mLocalPort);//set local port
- //std::cout << "mLocalPort = " << mLocalPort << std::endl;
+ bzero(&mLocalIPv4Addr, sizeof(mLocalIPv4Addr));
+ mLocalIPv4Addr.sin_family = AF_INET;//AF_INET: IPv4 Protocol
+ mLocalIPv4Addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY: let the kernel decide the active address
+ mLocalIPv4Addr.sin_port = htons(mLocalPort);//set local port
+ //std::cout << "mLocalPort = " << mLocalPort << std::endl;
}
//*******************************************************************************
void DataProtocol::setPeerIPv4Address(const char* peerHostOrIP)
{
- const char* peerAddress; // dotted decimal address to use in the struct below
+ const char* peerAddress; // dotted decimal address to use in the struct below
- /// \todo Improve this to make it work also with local ip numbers, in a LAN,
- /// that don't have an assigned host name
- /*
+ /// \todo Improve this to make it work also with local ip numbers, in a LAN,
+ /// that don't have an assigned host name
+ /*
// Resolve Peer IPv4 with either doted integer IP or hostname
//----------------------------------------------------------
std::cout << "Resolving Peer IPv4 address..." << std::endl;
}
*/
- // temporary implementation to make this work
- /// \todo change this
- peerAddress = peerHostOrIP;
-
- // Set the Peer IPv4 Address struct
- //---------------------------------
- bzero(&mPeerIPv4Addr, sizeof(mPeerIPv4Addr));
- mPeerIPv4Addr.sin_family = AF_INET;//AF_INET: IPv4 Protocol
- mPeerIPv4Addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY: let the kernel decide the active address
- mPeerIPv4Addr.sin_port = htons(mPeerPort);//set Peer port
- //std::cout << "mPeerPort = " << mPeerPort << std::endl;
- int nPeer = inet_pton(AF_INET, peerAddress, &mPeerIPv4Addr.sin_addr);
- if ( nPeer == 1 ) {
- std::cout << "Successful Set Peer Address" << std::endl;
- }
- else if ( nPeer == 0 ) {
- std::cout << "Error: Incorrect presentation format for address" << std::endl;
- std::exit(1);
- }
- else {
- std::cout << "Error: Could not set Peer Address" << std::endl;
- std::exit(1);
- }
+ // temporary implementation to make this work
+ /// \todo change this
+ peerAddress = peerHostOrIP;
+
+ // Set the Peer IPv4 Address struct
+ //---------------------------------
+ bzero(&mPeerIPv4Addr, sizeof(mPeerIPv4Addr));
+ mPeerIPv4Addr.sin_family = AF_INET;//AF_INET: IPv4 Protocol
+ mPeerIPv4Addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY: let the kernel decide the active address
+ mPeerIPv4Addr.sin_port = htons(mPeerPort);//set Peer port
+ //std::cout << "mPeerPort = " << mPeerPort << std::endl;
+ int nPeer = inet_pton(AF_INET, peerAddress, &mPeerIPv4Addr.sin_addr);
+ if ( nPeer == 1 ) {
+ std::cout << "Successful Set Peer Address" << std::endl;
+ }
+ else if ( nPeer == 0 ) {
+ std::cout << "Error: Incorrect presentation format for address" << std::endl;
+ std::exit(1);
+ }
+ else {
+ std::cout << "Error: Could not set Peer Address" << std::endl;
+ std::exit(1);
+ }
}
//*******************************************************************************
void DataProtocol::setRingBuffer(std::tr1::shared_ptr<RingBuffer> RingBuffer)
{
- mRingBuffer = RingBuffer;
+ mRingBuffer = RingBuffer;
}
//*******************************************************************************
void DataProtocol::run()
{
- std::cout << "Running DataProtocol Thread" << std::endl;
- std::cout << gPrintSeparator << std::endl;
- size_t packet_size = getAudioPacketSize();
- int8_t packet[packet_size];
-
- switch ( mRunMode )
+ std::cout << "Running DataProtocol Thread" << std::endl;
+ std::cout << gPrintSeparator << std::endl;
+ size_t packet_size = getAudioPacketSize();
+ int8_t packet[packet_size];
+
+ switch ( mRunMode )
{
- case RECEIVER :
- //-----------------------------------------------------------------------------------
- // Wait for the first packet to be ready and obtain address
- // from that packet
- /// \todo here is the place to read the datagram and check if the settings match
- /// the local ones. Extract this information from the header
- std::cout << "Waiting for Peer..." << std::endl;
- this->receivePacket( (char*) packet, packet_size); // This blocks waiting for the first packet
- std::cout << "Received Connection for Peer!" << std::endl;
-
- while ( !mStopped )
- {
- //std::cout << "RECEIVING PACKETS" << std::endl;
- /// \todo Set a timer to report packats arriving too late
- //std::cout << "RECIEVING THREAD" << std::endl;
-
- this->receivePacket( (char*) packet, packet_size);
- /// \todo Change this to match buffer size
- //std::cout << "PACKET RECIEVED" << std::endl;
- mRingBuffer->insertSlotBlocking(packet);
- //std::cout << buf << std::endl;
- }
- break;
-
-
- case SENDER :
- //-----------------------------------------------------------------------------------
- while ( !mStopped )
- {
- //std::cout << "SENDING PACKETS --------------------------" << std::endl;
- /// \todo This should be blocking, since we don't want to send trash
- mRingBuffer->readSlotBlocking(packet);
- //std::cout << "SENDING PACKETS" << std::endl;
- this->sendPacket( (char*) packet, packet_size);
- //std::cout << "SENDING PACKETS DONE!!!" << std::endl;
- //this->sendPacket( sendtest, 64);
- }
- break;
+ case RECEIVER :
+ //-----------------------------------------------------------------------------------
+ // Wait for the first packet to be ready and obtain address
+ // from that packet
+ /// \todo here is the place to read the datagram and check if the settings match
+ /// the local ones. Extract this information from the header
+ std::cout << "Waiting for Peer..." << std::endl;
+ this->receivePacket( (char*) packet, packet_size); // This blocks waiting for the first packet
+ std::cout << "Received Connection for Peer!" << std::endl;
+
+ while ( !mStopped )
+ {
+ //std::cout << "RECEIVING PACKETS" << std::endl;
+ /// \todo Set a timer to report packats arriving too late
+ //std::cout << "RECIEVING THREAD" << std::endl;
+
+ this->receivePacket( (char*) packet, packet_size);
+ /// \todo Change this to match buffer size
+ //std::cout << "PACKET RECIEVED" << std::endl;
+ mRingBuffer->insertSlotBlocking(packet);
+ //std::cout << buf << std::endl;
+ }
+ break;
+
+
+ case SENDER :
+ //-----------------------------------------------------------------------------------
+ while ( !mStopped )
+ {
+ //std::cout << "SENDING PACKETS --------------------------" << std::endl;
+ /// \todo This should be blocking, since we don't want to send trash
+ mRingBuffer->readSlotBlocking(packet);
+ //std::cout << "SENDING PACKETS" << std::endl;
+ this->sendPacket( (char*) packet, packet_size);
+ //std::cout << "SENDING PACKETS DONE!!!" << std::endl;
+ //this->sendPacket( sendtest, 64);
+ }
+ break;
}
}
void DataProtocol::setAudioPacketSize(size_t size_bytes)
{
- mAudioPacketSize = size_bytes;
+ mAudioPacketSize = size_bytes;
}
size_t DataProtocol::getAudioPacketSize()
{
- return(mAudioPacketSize);
+ return(mAudioPacketSize);
}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
/** \brief Base class that defines the transmission protocol.
- *
+ *
* This base class defines most of the common method to setup and connect
* sockets using the individual protocols (UDP, TCP, SCTP, etc).
*
{
public:
- /// \brief Enum to define packet header types
- enum packetHeaderTypeT {
- DEFAULT, ///< Default application header
- JAMLINK ///< Header to use with Jamlinks
- };
+ /// \brief Enum to define packet header types
+ enum packetHeaderTypeT {
+ DEFAULT, ///< Default application header
+ JAMLINK ///< Header to use with Jamlinks
+ };
+
+ /// \brief Enum to define class modes, SENDER or RECEIVER
+ enum runModeT {
+ SENDER, ///< Set class as a Sender (send packets)
+ RECEIVER ///< Set class as a Receiver (receives packets)
+ };
- /// \brief Enum to define class modes, SENDER or RECEIVER
- enum runModeT {
- SENDER, ///< Set class as a Sender (send packets)
- RECEIVER ///< Set class as a Receiver (receives packets)
- };
-
- /** \brief The class constructor
+ /** \brief The class constructor
* \param runmode Sets the run mode, use either SENDER or RECEIVER
*/
- DataProtocol(const runModeT runmode,
- const packetHeaderTypeT headertype = DEFAULT);
-
- /// \brief The class destructor
- virtual ~DataProtocol();
-
- /** \brief Sets the peer (remote) IPv4 address struct
+ DataProtocol(const runModeT runmode,
+ const packetHeaderTypeT headertype = DEFAULT);
+
+ /// \brief The class destructor
+ virtual ~DataProtocol();
+
+ /** \brief Sets the peer (remote) IPv4 address struct
* \param peerHostOrIP Either an IPv4 dotted integer number or a hostname
*/
- virtual void setPeerIPv4Address(const char* peerHostOrIP);
+ virtual void setPeerIPv4Address(const char* peerHostOrIP);
- /** \brief Receive a packet from the UDPSocket
+ /** \brief Receive a packet from the UDPSocket
*
* This method has to be implemented in the sub-classes
* \param buf Location at which to store the buffer
* \param n size of packet to receive in bytes
* \return number of bytes read, -1 on error
*/
- virtual size_t receivePacket(char* buf, size_t n) = 0;
-
- /** \brief Sends a packet
+ virtual size_t receivePacket(char* buf, size_t n) = 0;
+
+ /** \brief Sends a packet
*
* This method has to be implemented in the sub-classes
* \param buff Buffer to send
* \param n size of packet to receive in bytes
* \return number of bytes read, -1 on error
*/
- virtual size_t sendPacket(const char* buff, size_t n) = 0;
+ virtual size_t sendPacket(const char* buff, size_t n) = 0;
- /** \brief Implements the thread loop
+ /** \brief Implements the thread loop
*
* Depending on the runmode, with will run a RECEIVE thread or
* SEND thread
*/
- virtual void run();
+ virtual void run();
- /** \brief Set the pointer to the RingBuffer that'll be use to read
+ /** \brief Set the pointer to the RingBuffer that'll be use to read
* or write
*/
- void setRingBuffer(std::tr1::shared_ptr<RingBuffer> RingBuffer);
+ void setRingBuffer(std::tr1::shared_ptr<RingBuffer> RingBuffer);
- /// \brief Stops the execution of the Thread
- void stop();
+ /// \brief Stops the execution of the Thread
+ void stop();
- /** \brief Sets the size of the audio part of the packets
+ /** \brief Sets the size of the audio part of the packets
* \param size_bytes Size in bytes
*/
- void setAudioPacketSize(size_t size_bytes);
+ void setAudioPacketSize(size_t size_bytes);
- /** \brief Get the size of the audio part of the packets
+ /** \brief Get the size of the audio part of the packets
* \return size_bytes Size in bytes
*/
- size_t getAudioPacketSize();
+ size_t getAudioPacketSize();
- //virtual void getIPAddressFromFirstPacket() = 0;
+ //virtual void getIPAddressFromFirstPacket() = 0;
protected:
- /** \brief Sets the local IPv4 address struct
+ /** \brief Sets the local IPv4 address struct
*
* It uses the default active device.
*/
- virtual void setLocalIPv4Address();
+ virtual void setLocalIPv4Address();
- /** \brief Get the Run Mode of the object
+ /** \brief Get the Run Mode of the object
* \return SENDER or RECEIVER
*/
- runModeT getRunMode() const { return mRunMode; };
+ runModeT getRunMode() const { return mRunMode; };
- /** \brief Returns the Local machine IPv4 socket address stuct
+ /** \brief Returns the Local machine IPv4 socket address stuct
* \return Socket address stuct
*/
- const sockaddr_in& getLocalIPv4AddressStruct() const { return mLocalIPv4Addr; };
-
- /** \brief Returns the Peer IPv4 socket address stuct
+ const sockaddr_in& getLocalIPv4AddressStruct() const { return mLocalIPv4Addr; };
+
+ /** \brief Returns the Peer IPv4 socket address stuct
* \return Socket address stuct
*/
- const sockaddr_in& getPeerIPv4AddressStruct() const { return mPeerIPv4Addr; };
+ const sockaddr_in& getPeerIPv4AddressStruct() const { return mPeerIPv4Addr; };
private:
- int mLocalPort; ///< Local Port number to Bind
- int mPeerPort; ///< Peer Port number to Bind
- const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
+ int mLocalPort; ///< Local Port number to Bind
+ int mPeerPort; ///< Peer Port number to Bind
+ const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
+
+ struct sockaddr_in mLocalIPv4Addr; ///< Local IPv4 Address struct
+ struct sockaddr_in mPeerIPv4Addr; ///< Peer IPv4 Address struct
- struct sockaddr_in mLocalIPv4Addr; ///< Local IPv4 Address struct
- struct sockaddr_in mPeerIPv4Addr; ///< Peer IPv4 Address struct
+ /// Smart Pointer to RingBuffer to read (for SENDER) or write (for RECEIVER)
+ std::tr1::shared_ptr<RingBuffer> mRingBuffer;
- /// Smart Pointer to RingBuffer to read (for SENDER) or write (for RECEIVER)
- std::tr1::shared_ptr<RingBuffer> mRingBuffer;
-
- /// Boolean stop the execution of the thread
- volatile bool mStopped;
- /// Boolean to indicate if the RECEIVER is waiting to obtain peer address
- volatile bool mHasPeerAddress;
- /// Boolean that indicates if a packet was received
- volatile bool mHasPacketsToReceive;
+ /// Boolean stop the execution of the thread
+ volatile bool mStopped;
+ /// Boolean to indicate if the RECEIVER is waiting to obtain peer address
+ volatile bool mHasPeerAddress;
+ /// Boolean that indicates if a packet was received
+ volatile bool mHasPacketsToReceive;
- /// Number of clients running to check for ports already used
- /// \note Unimplemented, try to find another way to check for used ports
- static int sClientsRunning;
+ /// Number of clients running to check for ports already used
+ /// \note Unimplemented, try to find another way to check for used ports
+ static int sClientsRunning;
- size_t mAudioPacketSize; ///< Packet audio part size
+ size_t mAudioPacketSize; ///< Packet audio part size
- PacketHeader* mHeader; ///< Packet Header
+ PacketHeader* mHeader; ///< Packet Header
};
#endif
--- /dev/null
+/*
+ JMess: A simple utility so save your jack-audio mess.
+
+ Copyright (C) 2007-2010 Juan-Pablo Caceres.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+/*
+ * JMess.cpp
+ */
+
+#include "JMess.h"
+#include "JackTrip.h"
+#include "jacktrip_globals.h"
+#include <QDebug>
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Constructs a JMess object that has a jack client.
+ *
+ */
+//-------------------------------------------------------------------------------
+JMess::JMess()
+{
+ //Open a client connection to the JACK server. Starting a
+ //new server only to list its ports seems pointless, so we
+ //specify JackNoStartServer.
+ mClient = jack_client_open ("lsp", JackNoStartServer, &mStatus);
+ if (mClient == NULL) {
+ if (mStatus & JackServerFailed) {
+ cerr << "JACK server not running" << endl;
+ } else {
+ cerr << "jack_client_open() failed, "
+ << "status = 0x%2.0x\n" << mStatus << endl;
+ }
+ exit(1);
+ }
+}
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Distructor closes the jmess jack audio client.
+ *
+ */
+//-------------------------------------------------------------------------------
+JMess::~JMess()
+{
+ if (jack_client_close(mClient))
+ cerr << "ERROR: Could not close the hidden jmess jack client." << endl;
+}
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Write an XML file with the name specified at xmlOutFile.
+ *
+ */
+//-------------------------------------------------------------------------------
+void JMess::writeOutput(QString xmlOutFile)
+{
+ // QDomDocument jmess_xml; QDomElement root;
+ // QDomElement connection; QDomElement output;
+ // QDomElement input; QDomText output_name;
+ // QDomText input_name;
+
+ // QVector<QString> OutputInput(2);
+
+ // this->setConnectedPorts();
+
+ // root = jmess_xml.createElement("jmess");
+ // for (QVector<QVector<QString> >::iterator it = mConnectedPorts.begin();
+ // it != mConnectedPorts.end(); ++it) {
+ // OutputInput = *it;
+ // //cout << "Output ===> " <<qPrintable(OutputInput[0]) << endl;
+ // //cout << "Input ===> " <<qPrintable(OutputInput[1]) << endl;
+
+ // //Initialize XML elements
+ // connection = jmess_xml.createElement("connection");
+ // output = jmess_xml.createElement("output");
+ // input = jmess_xml.createElement("input");
+ // output_name = jmess_xml.createTextNode(OutputInput[0]);
+ // input_name = jmess_xml.createTextNode(OutputInput[1]);
+
+ // jmess_xml.appendChild(root); root.appendChild(connection);
+ // connection.appendChild(output); connection.appendChild(input);
+ // output.appendChild(output_name); input.appendChild(input_name);
+ // }
+
+ // //Write output file
+ // QFile file(xmlOutFile);
+ // string answer = "";
+ // //Check for existing file first, and confirm before overwriting
+ // if (file.exists()) {
+ // while ((answer != "yes") && (answer != "no")) {
+ // cout << "WARNING: The File " <<qPrintable(xmlOutFile)
+ // << " exists. Do you want to overwrite it? (yes/no): ";
+ // cin >> answer;
+ // }
+ // }
+ // else {
+ // answer = "yes";
+ // }
+
+ // if (answer == "yes") {
+ // if (!file.open(QIODevice::WriteOnly)) {
+ // cerr << "Cannot open file for writing: "
+ // << qPrintable(file.errorString()) << endl;
+ // exit(1);
+ // }
+
+ // QTextStream out(&file);
+ // jmess_xml.save(out, Indent);
+ // cout << qPrintable(xmlOutFile) << " written." << endl;
+ // }
+}
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Set list of ouput ports that have connections.
+ *
+ */
+//-------------------------------------------------------------------------------
+void JMess::setConnectedPorts()
+{
+ mConnectedPorts.clear();
+
+ const char **ports, **connections; //vector of ports and connections
+ QVector<QString> OutputInput(2); //helper variable
+
+ //Get active output ports.
+ ports = jack_get_ports (mClient, NULL, NULL, JackPortIsOutput);
+
+ for (unsigned int out_i = 0; ports[out_i]; ++out_i) {
+ if ((connections = jack_port_get_all_connections
+ (mClient, jack_port_by_name(mClient, ports[out_i]))) != 0) {
+ for (unsigned int in_i = 0; connections[in_i]; ++in_i) {
+ OutputInput[0] = ports[out_i];
+ // cout << "Output ===> " <<qPrintable(OutputInput[0]) << endl;
+ OutputInput[1] = connections[in_i];
+ // cout << "Input ===> " << qPrintable(OutputInput[1]) << endl;
+ mConnectedPorts.append(OutputInput);
+ }
+ }
+ }
+
+ free(ports);
+}
+//*******************************************************************************
+void JMess::connectSpawnedPorts(int nChans, int hubPatch)
+// called from UdpMasterListener::connectMesh
+{
+ QString IPS[gMAX_WAIRS];
+ int ctr = 0;
+
+ const char **ports, **connections; //vector of ports and connections
+ QVector<QString> OutputInput(2); //helper variable
+
+ //Get active output ports.
+ ports = jack_get_ports (mClient, NULL, NULL, JackPortIsOutput);
+
+ for (unsigned int out_i = 0; ports[out_i]; ++out_i) {
+ // qDebug() << QString(ports[out_i]);
+ bool systemPort = QString(ports[out_i]).contains(QString("system"));
+
+ QString str = QString(ports[out_i]);
+ // for example "171.64.197.121:receive_1"
+ QString s = str.section(':', 0, 0);
+ // qDebug() << s << systemPort;
+ // for example "171.64.197.121"
+
+ bool newOne = !systemPort;
+ for (int i = 0; i<ctr; i++) if (newOne && (IPS[i]==s)) newOne = false;
+ if (newOne)
+ {
+ IPS[ctr] = s;
+ ctr++;
+ // qDebug() << ports[out_i] << systemPort << s;
+ }
+ }
+ for (int i = 0; i<ctr; i++) qDebug() << IPS[i];
+ disconnectAll();
+
+ int k = 0;
+ int jLimit = 1;
+
+ // FULLMIX is the union of CLIENTFOFI, CLIENTECHO
+
+ // implements CLIENTFOFI, CLIENTECHO -- also FULLMIX part which is CLIENTECHO
+ for (int i = 0; i<ctr; i++) {
+ if (hubPatch == JackTrip::CLIENTFOFI) jLimit = (ctr-1);
+ for (int j = 0; j<jLimit; j++) {
+ if ((hubPatch == JackTrip::CLIENTECHO)||(hubPatch == JackTrip::FULLMIX)) k = i;
+ else if (hubPatch == JackTrip::CLIENTFOFI) k = (j+(i+1))%ctr;
+ for (int l = 1; l<=nChans; l++) { // chans are 1-based
+ qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
+ <<"with " << IPS[k]+":send_"+QString::number(l);
+
+ QString left = IPS[i] +
+ ":receive_" + QString::number(l);
+ QString right = IPS[k] +
+ ":send_" + QString::number(l);
+
+ if (0 !=
+ jack_connect(mClient, left.toStdString().c_str(), right.toStdString().c_str())) {
+ qDebug() << "WARNING: port: " << left
+ << "and port: " << right
+ << " could not be connected.";
+ }
+ }
+ }
+ }
+
+ // do it again to implement the FULLMIX part which is CLIENTFOFI
+ if (hubPatch == JackTrip::FULLMIX) {
+ jLimit = (ctr-1); // same as CLIENTFOFI
+ /*************/
+ // todo: the next block should be in a method, it's a repeat of the above
+ for (int i = 0; i<ctr; i++) {
+ for (int j = 0; j<jLimit; j++) {
+ k = (j+(i+1))%ctr;
+ for (int l = 1; l<=nChans; l++) { // chans are 1-based
+ qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
+ <<"with " << IPS[k]+":send_"+QString::number(l);
+
+ QString left = IPS[i] +
+ ":receive_" + QString::number(l);
+ QString right = IPS[k] +
+ ":send_" + QString::number(l);
+
+ if (0 !=
+ jack_connect(mClient, left.toStdString().c_str(), right.toStdString().c_str())) {
+ qDebug() << "WARNING: port: " << left
+ << "and port: " << right
+ << " could not be connected.";
+ }
+ }
+ }
+ }
+ }
+
+ free(ports);
+}
+
+//*******************************************************************************
+// connectTUB is called when in hubpatch mode 4 = RESERVEDMATRIX
+// TU Berlin Raspberry Pi ensemble, Winter 2019
+// this gets run on the ensemble's hub server with
+// ./jacktrip -S -p3
+// it connects a set of client jacktrips with known hardwired IP addresses
+// to a known hardwired audio process with known hardwired audio port names
+// when clients connect / disconnect dynamically this just runs through the
+// audio connection sequence bruteforce at every new connection change
+// those that are preexisting won't change
+// a new one will connect accordingly and
+// those that fail because they don't exist will fail, no worries
+
+// setting the connections tested with jacktrip_globals.h
+// const QString gDOMAIN_TRIPLE = QString("130.149.23"); // for TUB multiclient hub
+// const int gMIN_TUB = 215; // lowest client address
+// const int gMAX_TUB = 215; // highest client address
+
+///////////////////////////////
+// test NUC as server
+//#define HARDWIRED_AUDIO_PROCESS_ON_SERVER "par20straightWire"
+//#define ENUMERATE ""
+//#define HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN ":in_"
+//#define HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT ":out_"
+
+///////////////////////////////
+// test Riviera as server
+// for deployment change jacktrip_globals.h to
+// const QString gDOMAIN_TRIPLE = QString("192.168.0"); // for TUB multiclient hub
+// const int gMIN_TUB = 11; // lowest client address
+// const int gMAX_TUB = 20; // highest client address
+// and give the proper audio process and connection names
+
+#define HARDWIRED_AUDIO_PROCESS_ON_SERVER "SuperCollider"
+#define HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN ":in_"
+#define HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT ":out_"
+// On server side it is SC jack-clients with indivisual names:
+// POE_0...POE_16
+// and each has (at this moment) one port in/out:
+// receive_1
+// send_1
+// I think it should be extended to 4 in/out ports per client.
+
+// this is brute force, does not look at individual clients, just patches the whole ensemble
+// each time
+void JMess::connectTUB(int /*nChans*/)
+// called from UdpMasterListener::connectPatch
+{
+ for (int i = 0; i<=gMAX_TUB-gMIN_TUB; i++) // last IP decimal octet
+ for (int l = 1; l<=1; l++) // mono for now // chans are 1-based, 1...2
+ {
+ // jacktrip to SC
+ QString client = gDOMAIN_TRIPLE + QString(".") + QString::number(gMIN_TUB+i);
+ QString serverAudio = QString(HARDWIRED_AUDIO_PROCESS_ON_SERVER);
+ int tmp = i + l; // only works for mono... completely wrong for 2 or more chans
+ qDebug() << "connect " << client << ":receive_ " << l
+ <<"with " << serverAudio << HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN << tmp;
+
+ QString left = QString(client + ":receive_" + QString::number(l));
+ QString right = QString(serverAudio + HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN +
+ QString::number(tmp));
+
+ if (0 !=
+ jack_connect(mClient, left.toStdString().c_str(),
+ right.toStdString().c_str())) {
+ qDebug() << "WARNING: port: " << left
+ << "and port: " << right
+ << " could not be connected.";
+ }
+
+ // SC to jacktrip
+ tmp += 4; // increase tmp for port offest
+ qDebug() << "connect " << serverAudio << HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT
+ << tmp <<"with " << client << ":send_" << l;
+
+ left = QString(serverAudio + HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT +
+ QString::number(tmp));
+ right = QString(client + ":send_" + QString::number(l));
+
+ if (0 !=
+ jack_connect(mClient, left.toStdString().c_str(),
+ right.toStdString().c_str())) {
+ qDebug() << "WARNING: port: " << left
+ << "and port: " << right
+ << " could not be connected.";
+ }
+
+ }
+}
+
+//-------------------------------------------------------------------------------
+/*! \brief Disconnect all the clients.
+ *
+ */
+//-------------------------------------------------------------------------------
+void JMess::disconnectAll()
+{
+ QVector<QString> OutputInput(2);
+
+ this->setConnectedPorts();
+
+ for (QVector<QVector<QString> >::iterator it = mConnectedPorts.begin();
+ it != mConnectedPorts.end(); ++it) {
+ OutputInput = *it;
+
+ if (jack_disconnect(mClient, OutputInput[0].toLatin1(), OutputInput[1].toLatin1())) {
+ cerr << "WARNING: port: " << qPrintable(OutputInput[0])
+ << "and port: " << qPrintable(OutputInput[1])
+ << " could not be disconnected.\n";
+ }
+ }
+
+}
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Parse the XML input file.
+ *
+ * Returns 0 on success, or 1 if the file has an incorrect format or cannot
+ * read the file.
+ */
+//-------------------------------------------------------------------------------
+int JMess::parseXML(QString xmlInFile)
+{
+ // mPortsToConnect.clear();
+ // QString errorStr;
+ // int errorLine;
+ // int errorColumn;
+
+ // QFile file(xmlInFile);
+ // if (!file.open(QIODevice::ReadOnly)) {
+ // cerr << "Cannot open file for reading: "
+ // << qPrintable(file.errorString()) << endl;
+ // return 1;
+ // }
+
+ // QDomDocument doc;
+ // if (!doc.setContent(&file, true, &errorStr, &errorLine,
+ // &errorColumn)) {
+ // cerr << "===================================================\n"
+ // << "Error parsing XML input file:\n"
+ // << "Parse error at line " << errorLine
+ // << ", column " << errorColumn << "\n"
+ // << qPrintable(errorStr) << "\n"
+ // << "===================================================\n";
+ // return 1;
+ // }
+
+ // QDomElement jmess = doc.documentElement();
+ // if (jmess.tagName() != "jmess") {
+ // cerr << "Error: Root tag should be <jmess>: "
+ // << qPrintable(jmess.tagName()) << endl;
+ // return 1;
+ // }
+
+
+ // QVector<QString> OutputInput(2);
+ // //First check for <connection> tag
+ // for(QDomNode n_cntn = jmess.firstChild();
+ // !n_cntn.isNull(); n_cntn = n_cntn.nextSibling()) {
+ // QDomElement cntn = n_cntn.toElement();
+ // if (cntn.tagName() == "connection") {
+ // //Now check for ouput & input tag
+ // for(QDomNode n_sck = cntn.firstChild();
+ // !n_sck.isNull(); n_sck = n_sck.nextSibling()) {
+ // QDomElement sck = n_sck.toElement();
+ // //cout << qPrintable(sck.tagName()) << endl;
+ // //cout << qPrintable(sck.text()) << endl;
+ // if (sck.tagName() == "output") {
+ // OutputInput[0] = sck.text();
+ // }
+ // else if (sck.tagName() == "input") {
+ // OutputInput[1] = sck.text();
+ // }
+ // }
+ // mPortsToConnect.append(OutputInput);
+ // }
+ // }
+
+ return 0;
+
+}
+
+
+//-------------------------------------------------------------------------------
+/*! \brief Connect ports specified in input XML file xmlInFile
+ *
+ */
+//-------------------------------------------------------------------------------
+void JMess::connectPorts(QString xmlInFile)
+{
+ QVector<QString> OutputInput(2);
+
+ // if ( !(this->parseXML(xmlInFile)) ) {
+ // for (QVector<QVector<QString> >::iterator it = mPortsToConnect.begin();
+ // it != mPortsToConnect.end(); ++it) {
+ // OutputInput = *it;
+
+ // if (jack_connect(mClient, OutputInput[0].toLatin1(), OutputInput[1].toLatin1())) {
+ // //Display a warining only if the error is not because the ports are already
+ // //connected, in case the program doesn't display anyting.
+ // if (EEXIST !=
+ // jack_connect(mClient, OutputInput[0].toLatin1(), OutputInput[1].toLatin1())) {
+ // cerr << "WARNING: port: " << qPrintable(OutputInput[0])
+ // << "and port: " << qPrintable(OutputInput[1])
+ // << " could not be connected.\n";
+ // }
+ // }
+ // }
+ // }
+
+}
+
--- /dev/null
+/*
+ JMess: A simple utility so save your jack-audio mess.
+
+ Copyright (C) 2007-2010 Juan-Pablo Caceres.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+/*
+ * JMess.h
+ */
+
+#ifndef __JMESS_H
+#define __JMESS_H
+
+#include <iostream>
+#include <string>
+#include <errno.h>
+
+#include <QIODevice>
+#include <QString>
+#include <QVector>
+//#include <QtXml>
+//#include <QXmlSimpleReader>
+//#include <QXmlInputSource>
+//#include <QXmlContentHandler>
+
+#include <jack/jack.h>
+
+using namespace std;
+
+const int Indent = 2;
+
+//-------------------------------------------------------------------------------
+/*! \brief Class to save and load all jack client connections.
+ *
+ * Saves an XML file with all the current jack connections. This same file can
+ * be loaded to connect evrything again. The XML file can also be edited.
+ *
+ * Has also an option to disconnect all the clients.
+ */
+//-------------------------------------------------------------------------------
+class JMess {
+
+public:
+ JMess();
+ virtual ~JMess();
+
+ void disconnectAll();
+ void writeOutput(QString xmlOutFile);
+ void connectPorts(QString xmlInFile);
+ void setConnectedPorts();
+ /// \brief Cross connect ports between net combs, -l LAIR mode
+ void connectSpawnedPorts(int nChans, int hubPatch);
+ void connectTUB(int nChans);
+
+private:
+ int parseXML(QString xmlInFile);
+
+ jack_client_t *mClient; //Class client
+ jack_status_t mStatus; //Class client status
+
+ //Vectors of Connected Ports and Ports to connects
+ //This are a matrix (Nx2) of string like this:
+ //OuputPort1 InputPort1
+ // ...
+ //OuputPortN InputPortN
+ QVector<QVector<QString> > mConnectedPorts;
+ QVector<QVector<QString> > mPortsToConnect;
+};
+#endif
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
using std::cout; using std::endl;
-
// sJackMutex definition
QMutex JackAudioInterface::sJackMutex;
//*******************************************************************************
JackAudioInterface::JackAudioInterface(JackTrip* jacktrip,
int NumInChans, int NumOutChans,
+ #ifdef WAIR // wair
+ int NumNetRevChans,
+ #endif // endwhere
AudioInterface::audioBitResolutionT AudioBitResolution,
- const char* ClienName) :
-AudioInterface(jacktrip,
- NumInChans, NumOutChans,
- AudioBitResolution),
-mNumInChans(NumInChans), mNumOutChans(NumOutChans),
-//mAudioBitResolution(AudioBitResolution*8),
-mBitResolutionMode(AudioBitResolution),
-mClient(NULL),
-mClientName(ClienName),
-mJackTrip(jacktrip)
+ const char* ClientName) :
+ AudioInterface(jacktrip,
+ NumInChans, NumOutChans,
+ #ifdef WAIR // wair
+ NumNetRevChans,
+ #endif // endwhere
+ AudioBitResolution),
+ mNumInChans(NumInChans), mNumOutChans(NumOutChans),
+ #ifdef WAIR // WAIR
+ mNumNetRevChans(NumNetRevChans),
+ #endif // endwhere
+ //mAudioBitResolution(AudioBitResolution*8),
+ mBitResolutionMode(AudioBitResolution),
+ mClient(NULL),
+ mClientName(ClientName),
+ mJackTrip(jacktrip)
{}
//*******************************************************************************
void JackAudioInterface::setup()
{
- setupClient();
- AudioInterface::setup();
- setProcessCallback();
+ setupClient();
+ AudioInterface::setup();
+ setProcessCallback();
}
//*******************************************************************************
void JackAudioInterface::setupClient()
-{
- const char* client_name = mClientName;
- const char* server_name = NULL;
- jack_options_t options = JackNoStartServer;
- jack_status_t status;
-
- // Try to connect to the server
- /// \todo Write better warning messages. This following line displays very
- /// verbose message, check how to desable them.
- {
- QMutexLocker locker(&sJackMutex);
- mClient = jack_client_open (client_name, options, &status, server_name);
- }
-
- if (mClient == NULL) {
- //fprintf (stderr, "jack_client_open() failed, "
- // "status = 0x%2.0x\n", status);
- if (status & JackServerFailed) {
- fprintf (stderr, "Unable to connect to JACK server\n");
- //std::cerr << "ERROR: Maybe the JACK server is not running?" << std::endl;
- //std::cerr << gPrintSeparator << std::endl;
+{
+ const char* client_name = mClientName;
+ const char* server_name = NULL;
+ // was jack_options_t options = JackNoStartServer;
+ // and then jack_options_t options = JackLoadName;
+ jack_options_t options = JackNullOption; // from jackSimpleClient example
+ jack_status_t status;
+
+ // Try to connect to the server
+ /// \todo Write better warning messages. This following line displays very
+ /// verbose message, check how to desable them.
+ {
+ QMutexLocker locker(&sJackMutex);
+#ifndef WAIR // WAIR
+ mClient = jack_client_open (client_name, options, &status, server_name);
+#else
+ mClient = jack_client_open (client_name, JackUseExactName, &status, server_name);
+#endif // endwhere
+ }
+
+ if (mClient == NULL) {
+ //fprintf (stderr, "jack_client_open() failed, "
+ // "status = 0x%2.0x\n", status);
+ if (status & JackServerFailed) {
+ fprintf (stderr, "Unable to connect to JACK server\n");
+ //std::cerr << "ERROR: Maybe the JACK server is not running?" << std::endl;
+ //std::cerr << gPrintSeparator << std::endl;
+ }
+ //std::exit(1);
+ throw std::runtime_error("Maybe the JACK server is not running?");
+ }
+ if (status & JackServerStarted) {
+ fprintf (stderr, "JACK server started\n");
+ }
+ if (status & JackNameNotUnique) {
+ client_name = jack_get_client_name(mClient);
+ fprintf (stderr, "unique name `%s' assigned\n", client_name);
}
- //std::exit(1);
- throw std::runtime_error("Maybe the JACK server is not running?");
- }
- if (status & JackServerStarted) {
- fprintf (stderr, "JACK server started\n");
- }
- if (status & JackNameNotUnique) {
- client_name = jack_get_client_name(mClient);
- fprintf (stderr, "unique name `%s' assigned\n", client_name);
- }
- // Set function to call if Jack shuts down
- jack_on_shutdown (mClient, this->jackShutdown, 0);
+ // Set function to call if Jack shuts down
+ jack_on_shutdown (mClient, this->jackShutdown, 0);
- // Create input and output channels
- createChannels();
+ // Create input and output channels
+ createChannels();
- // Buffer size member
- mNumFrames = getBufferSizeInSamples();
+ // Buffer size member
+ mNumFrames = getBufferSizeInSamples();
- // Initialize Buffer array to read and write audio
- mInBuffer.resize(mNumInChans);
- mOutBuffer.resize(mNumOutChans);
+ // Initialize Buffer array to read and write audio
+ mInBuffer.resize(mNumInChans);
+ mOutBuffer.resize(mNumOutChans);
}
//*******************************************************************************
void JackAudioInterface::createChannels()
{
- //Create Input Ports
- mInPorts.resize(mNumInChans);
- for (int i = 0; i < mNumInChans; i++)
+ //Create Input Ports
+ mInPorts.resize(mNumInChans);
+ for (int i = 0; i < mNumInChans; i++)
{
- QString inName;
- QTextStream (&inName) << "send_" << i+1;
- mInPorts[i] = jack_port_register (mClient, inName.toLatin1(),
- JACK_DEFAULT_AUDIO_TYPE,
- JackPortIsInput, 0);
+ QString inName;
+ QTextStream (&inName) << "send_" << i+1;
+ mInPorts[i] = jack_port_register (mClient, inName.toLatin1(),
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput, 0);
}
- //Create Output Ports
- mOutPorts.resize(mNumOutChans);
- for (int i = 0; i < mNumInChans; i++)
+ //Create Output Ports
+ mOutPorts.resize(mNumOutChans);
+ for (int i = 0; i < mNumInChans; i++)
{
- QString outName;
- QTextStream (&outName) << "receive_" << i+1;
- mOutPorts[i] = jack_port_register (mClient, outName.toLatin1(),
- JACK_DEFAULT_AUDIO_TYPE,
- JackPortIsOutput, 0);
+ QString outName;
+ QTextStream (&outName) << "receive_" << i+1;
+ mOutPorts[i] = jack_port_register (mClient, outName.toLatin1(),
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
}
}
//*******************************************************************************
-uint32_t JackAudioInterface::getSampleRate() const
+uint32_t JackAudioInterface::getSampleRate() const
{
- return jack_get_sample_rate(mClient);
+ return jack_get_sample_rate(mClient);
}
//*******************************************************************************
-uint32_t JackAudioInterface::getBufferSizeInSamples() const
+uint32_t JackAudioInterface::getBufferSizeInSamples() const
{
- return jack_get_buffer_size(mClient);
+ return jack_get_buffer_size(mClient);
}
//*******************************************************************************
size_t JackAudioInterface::getSizeInBytesPerChannel() const
{
- return (getBufferSizeInSamples() * getAudioBitResolution()/8);
+ return (getBufferSizeInSamples() * getAudioBitResolution()/8);
}
//*******************************************************************************
void JackAudioInterface::setProcessCallback()
{
- std::cout << "Setting JACK Process Callback..." << std::endl;
- if ( int code =
- jack_set_process_callback(mClient, JackAudioInterface::wrapperProcessCallback, this)
- )
+ std::cout << "Setting JACK Process Callback..." << std::endl;
+ if ( int code =
+ jack_set_process_callback(mClient, JackAudioInterface::wrapperProcessCallback, this)
+ )
{
- //std::cerr << "Could not set the process callback" << std::endl;
- //return(code);
- (void) code; // to avoid compiler warnings
- throw std::runtime_error("Could not set the Jack process callback");
- //std::exit(1);
+ //std::cerr << "Could not set the process callback" << std::endl;
+ //return(code);
+ (void) code; // to avoid compiler warnings
+ throw std::runtime_error("Could not set the Jack process callback");
+ //std::exit(1);
}
- std::cout << "SUCCESS" << std::endl;
- std::cout << gPrintSeparator << std::endl;
- //return(0);
+ std::cout << "SUCCESS" << std::endl;
+ std::cout << gPrintSeparator << std::endl;
+ //return(0);
}
//*******************************************************************************
int JackAudioInterface::startProcess() const
{
- //Tell the JACK server that we are ready to roll. Our
- //process() callback will start running now.
- if ( int code = (jack_activate(mClient)) )
+ //Tell the JACK server that we are ready to roll. Our
+ //process() callback will start running now.
+ if ( int code = (jack_activate(mClient)) )
{
- std::cerr << "Cannot activate client" << std::endl;
- return(code);
+ std::cerr << "Cannot activate client" << std::endl;
+ return(code);
}
- return(0);
+ return(0);
}
//*******************************************************************************
int JackAudioInterface::stopProcess() const
{
- QMutexLocker locker(&sJackMutex);
- int code = (jack_client_close(mClient));
- if ( code != 0 )
+ QMutexLocker locker(&sJackMutex);
+ int code = (jack_client_close(mClient));
+ if ( code != 0 )
{
- std::cerr << "Cannot disconnect client" << std::endl;
- return(code);
+ std::cerr << "Cannot disconnect client" << std::endl;
+ return(code);
}
- return(0);
+ return(0);
}
//*******************************************************************************
void JackAudioInterface::jackShutdown (void*)
{
- //std::cout << "The Jack Server was shut down!" << std::endl;
- throw std::runtime_error("The Jack Server was shut down!");
- //std::cout << "Exiting program..." << std::endl;
- //std::exit(1);
+ //std::cout << "The Jack Server was shut down!" << std::endl;
+ throw std::runtime_error("The Jack Server was shut down!");
+ //std::cout << "Exiting program..." << std::endl;
+ //std::exit(1);
}
//*******************************************************************************
int JackAudioInterface::processCallback(jack_nframes_t nframes)
{
- // Get input and output buffers from JACK
- //-------------------------------------------------------------------
- for (int i = 0; i < mNumInChans; i++) {
- // Input Ports are READ ONLY
- mInBuffer[i] = (sample_t*) jack_port_get_buffer(mInPorts[i], nframes);
- }
- for (int i = 0; i < mNumOutChans; i++) {
- // Output Ports are WRITABLE
- mOutBuffer[i] = (sample_t*) jack_port_get_buffer(mOutPorts[i], nframes);
- }
- //-------------------------------------------------------------------
- // TEST: Loopback
- // To test, uncomment and send audio to client input. The same audio
- // should come out as output in the first channel
- //memcpy (mOutBuffer[0], mInBuffer[0], sizeof(sample_t) * nframes);
- //memcpy (mOutBuffer[1], mInBuffer[1], sizeof(sample_t) * nframes);
- //-------------------------------------------------------------------
-
- AudioInterface::callback(mInBuffer, mOutBuffer, nframes);
- return 0;
+ // Get input and output buffers from JACK
+ //-------------------------------------------------------------------
+ for (int i = 0; i < mNumInChans; i++) {
+ // Input Ports are READ ONLY
+ mInBuffer[i] = (sample_t*) jack_port_get_buffer(mInPorts[i], nframes);
+ }
+ for (int i = 0; i < mNumOutChans; i++) {
+ // Output Ports are WRITABLE
+ mOutBuffer[i] = (sample_t*) jack_port_get_buffer(mOutPorts[i], nframes);
+ }
+ //-------------------------------------------------------------------
+ // TEST: Loopback
+ // To test, uncomment and send audio to client input. The same audio
+ // should come out as output in the first channel
+ //memcpy (mOutBuffer[0], mInBuffer[0], sizeof(sample_t) * nframes);
+ //memcpy (mOutBuffer[1], mInBuffer[1], sizeof(sample_t) * nframes);
+ //-------------------------------------------------------------------
+
+ AudioInterface::callback(mInBuffer, mOutBuffer, nframes);
+ return 0;
}
//*******************************************************************************
-int JackAudioInterface::wrapperProcessCallback(jack_nframes_t nframes, void *arg)
+int JackAudioInterface::wrapperProcessCallback(jack_nframes_t nframes, void *arg)
{
- return static_cast<JackAudioInterface*>(arg)->processCallback(nframes);
+ return static_cast<JackAudioInterface*>(arg)->processCallback(nframes);
}
//*******************************************************************************
void JackAudioInterface::connectDefaultPorts()
{
- const char** ports;
-
- // Get physical output (capture) ports
- if ( (ports =
- jack_get_ports (mClient, NULL, NULL,
- JackPortIsPhysical | JackPortIsOutput)) == NULL)
- {
- cout << "WARING: Cannot find any physical capture ports" << endl;
- }
- else
- {
- // Connect capure ports to jacktrip send
- for (int i = 0; i < mNumInChans; i++)
+ const char** ports;
+
+ // Get physical output (capture) ports
+ if ( (ports =
+ jack_get_ports (mClient, NULL, NULL,
+ JackPortIsPhysical | JackPortIsOutput)) == NULL)
{
- // Check that we don't run out of capture ports
- if ( ports[i] != NULL ) {
- jack_connect(mClient, ports[i], jack_port_name(mInPorts[i]));
- }
+ cout << "WARNING: Cannot find any physical capture ports" << endl;
}
- std::free(ports);
- }
-
- // Get physical input (playback) ports
- if ( (ports =
- jack_get_ports (mClient, NULL, NULL,
- JackPortIsPhysical | JackPortIsInput)) == NULL)
- {
- cout << "WARING: Cannot find any physical playback ports" << endl;
- }
- else
- {
- // Connect playback ports to jacktrip receive
- for (int i = 0; i < mNumOutChans; i++)
+ else
{
- // Check that we don't run out of capture ports
- if ( ports[i] != NULL ) {
- jack_connect(mClient, jack_port_name(mOutPorts[i]), ports[i]);
- }
+ // Connect capure ports to jacktrip send
+ for (int i = 0; i < mNumInChans; i++)
+ {
+ // Check that we don't run out of capture ports
+ if ( ports[i] != NULL ) {
+ jack_connect(mClient, ports[i], jack_port_name(mInPorts[i]));
+ }
+ }
+ std::free(ports);
+ }
+
+ // Get physical input (playback) ports
+ if ( (ports =
+ jack_get_ports (mClient, NULL, NULL,
+ JackPortIsPhysical | JackPortIsInput)) == NULL)
+ {
+ cout << "WARNING: Cannot find any physical playback ports" << endl;
+ }
+ else
+ {
+ // Connect playback ports to jacktrip receive
+ for (int i = 0; i < mNumOutChans; i++)
+ {
+ // Check that we don't run out of capture ports
+ if ( ports[i] != NULL ) {
+ jack_connect(mClient, jack_port_name(mOutPorts[i]), ports[i]);
+ }
+ }
+ std::free(ports);
}
- std::free(ports);
- }
}
// --------------------------------
computeNetworkProcessToNetwork();
*/
- ///************PROTORYPE FOR CELT**************************
- ///********************************************************
- /*
+///************PROTORYPE FOR CELT**************************
+///********************************************************
+/*
CELTMode* mode;
int* error;
mode = celt_mode_create(48000, 2, 64, error);
*/
- //celt_mode_create(48000, 2, 64, NULL);
- //unsigned char* compressed;
- //CELTEncoder* celtEncoder;
- //celt_encode_float(celtEncoder, mInBuffer, NULL, compressed, );
+//celt_mode_create(48000, 2, 64, NULL);
+//unsigned char* compressed;
+//CELTEncoder* celtEncoder;
+//celt_encode_float(celtEncoder, mInBuffer, NULL, compressed, );
- ///********************************************************
- ///********************************************************
+///********************************************************
+///********************************************************
// return 0;
//}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
{
public:
- /** \brief The class constructor
+ /** \brief The class constructor
* \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
* \param NumInChans Number of Input Channels
* \param NumOutChans Number of Output Channels
* \param AudioBitResolution Audio Sample Resolutions in bits
* \param ClientName Client name in Jack
*/
- JackAudioInterface(JackTrip* jacktrip,
- int NumInChans, int NumOutChans,
- AudioInterface::audioBitResolutionT AudioBitResolution = AudioInterface::BIT16,
- const char* ClientName = "JackTrip");
- /// \brief The class destructor
- virtual ~JackAudioInterface();
-
- /// \brief Setup the client
- virtual void setup();
- /** \brief Tell the JACK server that we are ready to roll. The
+ JackAudioInterface(JackTrip* jacktrip,
+ int NumInChans, int NumOutChans,
+ #ifdef WAIR // wair
+ int NumNetRevChans,
+ #endif // endwhere
+ AudioInterface::audioBitResolutionT AudioBitResolution = AudioInterface::BIT16,
+ const char* ClientName = "JackTrip");
+ /// \brief The class destructor
+ virtual ~JackAudioInterface();
+
+ /// \brief Setup the client
+ virtual void setup();
+ /** \brief Tell the JACK server that we are ready to roll. The
* process-callback will start running. This runs on its own thread.
* \return 0 on success, otherwise a non-zero error code
*/
- virtual int startProcess() const;
- /** \brief Stops the process-callback thread
+ virtual int startProcess() const;
+ /** \brief Stops the process-callback thread
* \return 0 on success, otherwise a non-zero error code
*/
- virtual int stopProcess() const;
- /// \brief Connect the default ports, capture to sends, and receives to playback
- void connectDefaultPorts();
-
- //--------------SETTERS---------------------------------------------
- /// \brief Set Client Name to something different that the default (JackTrip)
- virtual void setClientName(const char* ClientName)
- { mClientName = ClientName; }
- virtual void setSampleRate(uint32_t /*sample_rate*/)
- { std::cout << "WARING: Setting the Sample Rate in Jack mode has no effect." << std::endl; }
- virtual void setBufferSizeInSamples(uint32_t /*buf_size*/)
- { std::cout << "WARING: Setting the Sample Rate in Jack mode has no effect." << std::endl; }
- //------------------------------------------------------------------
-
- //--------------GETTERS---------------------------------------------
- /// \brief Get the Jack Server Sampling Rate, in samples/second
- virtual uint32_t getSampleRate() const;
- /// \brief Get the Jack Server Buffer Size, in samples
- virtual uint32_t getBufferSizeInSamples() const;
- /// \brief Get the Jack Server Buffer Size, in bytes
- virtual uint32_t getBufferSizeInBytes() const
- { return (getBufferSizeInSamples() * getAudioBitResolution()/8); }
- /// \brief Get size of each audio per channel, in bytes
- virtual size_t getSizeInBytesPerChannel() const;
- //------------------------------------------------------------------
+ virtual int stopProcess() const;
+ /// \brief Connect the default ports, capture to sends, and receives to playback
+ void connectDefaultPorts();
+
+ //--------------SETTERS---------------------------------------------
+ /// \brief Set Client Name to something different that the default (JackTrip)
+ virtual void setClientName(const char* ClientName)
+ { mClientName = ClientName; }
+ virtual void setSampleRate(uint32_t /*sample_rate*/)
+ { std::cout << "WARNING: Setting the Sample Rate in Jack mode has no effect." << std::endl; }
+ virtual void setBufferSizeInSamples(uint32_t /*buf_size*/)
+ { std::cout << "WARNING: Setting the Sample Rate in Jack mode has no effect." << std::endl; }
+ //------------------------------------------------------------------
+
+ //--------------GETTERS---------------------------------------------
+ /// \brief Get the Jack Server Sampling Rate, in samples/second
+ virtual uint32_t getSampleRate() const;
+ /// \brief Get the Jack Server Buffer Size, in samples
+ virtual uint32_t getBufferSizeInSamples() const;
+ /// \brief Get the Jack Server Buffer Size, in bytes
+ virtual uint32_t getBufferSizeInBytes() const
+ { return (getBufferSizeInSamples() * getAudioBitResolution()/8); }
+ /// \brief Get size of each audio per channel, in bytes
+ virtual size_t getSizeInBytesPerChannel() const;
+ //------------------------------------------------------------------
private:
- /** \brief Private method to setup a client of the Jack server.
+ /** \brief Private method to setup a client of the Jack server.
* \exception std::runtime_error Can't start Jack
*
* This method is called by the class constructors. It does the following:\n
* - Sets the shutdown process callback
* - Creates the appropriate number of input and output channels
*/
- void setupClient();
- /// \brief Creates input and output channels in the Jack client
- void createChannels();
- /** \brief JACK calls this shutdown_callback if the server ever shuts down or
+ void setupClient();
+ /// \brief Creates input and output channels in the Jack client
+ void createChannels();
+ /** \brief JACK calls this shutdown_callback if the server ever shuts down or
* decides to disconnect the client.
*/
- static void jackShutdown(void*);
- /** \brief Set the process callback of the member function processCallback.
+ static void jackShutdown(void*);
+ /** \brief Set the process callback of the member function processCallback.
* This process will be called by the JACK server whenever there is work to be done.
*/
- void setProcessCallback();
- /** \brief JACK process callback
- *
- * This is the function to be called to process audio. This function is
+ void setProcessCallback();
+ /** \brief JACK process callback
+ *
+ * This is the function to be called to process audio. This function is
* of the type JackProcessCallback, which is defined as:\n
* <tt>typedef int(* JackProcessCallback)(jack_nframes_t nframes, void *arg)</tt>
* \n
* http://jackaudio.org/files/docs/html/types_8h.html#4923142208a8e7dacf00ca7a10681d2b
* for more details
*/
- int processCallback(jack_nframes_t nframes);
- /** \brief Wrapper to cast the member processCallback to a static function pointer
+ int processCallback(jack_nframes_t nframes);
+ /** \brief Wrapper to cast the member processCallback to a static function pointer
* that can be used with <tt>jack_set_process_callback</tt>
*
* <tt>jack_set_process_callback</tt> needs a static member function pointer. A normal
* member function won't work because a <b><i>this</i></b> pointer is passed under the scenes.
- * That's why we
+ * That's why we
* need to cast the member funcion processCallback to the static function
* wrapperProcessCallback. The callback is then set as:\n
* <tt>jack_set_process_callback(mClient, JackAudioInterface::wrapperProcessCallback,
* this)</tt>
*/
- // reference : http://article.gmane.org/gmane.comp.audio.jackit/12873
- static int wrapperProcessCallback(jack_nframes_t nframes, void *arg) ;
-
- int mNumInChans;///< Number of Input Channels
- int mNumOutChans; ///< Number of Output Channels
- int mNumFrames; ///< Buffer block size, in samples
- //int mAudioBitResolution; ///< Bit resolution in audio samples
- AudioInterface::audioBitResolutionT mBitResolutionMode; ///< Bit resolution (audioBitResolutionT) mode
-
- jack_client_t* mClient; ///< Jack Client
- const char* mClientName; ///< Jack Client Name
- QVarLengthArray<jack_port_t*> mInPorts; ///< Vector of Input Ports (Channels)
- QVarLengthArray<jack_port_t*> mOutPorts; ///< Vector of Output Ports (Channels)
- QVarLengthArray<sample_t*> mInBuffer; ///< Vector of Input buffers/channel read from JACK
- QVarLengthArray<sample_t*> mOutBuffer; ///< Vector of Output buffer/channel to write to JACK
- size_t mSizeInBytesPerChannel; ///< Size in bytes per audio channel
- QVector<ProcessPlugin*> mProcessPlugins; ///< Vector of ProcesPlugin<EM>s</EM>
- JackTrip* mJackTrip; ///< JackTrip mediator class
- static QMutex sJackMutex; ///< Mutex to make thread safe jack functions that are not
+ // reference : http://article.gmane.org/gmane.comp.audio.jackit/12873
+ static int wrapperProcessCallback(jack_nframes_t nframes, void *arg) ;
+
+ int mNumInChans;///< Number of Input Channels
+ int mNumOutChans; ///< Number of Output Channels
+#ifdef WAIR // WAIR
+ int mNumNetRevChans; ///< Number of Network Audio Channels (network comb filters
+#endif // endwhere
+ int mNumFrames; ///< Buffer block size, in samples
+ //int mAudioBitResolution; ///< Bit resolution in audio samples
+ AudioInterface::audioBitResolutionT mBitResolutionMode; ///< Bit resolution (audioBitResolutionT) mode
+
+ jack_client_t* mClient; ///< Jack Client
+ const char* mClientName; ///< Jack Client Name
+ QVarLengthArray<jack_port_t*> mInPorts; ///< Vector of Input Ports (Channels)
+ QVarLengthArray<jack_port_t*> mOutPorts; ///< Vector of Output Ports (Channels)
+ QVarLengthArray<sample_t*> mInBuffer; ///< Vector of Input buffers/channel read from JACK
+ QVarLengthArray<sample_t*> mOutBuffer; ///< Vector of Output buffer/channel to write to JACK
+ size_t mSizeInBytesPerChannel; ///< Size in bytes per audio channel
+ QVector<ProcessPlugin*> mProcessPlugins; ///< Vector of ProcesPlugin<EM>s</EM>
+ JackTrip* mJackTrip; ///< JackTrip mediator class
+ static QMutex sJackMutex; ///< Mutex to make thread safe jack functions that are not
};
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#endif
#include <iostream>
-//#include <unistd.h> // for usleep, sleep
#include <cstdlib>
#include <stdexcept>
#include <QHostAddress>
+#include <QHostInfo>
#include <QThread>
#include <QTcpSocket>
//its purpose is to close the app when control c is hit by the user in rtaudio/asio4all mode
#if defined __WIN_32__
void sigint_handler(int sig)
- {
- exit(0);
- }
+{
+ exit(0);
+}
#endif
//*******************************************************************************
JackTrip::JackTrip(jacktripModeT JacktripMode,
- dataProtocolT DataProtocolType,
- int NumChans,
- int BufferQueueLength,
- unsigned int redundancy,
- AudioInterface::audioBitResolutionT AudioBitResolution,
- DataProtocol::packetHeaderTypeT PacketHeaderType,
- underrunModeT UnderRunMode,
- int receiver_bind_port, int sender_bind_port,
- int receiver_peer_port, int sender_peer_port) :
- mJackTripMode(JacktripMode),
- mDataProtocol(DataProtocolType),
- mPacketHeaderType(PacketHeaderType),
- mAudiointerfaceMode(JackTrip::JACK),
- mNumChans(NumChans),
- mBufferQueueLength(BufferQueueLength),
- mSampleRate(gDefaultSampleRate),
- mAudioBufferSize(gDefaultBufferSizeInSamples),
- mAudioBitResolution(AudioBitResolution),
- mDataProtocolSender(NULL),
- mDataProtocolReceiver(NULL),
- mAudioInterface(NULL),
- mPacketHeader(NULL),
- mUnderRunMode(UnderRunMode),
- mSendRingBuffer(NULL),
- mReceiveRingBuffer(NULL),
- mReceiverBindPort(receiver_bind_port),
- mSenderPeerPort(sender_peer_port),
- mSenderBindPort(sender_bind_port),
- mReceiverPeerPort(receiver_peer_port),
- mTcpServerPort(4464),
- mRedundancy(redundancy),
- mJackClientName("JackTrip"),
- mConnectionMode(JackTrip::NORMAL),
- mReceivedConnection(false),
- mTcpConnectionError(false),
- mStopped(false)
+ dataProtocolT DataProtocolType,
+ int NumChans,
+ #ifdef WAIR // WAIR
+ int NumNetRevChans,
+ #endif // endwhere
+ int BufferQueueLength,
+ unsigned int redundancy,
+ AudioInterface::audioBitResolutionT AudioBitResolution,
+ DataProtocol::packetHeaderTypeT PacketHeaderType,
+ underrunModeT UnderRunMode,
+ int receiver_bind_port, int sender_bind_port,
+ int receiver_peer_port, int sender_peer_port) :
+ mJackTripMode(JacktripMode),
+ mDataProtocol(DataProtocolType),
+ mPacketHeaderType(PacketHeaderType),
+ mAudiointerfaceMode(JackTrip::JACK),
+ mNumChans(NumChans),
+ #ifdef WAIR // WAIR
+ mNumNetRevChans(NumNetRevChans),
+ #endif // endwhere
+ mBufferQueueLength(BufferQueueLength),
+ mSampleRate(gDefaultSampleRate),
+ mDeviceID(gDefaultDeviceID),
+ mAudioBufferSize(gDefaultBufferSizeInSamples),
+ mAudioBitResolution(AudioBitResolution),
+ mDataProtocolSender(NULL),
+ mDataProtocolReceiver(NULL),
+ mAudioInterface(NULL),
+ mPacketHeader(NULL),
+ mUnderRunMode(UnderRunMode),
+ mSendRingBuffer(NULL),
+ mReceiveRingBuffer(NULL),
+ mReceiverBindPort(receiver_bind_port),
+ mSenderPeerPort(sender_peer_port),
+ mSenderBindPort(sender_bind_port),
+ mReceiverPeerPort(receiver_peer_port),
+ mTcpServerPort(4464),
+ mRedundancy(redundancy),
+ mJackClientName("JackTrip"),
+ mConnectionMode(JackTrip::NORMAL),
+ mReceivedConnection(false),
+ mTcpConnectionError(false),
+ mStopped(false),
+ mConnectDefaultAudioPorts(true)
{
- createHeader(mPacketHeaderType);
+ createHeader(mPacketHeaderType);
}
//*******************************************************************************
JackTrip::~JackTrip()
{
- wait();
- delete mDataProtocolSender;
- delete mDataProtocolReceiver;
- delete mAudioInterface;
- delete mPacketHeader;
- delete mSendRingBuffer;
- delete mReceiveRingBuffer;
+ wait();
+ delete mDataProtocolSender;
+ delete mDataProtocolReceiver;
+ delete mAudioInterface;
+ delete mPacketHeader;
+ delete mSendRingBuffer;
+ delete mReceiveRingBuffer;
}
//*******************************************************************************
-void JackTrip::setupAudio()
+void JackTrip::setupAudio(
+ #ifdef WAIRTOMASTER // WAIR
+ int ID
+ #endif // endwhere
+ )
{
- // Check if mAudioInterface has already been created or not
- if (mAudioInterface != NULL) { // if it has been created, disconnet it from JACK and delete it
- cout << "WARINING: JackAudio interface was setup already:" << endl;
- cout << "It will be errased and setup again." << endl;
- cout << gPrintSeparator << endl;
- closeAudio();
- }
+ // Check if mAudioInterface has already been created or not
+ if (mAudioInterface != NULL) { // if it has been created, disconnet it from JACK and delete it
+ cout << "WARINING: JackAudio interface was setup already:" << endl;
+ cout << "It will be errased and setup again." << endl;
+ cout << gPrintSeparator << endl;
+ closeAudio();
+ }
- // Create AudioInterface Client Object
- if ( mAudiointerfaceMode == JackTrip::JACK ) {
+ // Create AudioInterface Client Object
+ if ( mAudiointerfaceMode == JackTrip::JACK ) {
#ifndef __NO_JACK__
- mAudioInterface = new JackAudioInterface(this, mNumChans, mNumChans, mAudioBitResolution);
- mAudioInterface->setClientName(mJackClientName);
- mAudioInterface->setup();
- mSampleRate = mAudioInterface->getSampleRate();
- mAudioBufferSize = mAudioInterface->getBufferSizeInSamples();
+ if (gVerboseFlag) std::cout << " JackTrip:setupAudio before new JackAudioInterface" << std::endl;
+ mAudioInterface = new JackAudioInterface(this, mNumChans, mNumChans,
+ #ifdef WAIR // wair
+ mNumNetRevChans,
+ #endif // endwhere
+ mAudioBitResolution);
+
+#ifdef WAIRTOMASTER // WAIR
+ qDebug() << "mPeerAddress" << mPeerAddress << mPeerAddress.contains(gDOMAIN_TRIPLE);
+ QString VARIABLE_AUDIO_NAME = WAIR_AUDIO_NAME; // legacy for WAIR
+ QByteArray tmp = QString(mPeerAddress).replace(":", ".").toLatin1();
+ if(mPeerAddress.toStdString()!="")
+ mJackClientName = tmp.constData();
+ std::cout << "WAIR ID " << ID << " jacktrip client name set to=" <<
+ mJackClientName << std::endl;
+
+#endif // endwhere
+
+ mAudioInterface->setClientName(mJackClientName);
+
+ if (gVerboseFlag) std::cout << " JackTrip:setupAudio before mAudioInterface->setup" << std::endl;
+ mAudioInterface->setup();
+ mSampleRate = mAudioInterface->getSampleRate();
+ mDeviceID = mAudioInterface->getDeviceID();
+ mAudioBufferSize = mAudioInterface->getBufferSizeInSamples();
#endif //__NON_JACK__
#ifdef __NO_JACK__ /// \todo FIX THIS REPETITION OF CODE
#ifdef __RT_AUDIO__
- cout << "Warning: using non jack version, RtAudio will be used instead" << endl;
- mAudioInterface = new RtAudioInterface(this, mNumChans, mNumChans, mAudioBitResolution);
- mAudioInterface->setSampleRate(mSampleRate);
- mAudioInterface->setBufferSizeInSamples(mAudioBufferSize);
- mAudioInterface->setup();
+ cout << "Warning: using non jack version, RtAudio will be used instead" << endl;
+ mAudioInterface = new RtAudioInterface(this, mNumChans, mNumChans, mAudioBitResolution);
+ mAudioInterface->setSampleRate(mSampleRate);
+ mAudioInterface->setDeviceID(mDeviceID);
+ mAudioInterface->setBufferSizeInSamples(mAudioBufferSize);
+ mAudioInterface->setup();
#endif
#endif
- }
- else if ( mAudiointerfaceMode == JackTrip::RTAUDIO ) {
+ }
+ else if ( mAudiointerfaceMode == JackTrip::RTAUDIO ) {
#ifdef __RT_AUDIO__
- mAudioInterface = new RtAudioInterface(this, mNumChans, mNumChans, mAudioBitResolution);
- mAudioInterface->setSampleRate(mSampleRate);
- mAudioInterface->setBufferSizeInSamples(mAudioBufferSize);
- mAudioInterface->setup();
+ mAudioInterface = new RtAudioInterface(this, mNumChans, mNumChans, mAudioBitResolution);
+ mAudioInterface->setSampleRate(mSampleRate);
+ mAudioInterface->setDeviceID(mDeviceID);
+ mAudioInterface->setBufferSizeInSamples(mAudioBufferSize);
+ mAudioInterface->setup();
#endif
- }
+ }
- std::cout << "The Sampling Rate is: " << mSampleRate << std::endl;
- std::cout << gPrintSeparator << std::endl;
- int AudioBufferSizeInBytes = mAudioBufferSize*sizeof(sample_t);
- std::cout << "The Audio Buffer Size is: " << mAudioBufferSize << " samples" << std::endl;
- std::cout << " or: " << AudioBufferSizeInBytes
- << " bytes" << std::endl;
- std::cout << gPrintSeparator << std::endl;
- cout << "The Number of Channels is: " << mAudioInterface->getNumInputChannels() << endl;
- std::cout << gPrintSeparator << std::endl;
- QThread::usleep(100);
+ std::cout << "The Sampling Rate is: " << mSampleRate << std::endl;
+ std::cout << gPrintSeparator << std::endl;
+ int AudioBufferSizeInBytes = mAudioBufferSize*sizeof(sample_t);
+ std::cout << "The Audio Buffer Size is: " << mAudioBufferSize << " samples" << std::endl;
+ std::cout << " or: " << AudioBufferSizeInBytes
+ << " bytes" << std::endl;
+ std::cout << gPrintSeparator << std::endl;
+ cout << "The Number of Channels is: " << mAudioInterface->getNumInputChannels() << endl;
+ std::cout << gPrintSeparator << std::endl;
+ cout << "The RTAudio device ID is: " << mAudioInterface->getDeviceID() << endl;
+ std::cout << gPrintSeparator << std::endl;
+ QThread::usleep(100);
}
//*******************************************************************************
void JackTrip::closeAudio()
{
- //mAudioInterface->close();
- if ( mAudioInterface != NULL ) {
- mAudioInterface->stopProcess();
- delete mAudioInterface;
- mAudioInterface = NULL;
- }
+ //mAudioInterface->close();
+ if ( mAudioInterface != NULL ) {
+ mAudioInterface->stopProcess();
+ delete mAudioInterface;
+ mAudioInterface = NULL;
+ }
}
//*******************************************************************************
void JackTrip::setupDataProtocol()
{
- // Create DataProtocol Objects
- switch (mDataProtocol) {
- case UDP:
- std::cout << "Using UDP Protocol" << std::endl;
- std::cout << gPrintSeparator << std::endl;
- QThread::usleep(100);
- mDataProtocolSender = new UdpDataProtocol(this, DataProtocol::SENDER,
- //mSenderPeerPort, mSenderBindPort,
- mSenderBindPort, mSenderPeerPort,
- mRedundancy);
- mDataProtocolReceiver = new UdpDataProtocol(this, DataProtocol::RECEIVER,
- mReceiverBindPort, mReceiverPeerPort,
- mRedundancy);
- break;
- case TCP:
- throw std::invalid_argument("TCP Protocol is not implemented");
- break;
- case SCTP:
- throw std::invalid_argument("SCTP Protocol is not implemented");
- break;
- default:
- throw std::invalid_argument("Protocol not defined or unimplemented");
- break;
- }
-
- // Set Audio Packet Size
- //mDataProtocolSender->setAudioPacketSize
- // (mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
- //mDataProtocolReceiver->setAudioPacketSize
- // (mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
- mDataProtocolSender->setAudioPacketSize(getTotalAudioPacketSizeInBytes());
- mDataProtocolReceiver->setAudioPacketSize(getTotalAudioPacketSizeInBytes());
+ // Create DataProtocol Objects
+ switch (mDataProtocol) {
+ case UDP:
+ std::cout << "Using UDP Protocol" << std::endl;
+ std::cout << gPrintSeparator << std::endl;
+ QThread::usleep(100);
+ mDataProtocolSender = new UdpDataProtocol(this, DataProtocol::SENDER,
+ //mSenderPeerPort, mSenderBindPort,
+ mSenderBindPort, mSenderPeerPort,
+ mRedundancy);
+ mDataProtocolReceiver = new UdpDataProtocol(this, DataProtocol::RECEIVER,
+ mReceiverBindPort, mReceiverPeerPort,
+ mRedundancy);
+ break;
+ case TCP:
+ throw std::invalid_argument("TCP Protocol is not implemented");
+ break;
+ case SCTP:
+ throw std::invalid_argument("SCTP Protocol is not implemented");
+ break;
+ default:
+ throw std::invalid_argument("Protocol not defined or unimplemented");
+ break;
+ }
+
+ // Set Audio Packet Size
+ //mDataProtocolSender->setAudioPacketSize
+ // (mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
+ //mDataProtocolReceiver->setAudioPacketSize
+ // (mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
+ mDataProtocolSender->setAudioPacketSize(getTotalAudioPacketSizeInBytes());
+ mDataProtocolReceiver->setAudioPacketSize(getTotalAudioPacketSizeInBytes());
}
//*******************************************************************************
void JackTrip::setupRingBuffers()
{
- // Create RingBuffers with the apprioprate size
- /// \todo Make all this operations cleaner
- //int total_audio_packet_size = getTotalAudioPacketSizeInBytes();
- int slot_size = getRingBuffersSlotSize();
-
- switch (mUnderRunMode) {
- case WAVETABLE:
- mSendRingBuffer = new RingBufferWavetable(slot_size,
- gDefaultOutputQueueLength);
- mReceiveRingBuffer = new RingBufferWavetable(slot_size,
- mBufferQueueLength);
- /*
+ // Create RingBuffers with the apprioprate size
+ /// \todo Make all this operations cleaner
+ //int total_audio_packet_size = getTotalAudioPacketSizeInBytes();
+ int slot_size = getRingBuffersSlotSize();
+
+ switch (mUnderRunMode) {
+ case WAVETABLE:
+ mSendRingBuffer = new RingBufferWavetable(slot_size,
+ gDefaultOutputQueueLength);
+ mReceiveRingBuffer = new RingBufferWavetable(slot_size,
+ mBufferQueueLength);
+ /*
mSendRingBuffer = new RingBufferWavetable(mAudioInterface->getSizeInBytesPerChannel() * mNumChans,
gDefaultOutputQueueLength);
mReceiveRingBuffer = new RingBufferWavetable(mAudioInterface->getSizeInBytesPerChannel() * mNumChans,
mBufferQueueLength);
*/
-
- break;
- case ZEROS:
- mSendRingBuffer = new RingBuffer(slot_size,
- gDefaultOutputQueueLength);
- mReceiveRingBuffer = new RingBuffer(slot_size,
- mBufferQueueLength);
- /*
+
+ break;
+ case ZEROS:
+ mSendRingBuffer = new RingBuffer(slot_size,
+ gDefaultOutputQueueLength);
+ mReceiveRingBuffer = new RingBuffer(slot_size,
+ mBufferQueueLength);
+ /*
mSendRingBuffer = new RingBuffer(mAudioInterface->getSizeInBytesPerChannel() * mNumChans,
gDefaultOutputQueueLength);
mReceiveRingBuffer = new RingBuffer(mAudioInterface->getSizeInBytesPerChannel() * mNumChans,
mBufferQueueLength);
*/
- break;
- default:
- throw std::invalid_argument("Underrun Mode undefined");
- break;
- }
+ break;
+ default:
+ throw std::invalid_argument("Underrun Mode undefined");
+ break;
+ }
}
//*******************************************************************************
void JackTrip::setPeerAddress(const char* PeerHostOrIP)
{
- mPeerAddress = PeerHostOrIP;
+ mPeerAddress = PeerHostOrIP;
}
//*******************************************************************************
void JackTrip::appendProcessPlugin(ProcessPlugin* plugin)
{
- mProcessPlugins.append(plugin);
- //mAudioInterface->appendProcessPlugin(plugin);
+ mProcessPlugins.append(plugin);
+ //mAudioInterface->appendProcessPlugin(plugin);
}
//*******************************************************************************
-void JackTrip::startProcess() throw(std::invalid_argument)
+void JackTrip::startProcess(
+ #ifdef WAIRTOMASTER // WAIR
+ int ID
+ #endif // endwhere
+ ) throw(std::invalid_argument)
{ //signal that catches ctrl c in rtaudio-asio mode
#if defined (__WIN_32__)
if (signal(SIGINT, sigint_handler) == SIG_ERR) {
- perror("signal");
- exit(1);
- }
-#endif
- // Check if ports are already binded by another process on this machine
- // ------------------------------------------------------------------
- checkIfPortIsBinded(mReceiverBindPort);
- checkIfPortIsBinded(mSenderBindPort);
- // Set all classes and parameters
- // ------------------------------
- setupAudio();
- createHeader(mPacketHeaderType);
- setupDataProtocol();
- setupRingBuffers();
- // Connect Signals and Slots
- // -------------------------
- QObject::connect(mPacketHeader, SIGNAL(signalError(const char*)),
- this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
- QObject::connect(mDataProtocolReceiver, SIGNAL(signalReceivedConnectionFromPeer()),
- this, SLOT(slotReceivedConnectionFromPeer()),
- Qt::QueuedConnection);
- QObject::connect(this, SIGNAL(signalUdpTimeOut()),
- this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
-
- //QObject::connect(mDataProtocolSender, SIGNAL(signalError(const char*)),
- // this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
- //QObject::connect(mDataProtocolReceiver, SIGNAL(signalError(const char*)),
- // this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
-
- // Start the threads for the specific mode
- // ---------------------------------------
- switch ( mJackTripMode )
- {
- case CLIENT :
- clientStart();
- break;
- case SERVER :
- serverStart();
- break;
- case CLIENTTOPINGSERVER :
- if ( clientPingToServerStart() == -1 ) { // if error on server start (-1) we return inmediatly
- mTcpConnectionError = true;
- slotStopProcesses();
- return;
- }
- break;
- case SERVERPINGSERVER :
- if ( serverStart(true) == -1 ) { // if error on server start (-1) we return inmediatly
- slotStopProcesses();
- return;
+ perror("signal");
+ exit(1);
}
- break;
- default:
- throw std::invalid_argument("Jacktrip Mode undefined");
- break;
- }
+#endif
+ // Check if ports are already binded by another process on this machine
+ // ------------------------------------------------------------------
+ if (gVerboseFlag) std::cout << "step 1" << std::endl;
- // Start Threads
- mAudioInterface->startProcess();
+ if (gVerboseFlag) std::cout << " JackTrip:startProcess before checkIfPortIsBinded(mReceiverBindPort)" << std::endl;
+#if defined __WIN_32__
+ //cc fixed windows crash with this print statement!
+ qDebug() << "before mJackTrip->startProcess"
+ << mReceiverBindPort<< mSenderBindPort;
+ // msleep(2000);
+#endif
+ checkIfPortIsBinded(mReceiverBindPort);
+ if (gVerboseFlag) std::cout << " JackTrip:startProcess before checkIfPortIsBinded(mSenderBindPort)" << std::endl;
+ checkIfPortIsBinded(mSenderBindPort);
+ // Set all classes and parameters
+ // ------------------------------
+ if (gVerboseFlag) std::cout << " JackTrip:startProcess before setupAudio" << std::endl;
+ setupAudio(
+ #ifdef WAIRTOMASTER // wair
+ ID
+ #endif // endwhere
+ );
+ //cc redundant with instance creator createHeader(mPacketHeaderType); next line fixme
+ createHeader(mPacketHeaderType);
+ setupDataProtocol();
+ setupRingBuffers();
+ // Connect Signals and Slots
+ // -------------------------
+ QObject::connect(mPacketHeader, SIGNAL(signalError(const char*)),
+ this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
+ QObject::connect(mDataProtocolReceiver, SIGNAL(signalReceivedConnectionFromPeer()),
+ this, SLOT(slotReceivedConnectionFromPeer()),
+ Qt::QueuedConnection);
+ QObject::connect(this, SIGNAL(signalUdpTimeOut()),
+ this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
+
+ //QObject::connect(mDataProtocolSender, SIGNAL(signalError(const char*)),
+ // this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
+ //QObject::connect(mDataProtocolReceiver, SIGNAL(signalError(const char*)),
+ // this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
+
+ // Start the threads for the specific mode
+ // ---------------------------------------
+ switch ( mJackTripMode )
+ {
+ case CLIENT :
+ if (gVerboseFlag) std::cout << "step 2c client only" << std::endl;
+ if (gVerboseFlag) std::cout << " JackTrip:startProcess case CLIENT before clientStart" << std::endl;
+ clientStart();
+ break;
+ case SERVER :
+ if (gVerboseFlag) std::cout << "step 2s server only" << std::endl;
+ if (gVerboseFlag) std::cout << " JackTrip:startProcess case SERVER before serverStart" << std::endl;
+ serverStart();
+ break;
+ case CLIENTTOPINGSERVER :
+ if (gVerboseFlag) std::cout << "step 2C client only" << std::endl;
+ if (gVerboseFlag) std::cout << " JackTrip:startProcess case CLIENTTOPINGSERVER before clientPingToServerStart" << std::endl;
+ if ( clientPingToServerStart() == -1 ) { // if error on server start (-1) we return inmediatly
+ mTcpConnectionError = true;
+ slotStopProcesses();
+ return;
+ }
+ break;
+ case SERVERPINGSERVER :
+ if (gVerboseFlag) std::cout << "step 2S server only (same as 2s)" << std::endl;
+ if (gVerboseFlag) std::cout << " JackTrip:startProcess case SERVERPINGSERVER before serverStart" << std::endl;
+ if ( serverStart(true) == -1 ) { // if error on server start (-1) we return inmediatly
+ slotStopProcesses();
+ return;
+ }
+ break;
+ default:
+ throw std::invalid_argument("Jacktrip Mode undefined");
+ break;
+ }
- for (int i = 0; i < mProcessPlugins.size(); ++i) {
- mAudioInterface->appendProcessPlugin(mProcessPlugins[i]);
- }
- mAudioInterface->connectDefaultPorts();
- mDataProtocolReceiver->start();
- QThread::msleep(1);
- mDataProtocolSender->start();
+ // Have the threads share a single socket that operates at full duplex.
+#if defined (__WIN_32__)
+ SOCKET sock_fd = INVALID_SOCKET;
+#else
+ int sock_fd = -1;
+#endif
+ mDataProtocolReceiver->setSocket(sock_fd);
+ mDataProtocolSender->setSocket(sock_fd);
+
+ // Start Threads
+ if (gVerboseFlag) std::cout << " JackTrip:startProcess before mDataProtocolReceiver->start" << std::endl;
+ mDataProtocolReceiver->start();
+ QThread::msleep(1);
+ if (gVerboseFlag) std::cout << " JackTrip:startProcess before mDataProtocolSender->start" << std::endl;
+ mDataProtocolSender->start();
+ /*
+ * changed order so that audio starts after receiver and sender
+ * because UdpDataProtocol:run0 before setRealtimeProcessPriority()
+ * causes an audio hiccup from jack JackPosixSemaphore::TimedWait err = Interrupted system call
+ * new QThread::msleep(1);
+ * to allow sender to start
+ */
+ QThread::msleep(1);
+ if (gVerboseFlag) std::cout << "step 5" << std::endl;
+ if (gVerboseFlag) std::cout << " JackTrip:startProcess before mAudioInterface->startProcess" << std::endl;
+ mAudioInterface->startProcess();
+
+ for (int i = 0; i < mProcessPlugins.size(); ++i) {
+ mAudioInterface->appendProcessPlugin(mProcessPlugins[i]);
+ }
+ if (mConnectDefaultAudioPorts) { mAudioInterface->connectDefaultPorts(); }
}
//*******************************************************************************
void JackTrip::stop()
{
- // Stop The Sender
- mDataProtocolSender->stop();
- mDataProtocolSender->wait();
+ // Stop The Sender
+ mDataProtocolSender->stop();
+ mDataProtocolSender->wait();
- // Stop The Receiver
- mDataProtocolReceiver->stop();
- mDataProtocolReceiver->wait();
+ // Stop The Receiver
+ mDataProtocolReceiver->stop();
+ mDataProtocolReceiver->wait();
- // Stop the audio processes
- //mAudioInterface->stopProcess();
- closeAudio();
+ // Stop the audio processes
+ //mAudioInterface->stopProcess();
+ closeAudio();
- cout << "JackTrip Processes STOPPED!" << endl;
- cout << gPrintSeparator << endl;
+ cout << "JackTrip Processes STOPPED!" << endl;
+ cout << gPrintSeparator << endl;
- // Emit the jack stopped signal
- emit signalProcessesStopped();
+ // Emit the jack stopped signal
+ emit signalProcessesStopped();
}
//*******************************************************************************
void JackTrip::waitThreads()
{
- mDataProtocolSender->wait();
- mDataProtocolReceiver->wait();
+ mDataProtocolSender->wait();
+ mDataProtocolReceiver->wait();
}
//*******************************************************************************
void JackTrip::clientStart() throw(std::invalid_argument)
{
- // For the Client mode, the peer (or server) address has to be specified by the user
- if ( mPeerAddress.isEmpty() ) {
- throw std::invalid_argument("Peer Address has to be set if you run in CLIENT mode");
- }
- else {
- mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
- mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().data() );
- cout << "Peer Address set to: " << mPeerAddress.toStdString() << std::endl;
- cout << gPrintSeparator << endl;
- }
+ // For the Client mode, the peer (or server) address has to be specified by the user
+ if ( mPeerAddress.isEmpty() ) {
+ throw std::invalid_argument("Peer Address has to be set if you run in CLIENT mode");
+ }
+ else {
+ mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
+ mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().data() );
+ cout << "Peer Address set to: " << mPeerAddress.toStdString() << std::endl;
+ cout << gPrintSeparator << endl;
+ }
}
//*******************************************************************************
-int JackTrip::serverStart(bool timeout, int udpTimeout)
- throw(std::invalid_argument, std::runtime_error)
+int JackTrip::serverStart(bool timeout, int udpTimeout) // udpTimeout unused
+throw(std::invalid_argument, std::runtime_error)
{
- // Set the peer address
- if ( !mPeerAddress.isEmpty() ) {
- std::cout << "WARNING: SERVER mode: Peer Address was set but will be deleted." << endl;
- //throw std::invalid_argument("Peer Address has to be set if you run in CLIENT mode");
- mPeerAddress.clear();
- //return;
- }
+ // Set the peer address
+ if ( !mPeerAddress.isEmpty() ) {
+ if (gVerboseFlag) std::cout << "WARNING: SERVER mode: Peer Address was set but will be deleted." << endl;
+ //throw std::invalid_argument("Peer Address has to be set if you run in CLIENT mode");
+ mPeerAddress.clear();
+ //return;
+ }
- // Get the client address when it connects
- cout << "Waiting for Connection From Client..." << endl;
- QHostAddress peerHostAddress;
- uint16_t peer_port;
- QUdpSocket UdpSockTemp;// Create socket to wait for client
+ // Get the client address when it connects
+ QHostAddress peerHostAddress;
+ uint16_t peer_port;
+ if (gVerboseFlag) std::cout << "JackTrip:serverStart before QUdpSocket UdpSockTemp" << std::endl;
+ QUdpSocket UdpSockTemp;// Create socket to wait for client
- // Bind the socket
- if ( !UdpSockTemp.bind(QHostAddress::Any, mReceiverBindPort,
- QUdpSocket::DefaultForPlatform) )
- {
- std::cerr << "in JackTrip: Could not bind UDP socket. It may be already binded." << endl;
- throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
- }
- // Listen to client
- int sleepTime = 100; // ms
- int elapsedTime = 0;
- if (timeout) {
- while ( (!UdpSockTemp.hasPendingDatagrams()) && (elapsedTime <= udpTimeout) ) {
- if (mStopped == true) { emit signalUdpTimeOut(); UdpSockTemp.close(); return -1; }
- QThread::msleep(sleepTime);
- elapsedTime += sleepTime;
- }
- if (!UdpSockTemp.hasPendingDatagrams()) {
- emit signalUdpTimeOut();
- cout << "JackTrip Server Timed Out!" << endl;
- return -1;
+ if (gVerboseFlag) std::cout << "JackTrip:serverStart before UdpSockTemp.bind(Any)" << std::endl;
+ // Bind the socket
+ if ( !UdpSockTemp.bind(QHostAddress::Any, mReceiverBindPort,
+ QUdpSocket::DefaultForPlatform) )
+ {
+ std::cerr << "in JackTrip: Could not bind UDP socket. It may be already binded." << endl;
+ throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
}
- } else {
- while ( !UdpSockTemp.hasPendingDatagrams() ) {
- if (mStopped == true) { emit signalUdpTimeOut(); return -1; }
- QThread::msleep(sleepTime);
+ // Listen to client
+ int sleepTime = 100; // ms
+ int elapsedTime = 0;
+ if (timeout) {
+ while ( (!UdpSockTemp.hasPendingDatagrams()) && (elapsedTime <= udpTimeout) ) {
+ if (mStopped == true) { emit signalUdpTimeOut(); UdpSockTemp.close(); return -1; }
+ QThread::msleep(sleepTime);
+ elapsedTime += sleepTime;
+ }
+ if (!UdpSockTemp.hasPendingDatagrams()) {
+ emit signalUdpTimeOut();
+ cout << "JackTrip Server Timed Out!" << endl;
+ return -1;
+ }
+ } else {
+ if (gVerboseFlag) std::cout << "JackTrip:serverStart before !UdpSockTemp.hasPendingDatagrams()" << std::endl;
+ cout << "Waiting for Connection From a Client..." << endl;
+ while ( !UdpSockTemp.hasPendingDatagrams() ) {
+ if (mStopped == true) { emit signalUdpTimeOut(); return -1; }
+ if (gVerboseFlag) std::cout << sleepTime << "ms " << std::flush;
+ QThread::msleep(sleepTime);
+ }
}
- }
- char buf[1];
- // set client address
- UdpSockTemp.readDatagram(buf, 1, &peerHostAddress, &peer_port);
- UdpSockTemp.close(); // close the socket
+ // char buf[1];
+ // // set client address
+ // UdpSockTemp.readDatagram(buf, 1, &peerHostAddress, &peer_port);
+ // UdpSockTemp.close(); // close the socket
+
+ // IPv6 addition from fyfe
+ // Get the datagram size to avoid problems with IPv6
+ qint64 datagramSize = UdpSockTemp.pendingDatagramSize();
+ char buf[datagramSize];
+ // set client address
+ UdpSockTemp.readDatagram(buf, datagramSize, &peerHostAddress, &peer_port);
+ UdpSockTemp.close(); // close the socket
- mPeerAddress = peerHostAddress.toString();
- cout << "Client Connection Received from IP : "
- << qPrintable(mPeerAddress) << endl;
- cout << gPrintSeparator << endl;
+ // Check for mapped IPv4->IPv6 addresses that look like ::ffff:x.x.x.x
+ if (peerHostAddress.protocol() == QAbstractSocket::IPv6Protocol) {
+ bool mappedIPv4;
+ uint32_t address = peerHostAddress.toIPv4Address(&mappedIPv4);
+ // If the IPv4 address is mapped to IPv6, convert it to IPv4
+ if (mappedIPv4) {
+ QHostAddress ipv4Address = QHostAddress(address);
+ mPeerAddress = ipv4Address.toString();
+ } else {
+ mPeerAddress = peerHostAddress.toString();
+ }
+ }
+ else {
+ mPeerAddress = peerHostAddress.toString();
+ }
- // Set the peer address to send packets (in the protocol sender)
- mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().constData() );
- mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().constData() );
- // We reply to the same port the peer sent the packets from
- // This way we can go through NAT
- // Because of the NAT traversal scheme, the portn need to be
- // "symetric", e.g.:
- // from Client to Server : src = 4474, dest = 4464
- // from Server to Client : src = 4464, dest = 4474
- mDataProtocolSender->setPeerPort(peer_port);
- mDataProtocolReceiver->setPeerPort(peer_port);
- setPeerPorts(peer_port);
- return 0;
+ // Set the peer address to send packets (in the protocol sender)
+ if (gVerboseFlag) std::cout << "JackTrip:serverStart before mDataProtocolSender->setPeerAddress()" << std::endl;
+ mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().constData() );
+ if (gVerboseFlag) std::cout << "JackTrip:serverStart before mDataProtocolReceiver->setPeerAddress()" << std::endl;
+ mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().constData() );
+ // We reply to the same port the peer sent the packets from
+ // This way we can go through NAT
+ // Because of the NAT traversal scheme, the portn need to be
+ // "symetric", e.g.:
+ // from Client to Server : src = 4474, dest = 4464
+ // from Server to Client : src = 4464, dest = 4474
+ // no -- all are the same -- 4464
+ if (gVerboseFlag) std::cout << "JackTrip:serverStart before setting all peer_port instances to " << peer_port << std::endl;
+ mDataProtocolSender->setPeerPort(peer_port);
+ mDataProtocolReceiver->setPeerPort(peer_port);
+ setPeerPorts(peer_port);
+ return 0;
}
//*******************************************************************************
int JackTrip::clientPingToServerStart() throw(std::invalid_argument)
{
- //mConnectionMode = JackTrip::KSTRONG;
- //mConnectionMode = JackTrip::JAMTEST;
-
- // Set Peer (server in this case) address
- // --------------------------------------
- // For the Client mode, the peer (or server) address has to be specified by the user
- if ( mPeerAddress.isEmpty() ) {
- throw std::invalid_argument("Peer Address has to be set if you run in CLIENTTOPINGSERVER mode");
- return -1;
- }
+ //mConnectionMode = JackTrip::KSTRONG;
+ //mConnectionMode = JackTrip::JAMTEST;
+
+ // Set Peer (server in this case) address
+ // --------------------------------------
+ // For the Client mode, the peer (or server) address has to be specified by the user
+ if ( mPeerAddress.isEmpty() ) {
+ throw std::invalid_argument("Peer Address has to be set if you run in CLIENTTOPINGSERVER mode");
+ return -1;
+ }
- // Creat Socket Objects
- // --------------------
- QTcpSocket tcpClient;
- QHostAddress serverHostAddress;
- serverHostAddress.setAddress(mPeerAddress);
-
- // Connect Socket to Server and wait for response
- // ----------------------------------------------
- tcpClient.connectToHost(serverHostAddress, mTcpServerPort);
- cout << "Connecting to TCP Server..." << endl;
- if (!tcpClient.waitForConnected()) {
- std::cerr << "TCP Socket ERROR: " << tcpClient.errorString().toStdString() << endl;
- //std::exit(1);
- return -1;
- }
- cout << "TCP Socket Connected to Server!" << endl;
- emit signalTcpClientConnected();
+ // Create Socket Objects
+ // --------------------
+ QTcpSocket tcpClient;
+ QHostAddress serverHostAddress;
+ if (!serverHostAddress.setAddress(mPeerAddress)) {
+ QHostInfo info = QHostInfo::fromName(mPeerAddress);
+ if (!info.addresses().isEmpty()) {
+ // use the first IP address
+ serverHostAddress = info.addresses().first();
+ }
+ }
- // Send Client Port Number to Server
- // ---------------------------------
- char port_buf[sizeof(mReceiverBindPort)];
- std::memcpy(port_buf, &mReceiverBindPort, sizeof(mReceiverBindPort));
+ // Connect Socket to Server and wait for response
+ // ----------------------------------------------
+ tcpClient.connectToHost(serverHostAddress, mTcpServerPort);
+ if (gVerboseFlag) cout << "Connecting to TCP Server..." << endl;
+ if (!tcpClient.waitForConnected()) {
+ std::cerr << "TCP Socket ERROR: " << tcpClient.errorString().toStdString() << endl;
+ //std::exit(1);
+ return -1;
+ }
+ if (gVerboseFlag) cout << "TCP Socket Connected to Server!" << endl;
+ emit signalTcpClientConnected();
- tcpClient.write(port_buf, sizeof(mReceiverBindPort));
- while ( tcpClient.bytesToWrite() > 0 ) {
- tcpClient.waitForBytesWritten(-1);
- }
- cout << "Port sent to Client" << endl;
-
- // Read the size of the package
- // ----------------------------
- cout << "Reading UDP port from Server..." << endl;
- while (tcpClient.bytesAvailable() < (int)sizeof(uint16_t)) {
- if (!tcpClient.waitForReadyRead()) {
- std::cerr << "TCP Socket ERROR: " << tcpClient.errorString().toStdString() << endl;
- //std::exit(1);
- return -1;
+ // Send Client Port Number to Server
+ // ---------------------------------
+ char port_buf[sizeof(mReceiverBindPort)];
+ std::memcpy(port_buf, &mReceiverBindPort, sizeof(mReceiverBindPort));
+
+ tcpClient.write(port_buf, sizeof(mReceiverBindPort));
+ while ( tcpClient.bytesToWrite() > 0 ) {
+ tcpClient.waitForBytesWritten(-1);
}
- }
- cout << "Ready To Read From Socket!" << endl;
-
- // Read UDP Port Number from Server
- // --------------------------------
- uint32_t udp_port;
- int size = sizeof(udp_port);
- //char port_buf[size];
- tcpClient.read(port_buf, size);
- std::memcpy(&udp_port, port_buf, size);
- //cout << "Received UDP Port Number: " << udp_port << endl;
-
- // Close the TCP Socket
- // --------------------
- tcpClient.close(); // Close the socket
- //cout << "TCP Socket Closed!" << endl;
- cout << "Connection Succesfull!" << endl;
-
- // Set with the received UDP port
- // ------------------------------
- setPeerPorts(udp_port);
- mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().data() );
- mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
- mDataProtocolSender->setPeerPort(udp_port);
- mDataProtocolReceiver->setPeerPort(udp_port);
- cout << "Server Address set to: " << mPeerAddress.toStdString() << " Port: " << udp_port << std::endl;
- cout << gPrintSeparator << endl;
- return 0;
+ if (gVerboseFlag) cout << "Port sent to Server" << endl;
+
+ // Read the size of the package
+ // ----------------------------
+ if (gVerboseFlag) cout << "Reading UDP port from Server..." << endl;
+ while (tcpClient.bytesAvailable() < (int)sizeof(uint16_t)) {
+ if (!tcpClient.waitForReadyRead()) {
+ std::cerr << "TCP Socket ERROR: " << tcpClient.errorString().toStdString() << endl;
+ //std::exit(1);
+ return -1;
+ }
+ }
+ if (gVerboseFlag) cout << "Ready To Read From Socket!" << endl;
+
+ // Read UDP Port Number from Server
+ // --------------------------------
+ uint32_t udp_port;
+ int size = sizeof(udp_port);
+ //char port_buf[size];
+ tcpClient.read(port_buf, size);
+ std::memcpy(&udp_port, port_buf, size);
+ //cout << "Received UDP Port Number: " << udp_port << endl;
+
+ // Close the TCP Socket
+ // --------------------
+ tcpClient.close(); // Close the socket
+ //cout << "TCP Socket Closed!" << endl;
+ if (gVerboseFlag) cout << "Connection Succesfull!" << endl;
+
+ // Set with the received UDP port
+ // ------------------------------
+ setPeerPorts(udp_port);
+ mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().data() );
+ mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
+ mDataProtocolSender->setPeerPort(udp_port);
+ mDataProtocolReceiver->setPeerPort(udp_port);
+ cout << "Server Address set to: " << mPeerAddress.toStdString() << " Port: " << udp_port << std::endl;
+ cout << gPrintSeparator << endl;
+ return 0;
- /*
+ /*
else {
// Set the peer address
mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
cout << "Server port now set to: " << server_port << endl;
cout << gPrintSeparator << endl;
mDataProtocolSender->setPeerPort(server_port);
-
+
// Start Threads
//mAudioInterface->connectDefaultPorts();
mDataProtocolSender->start();
//*******************************************************************************
void JackTrip::createHeader(const DataProtocol::packetHeaderTypeT headertype)
{
- delete mPacketHeader; //Just in case it has already been allocated
- switch (headertype) {
- case DataProtocol::DEFAULT :
- mPacketHeader = new DefaultHeader(this);
- break;
- case DataProtocol::JAMLINK :
- mPacketHeader = new JamLinkHeader(this);
- break;
- case DataProtocol::EMPTY :
- mPacketHeader = new EmptyHeader(this);
- break;
- default :
- throw std::invalid_argument("Undefined Header Type");
- break;
- }
+ delete mPacketHeader; //Just in case it has already been allocated
+ switch (headertype) {
+ case DataProtocol::DEFAULT :
+ mPacketHeader = new DefaultHeader(this);
+ break;
+ case DataProtocol::JAMLINK :
+ mPacketHeader = new JamLinkHeader(this);
+ break;
+ case DataProtocol::EMPTY :
+ mPacketHeader = new EmptyHeader(this);
+ break;
+ default :
+ throw std::invalid_argument("Undefined Header Type");
+ break;
+ }
}
//*******************************************************************************
void JackTrip::putHeaderInPacket(int8_t* full_packet, int8_t* audio_packet)
{
- mPacketHeader->fillHeaderCommonFromAudio();
- mPacketHeader->putHeaderInPacket(full_packet);
-
- int8_t* audio_part;
- audio_part = full_packet + mPacketHeader->getHeaderSizeInBytes();
- //std::memcpy(audio_part, audio_packet, mAudioInterface->getBufferSizeInBytes());
- //std::memcpy(audio_part, audio_packet, mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
- std::memcpy(audio_part, audio_packet, getTotalAudioPacketSizeInBytes());
+ mPacketHeader->fillHeaderCommonFromAudio();
+ mPacketHeader->putHeaderInPacket(full_packet);
+
+ int8_t* audio_part;
+ audio_part = full_packet + mPacketHeader->getHeaderSizeInBytes();
+ //std::memcpy(audio_part, audio_packet, mAudioInterface->getBufferSizeInBytes());
+ //std::memcpy(audio_part, audio_packet, mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
+ std::memcpy(audio_part, audio_packet, getTotalAudioPacketSizeInBytes());
}
//*******************************************************************************
int JackTrip::getPacketSizeInBytes()
{
- //return (mAudioInterface->getBufferSizeInBytes() + mPacketHeader->getHeaderSizeInBytes());
- //return (mAudioInterface->getSizeInBytesPerChannel() * mNumChans +
- //mPacketHeader->getHeaderSizeInBytes());
- return (getTotalAudioPacketSizeInBytes() +
- mPacketHeader->getHeaderSizeInBytes());
+ //return (mAudioInterface->getBufferSizeInBytes() + mPacketHeader->getHeaderSizeInBytes());
+ //return (mAudioInterface->getSizeInBytesPerChannel() * mNumChans +
+ //mPacketHeader->getHeaderSizeInBytes());
+ return (getTotalAudioPacketSizeInBytes() +
+ mPacketHeader->getHeaderSizeInBytes());
}
//*******************************************************************************
void JackTrip::parseAudioPacket(int8_t* full_packet, int8_t* audio_packet)
{
- int8_t* audio_part;
- audio_part = full_packet + mPacketHeader->getHeaderSizeInBytes();
- //std::memcpy(audio_packet, audio_part, mAudioInterface->getBufferSizeInBytes());
- //std::memcpy(audio_packet, audio_part, mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
- std::memcpy(audio_packet, audio_part, getTotalAudioPacketSizeInBytes());
+ int8_t* audio_part;
+ audio_part = full_packet + mPacketHeader->getHeaderSizeInBytes();
+ //std::memcpy(audio_packet, audio_part, mAudioInterface->getBufferSizeInBytes());
+ //std::memcpy(audio_packet, audio_part, mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
+ std::memcpy(audio_packet, audio_part, getTotalAudioPacketSizeInBytes());
}
//*******************************************************************************
void JackTrip::checkPeerSettings(int8_t* full_packet)
{
- mPacketHeader->checkPeerSettings(full_packet);
+ mPacketHeader->checkPeerSettings(full_packet);
}
//*******************************************************************************
void JackTrip::checkIfPortIsBinded(int port)
{
- QUdpSocket UdpSockTemp;// Create socket to wait for client
-
- // Bind the socket
- if ( !UdpSockTemp.bind(QHostAddress::Any, port, QUdpSocket::DontShareAddress) )
- {
+ QUdpSocket UdpSockTemp;// Create socket to wait for client
+ // Bind the socket
+ //cc if ( !UdpSockTemp.bind(QHostAddress::AnyIPv4, port, QUdpSocket::DontShareAddress) )
+ if ( !UdpSockTemp.bind(QHostAddress::Any, port,
+ QUdpSocket::DontShareAddress) )
+ {
+ UdpSockTemp.close(); // close the socket
+ throw std::runtime_error(
+ "Could not bind UDP socket. It may already be binded by another process on your machine. Try using a different port number");
+ }
UdpSockTemp.close(); // close the socket
- throw std::runtime_error(
- "Could not bind UDP socket. It may already be binded by another process on your machine. Try using a different port number");
- }
- UdpSockTemp.close(); // close the socket
}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
class JackTrip : public QThread
{
- Q_OBJECT;
+ Q_OBJECT;
public:
- //----------ENUMS------------------------------------------
- /// \brief Enum for the data Protocol. At this time only UDP is implemented
- enum dataProtocolT {
- UDP, ///< Use UDP (User Datagram Protocol)
- TCP, ///< <B>NOT IMPLEMENTED</B>: Use TCP (Transmission Control Protocol)
- SCTP ///< <B>NOT IMPLEMENTED</B>: Use SCTP (Stream Control Transmission Protocol)
- };
-
- /// \brief Enum for the JackTrip mode
- enum jacktripModeT {
- SERVER, ///< Run in Server Mode
- CLIENT, ///< Run in Client Mode
- CLIENTTOPINGSERVER, ///< Client of the Ping Server Mode
- SERVERPINGSERVER ///< Server of the MultiThreaded JackTrip
- };
-
- /// \brief Enum for the JackTrip Underrun Mode, when packets
- enum underrunModeT {
- WAVETABLE, ///< Loops on the last received packet
- ZEROS ///< Set new buffers to zero if there are no new ones
- };
-
- /// \brief Enum for Audio Interface Mode
- enum audiointerfaceModeT {
- JACK, ///< Jack Mode
- RTAUDIO ///< RtAudio Mode
- };
-
- /// \brief Enum for Connection Mode (useful for connections to MultiClient Server)
- enum connectionModeT {
- NORMAL, ///< Normal Mode
- KSTRONG, ///< Karplus Strong
- JAMTEST ///< Karplus Strong
- };
- //---------------------------------------------------------
-
-
- /** \brief The class Constructor with Default Parameters
+ //----------ENUMS------------------------------------------
+ /// \brief Enum for the data Protocol. At this time only UDP is implemented
+ enum dataProtocolT {
+ UDP, ///< Use UDP (User Datagram Protocol)
+ TCP, ///< <B>NOT IMPLEMENTED</B>: Use TCP (Transmission Control Protocol)
+ SCTP ///< <B>NOT IMPLEMENTED</B>: Use SCTP (Stream Control Transmission Protocol)
+ };
+
+ /// \brief Enum for the JackTrip mode
+ enum jacktripModeT {
+ SERVER, ///< Run in Server Mode
+ CLIENT, ///< Run in Client Mode
+ CLIENTTOPINGSERVER, ///< Client of the Ping Server Mode
+ SERVERPINGSERVER ///< Server of the MultiThreaded JackTrip
+ };
+
+ /// \brief Enum for the JackTrip Underrun Mode, when packets
+ enum underrunModeT {
+ WAVETABLE, ///< Loops on the last received packet
+ ZEROS ///< Set new buffers to zero if there are no new ones
+ };
+
+ /// \brief Enum for Audio Interface Mode
+ enum audiointerfaceModeT {
+ JACK, ///< Jack Mode
+ RTAUDIO ///< RtAudio Mode
+ };
+
+ /// \brief Enum for Connection Mode (in packet header)
+ enum connectionModeT {
+ NORMAL, ///< Normal Mode
+ KSTRONG, ///< Karplus Strong
+ JAMTEST ///< Karplus Strong
+ };
+
+ /// \brief Enum for Hub Server Audio Connection Mode (connections to hub server are automatically patched in Jack)
+ enum hubConnectionModeT {
+ SERVERTOCLIENT, ///< Normal Mode, Sever to All Clients (but not client to any client)
+ CLIENTECHO, ///< Client Echo (client self-to-self)
+ CLIENTFOFI, ///< Client Fan Out to Clients and Fan In from Clients (but not self-to-self)
+ RESERVEDMATRIX, ///< Reserved for custom patch matrix (for TUB ensemble)
+ FULLMIX ///< Client Fan Out to Clients and Fan In from Clients (including self-to-self)
+ };
+ //---------------------------------------------------------
+
+
+ /** \brief The class Constructor with Default Parameters
* \param JacktripMode JackTrip::CLIENT or JackTrip::SERVER
* \param DataProtocolType JackTrip::dataProtocolT
* \param NumChans Number of Audio Channels (same for inputs and outputs)
* \param AudioBitResolution Audio Sample Resolutions in bits
* \param redundancy redundancy factor for network data
*/
- JackTrip(jacktripModeT JacktripMode = CLIENT,
- dataProtocolT DataProtocolType = UDP,
- int NumChans = gDefaultNumInChannels,
- int BufferQueueLength = gDefaultQueueLength,
- unsigned int redundancy = gDefaultRedundancy,
- AudioInterface::audioBitResolutionT AudioBitResolution =
- AudioInterface::BIT16,
- DataProtocol::packetHeaderTypeT PacketHeaderType =
- DataProtocol::DEFAULT,
- underrunModeT UnderRunMode = WAVETABLE,
- int receiver_bind_port = gDefaultPort,
- int sender_bind_port = gDefaultPort,
- int receiver_peer_port = gDefaultPort,
- int sender_peer_port = gDefaultPort);
-
- /// \brief The class destructor
- virtual ~JackTrip();
-
- /// \brief Starting point for the thread
- virtual void run() {}
-
- /// \brief Set the Peer Address for jacktripModeT::CLIENT mode only
- virtual void setPeerAddress(const char* PeerHostOrIP);
-
- /** \brief Append a process plugin. Processes will be appended in order
+ JackTrip(jacktripModeT JacktripMode = CLIENT,
+ dataProtocolT DataProtocolType = UDP,
+ int NumChans = gDefaultNumInChannels,
+ #ifdef WAIR // wair
+ int NumNetRevChans = 0,
+ #endif // endwhere
+ int BufferQueueLength = gDefaultQueueLength,
+ unsigned int redundancy = gDefaultRedundancy,
+ AudioInterface::audioBitResolutionT AudioBitResolution =
+ AudioInterface::BIT16,
+ DataProtocol::packetHeaderTypeT PacketHeaderType =
+ DataProtocol::DEFAULT,
+ underrunModeT UnderRunMode = WAVETABLE,
+ int receiver_bind_port = gDefaultPort,
+ int sender_bind_port = gDefaultPort,
+ int receiver_peer_port = gDefaultPort,
+ int sender_peer_port = gDefaultPort);
+
+ /// \brief The class destructor
+ virtual ~JackTrip();
+
+ /// \brief Starting point for the thread
+ virtual void run() {
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->run" << std::endl;
+ }
+
+ /// \brief Set the Peer Address for jacktripModeT::CLIENT mode only
+ virtual void setPeerAddress(const char* PeerHostOrIP);
+
+ /** \brief Append a process plugin. Processes will be appended in order
* \param plugin Pointer to ProcessPlugin Class
*/
- //void appendProcessPlugin(const std::tr1::shared_ptr<ProcessPlugin> plugin);
- virtual void appendProcessPlugin(ProcessPlugin* plugin);
-
- /// \brief Start the processing threads
- virtual void startProcess() throw(std::invalid_argument);
-
- /// \brief Stop the processing threads
- virtual void stop();
-
- /// \brief Wait for all the threads to finish. This functions is used when JackTrip is
- /// run as a thread
- virtual void waitThreads();
-
- /// \brief Check if UDP port is already binded
- /// \param port Port number
- virtual void checkIfPortIsBinded(int port);
-
- //------------------------------------------------------------------------------------
- /// \name Getters and Setters Methods to change parameters after construction
- //@{
- //
- /// \brief Sets (override) JackTrip Mode after construction
- virtual void setJackTripMode(jacktripModeT JacktripMode)
- { mJackTripMode = JacktripMode; }
- /// \brief Sets (override) DataProtocol Type after construction
- virtual void setDataProtocoType(dataProtocolT DataProtocolType)
- { mDataProtocol = DataProtocolType; }
- /// \brief Sets the Packet header type
- virtual void setPacketHeaderType(DataProtocol::packetHeaderTypeT PacketHeaderType)
- {
- mPacketHeaderType = PacketHeaderType;
- delete mPacketHeader;
- mPacketHeader = NULL;
- createHeader(mPacketHeaderType);
- }
- /// \brief Sets (override) Buffer Queue Length Mode after construction
- virtual void setBufferQueueLength(int BufferQueueLength)
- { mBufferQueueLength = BufferQueueLength; }
- /// \brief Sets (override) Audio Bit Resolution after construction
- virtual void setAudioBitResolution(AudioInterface::audioBitResolutionT AudioBitResolution)
- { mAudioBitResolution = AudioBitResolution; }
- /// \brief Sets (override) Underrun Mode
- virtual void setUnderRunMode(underrunModeT UnderRunMode)
- { mUnderRunMode = UnderRunMode; }
- /// \brief Sets port numbers for the local and peer machine.
- /// Receive port is <tt>port</tt>
- virtual void setAllPorts(int port)
- {
- mReceiverBindPort = port;
- mSenderPeerPort = port;
- mSenderBindPort = port;
- mReceiverPeerPort = port;
- }
- /// \brief Sets port numbers to bind in RECEIVER and SENDER sockets.
- virtual void setBindPorts(int port)
- {
- mReceiverBindPort = port;
- mSenderBindPort = port;
- }
- /// \brief Sets port numbers for the peer (remote) machine.
- virtual void setPeerPorts(int port)
- {
- mSenderPeerPort = port;
- mReceiverPeerPort = port;
- }
- /// \brief Set Client Name to something different that the default (JackTrip)
- virtual void setClientName(const char* ClientName)
- { mJackClientName = ClientName; }
- /// \brief Set the number of audio channels
- virtual void setNumChannels(int num_chans)
- { mNumChans = num_chans; }
-
- virtual int getReceiverBindPort() const
- { return mReceiverBindPort; }
- virtual int getSenderPeerPort() const
- { return mSenderPeerPort; }
- virtual int getSenderBindPort() const
- { return mSenderBindPort; }
- virtual int getReceiverPeerPort() const
- { return mReceiverPeerPort; }
-
- virtual DataProtocol* getDataProtocolSender() const
- { return mDataProtocolSender; }
- virtual DataProtocol* getDataProtocolReceiver() const
- { return mDataProtocolReceiver; }
- virtual void setDataProtocolSender(DataProtocol* const DataProtocolSender)
- { mDataProtocolSender = DataProtocolSender; }
- virtual void setDataProtocolReceiver(DataProtocol* const DataProtocolReceiver)
- { mDataProtocolReceiver = DataProtocolReceiver; }
-
- virtual RingBuffer* getSendRingBuffer() const
- { return mSendRingBuffer; }
- virtual RingBuffer* getReceiveRingBuffer() const
- { return mReceiveRingBuffer; }
- virtual void setSendRingBuffer(RingBuffer* const SendRingBuffer)
- { mSendRingBuffer = SendRingBuffer; }
- virtual void setReceiveRingBuffer(RingBuffer* const ReceiveRingBuffer)
- { mReceiveRingBuffer = ReceiveRingBuffer; }
-
- virtual void setPacketHeader(PacketHeader* const PacketHeader)
- { mPacketHeader = PacketHeader; }
-
- virtual int getRingBuffersSlotSize()
- { return getTotalAudioPacketSizeInBytes(); }
-
- virtual void setAudiointerfaceMode(JackTrip::audiointerfaceModeT audiointerface_mode)
- { mAudiointerfaceMode = audiointerface_mode; }
- virtual void setAudioInterface(AudioInterface* const AudioInterface)
- { mAudioInterface = AudioInterface; }
-
-
- void setSampleRate(uint32_t sample_rate)
- { mSampleRate = sample_rate; }
- void setAudioBufferSizeInSamples(uint32_t buf_size)
- { mAudioBufferSize = buf_size; }
-
- JackTrip::connectionModeT getConnectionMode() const
- { return mConnectionMode; }
- void setConnectionMode(JackTrip::connectionModeT connection_mode)
- { mConnectionMode = connection_mode; }
-
- JackTrip::jacktripModeT getJackTripMode() const
- { return mJackTripMode; }
-
- QString getPeerAddress() const
- { return mPeerAddress; }
-
- bool receivedConnectionFromPeer()
- { return mReceivedConnection; }
-
- bool tcpConnectionError()
- { return mTcpConnectionError; }
- //@}
- //------------------------------------------------------------------------------------
-
-
- //------------------------------------------------------------------------------------
- /// \name Mediator Functions
- //@{
- /// \todo Document all these functions
- virtual void createHeader(const DataProtocol::packetHeaderTypeT headertype);
- void putHeaderInPacket(int8_t* full_packet, int8_t* audio_packet);
- virtual int getPacketSizeInBytes();
- void parseAudioPacket(int8_t* full_packet, int8_t* audio_packet);
- virtual void sendNetworkPacket(const int8_t* ptrToSlot)
- { mSendRingBuffer->insertSlotNonBlocking(ptrToSlot); }
- virtual void receiveNetworkPacket(int8_t* ptrToReadSlot)
- { mReceiveRingBuffer->readSlotNonBlocking(ptrToReadSlot); }
- virtual void readAudioBuffer(int8_t* ptrToReadSlot)
- { mSendRingBuffer->readSlotBlocking(ptrToReadSlot); }
- virtual void writeAudioBuffer(const int8_t* ptrToSlot)
- { mReceiveRingBuffer->insertSlotNonBlocking(ptrToSlot); }
- uint32_t getBufferSizeInSamples() const
- { return mAudioBufferSize; /*return mAudioInterface->getBufferSizeInSamples();*/ }
-
- AudioInterface::samplingRateT getSampleRateType() const
- { return mAudioInterface->getSampleRateType(); }
- int getSampleRate() const
- { return mSampleRate; /*return mAudioInterface->getSampleRate();*/ }
-
- uint8_t getAudioBitResolution() const
- { return mAudioBitResolution*8; /*return mAudioInterface->getAudioBitResolution();*/ }
- unsigned int getNumInputChannels() const
- { return mNumChans; /*return mAudioInterface->getNumInputChannels();*/ }
- unsigned int getNumOutputChannels() const
- { return mNumChans; /*return mAudioInterface->getNumOutputChannels();*/ }
- unsigned int getNumChannels() const
- {
- if (getNumInputChannels() == getNumOutputChannels())
- { return getNumInputChannels(); }
- else { return 0; }
- }
- virtual void checkPeerSettings(int8_t* full_packet);
- void increaseSequenceNumber()
- { mPacketHeader->increaseSequenceNumber(); }
- int getSequenceNumber() const
- { return mPacketHeader->getSequenceNumber(); }
-
- uint64_t getPeerTimeStamp(int8_t* full_packet) const
- { return mPacketHeader->getPeerTimeStamp(full_packet); }
-
- uint16_t getPeerSequenceNumber(int8_t* full_packet) const
- { return mPacketHeader->getPeerSequenceNumber(full_packet); }
-
- uint16_t getPeerBufferSize(int8_t* full_packet) const
- { return mPacketHeader->getPeerBufferSize(full_packet); }
-
- uint8_t getPeerSamplingRate(int8_t* full_packet) const
- { return mPacketHeader->getPeerSamplingRate(full_packet); }
-
- uint8_t getPeerBitResolution(int8_t* full_packet) const
- { return mPacketHeader->getPeerBitResolution(full_packet); }
-
- uint8_t getPeerNumChannels(int8_t* full_packet) const
- { return mPacketHeader->getPeerNumChannels(full_packet); }
-
- uint8_t getPeerConnectionMode(int8_t* full_packet) const
- { return mPacketHeader->getPeerConnectionMode(full_packet); }
-
- size_t getSizeInBytesPerChannel() const
- { return mAudioInterface->getSizeInBytesPerChannel(); }
- int getHeaderSizeInBytes() const
- { return mPacketHeader->getHeaderSizeInBytes(); }
- virtual int getTotalAudioPacketSizeInBytes() const
- { return mAudioInterface->getSizeInBytesPerChannel() * mNumChans; }
- //@}
- //------------------------------------------------------------------------------------
-
- void printTextTest() {std::cout << "=== JackTrip PRINT ===" << std::endl;}
- void printTextTest2() {std::cout << "=== JackTrip PRINT2 ===" << std::endl;}
+ //void appendProcessPlugin(const std::tr1::shared_ptr<ProcessPlugin> plugin);
+ virtual void appendProcessPlugin(ProcessPlugin* plugin);
+
+ /// \brief Start the processing threads
+ virtual void startProcess(
+ #ifdef WAIRTOMASTER // wair
+ int ID
+ #endif // endwhere
+ ) throw(std::invalid_argument);
+
+ /// \brief Stop the processing threads
+ virtual void stop();
+
+ /// \brief Wait for all the threads to finish. This functions is used when JackTrip is
+ /// run as a thread
+ virtual void waitThreads();
+
+ /// \brief Check if UDP port is already binded
+ /// \param port Port number
+ virtual void checkIfPortIsBinded(int port);
+
+ //------------------------------------------------------------------------------------
+ /// \name Getters and Setters Methods to change parameters after construction
+ //@{
+ //
+ /// \brief Sets (override) JackTrip Mode after construction
+ virtual void setJackTripMode(jacktripModeT JacktripMode)
+ { mJackTripMode = JacktripMode; }
+ /// \brief Sets (override) DataProtocol Type after construction
+ virtual void setDataProtocoType(dataProtocolT DataProtocolType)
+ { mDataProtocol = DataProtocolType; }
+ /// \brief Sets the Packet header type
+ virtual void setPacketHeaderType(DataProtocol::packetHeaderTypeT PacketHeaderType)
+ {
+ mPacketHeaderType = PacketHeaderType;
+ delete mPacketHeader;
+ mPacketHeader = NULL;
+ createHeader(mPacketHeaderType);
+ }
+ /// \brief Sets (override) Buffer Queue Length Mode after construction
+ virtual void setBufferQueueLength(int BufferQueueLength)
+ { mBufferQueueLength = BufferQueueLength; }
+ /// \brief Sets (override) Audio Bit Resolution after construction
+ virtual void setAudioBitResolution(AudioInterface::audioBitResolutionT AudioBitResolution)
+ { mAudioBitResolution = AudioBitResolution; }
+ /// \brief Sets (override) Underrun Mode
+ virtual void setUnderRunMode(underrunModeT UnderRunMode)
+ { mUnderRunMode = UnderRunMode; }
+ /// \brief Sets port numbers for the local and peer machine.
+ /// Receive port is <tt>port</tt>
+ virtual void setAllPorts(int port)
+ {
+ mReceiverBindPort = port;
+ mSenderPeerPort = port;
+ mSenderBindPort = port;
+ mReceiverPeerPort = port;
+ }
+ /// \brief Sets port numbers to bind in RECEIVER and SENDER sockets.
+ virtual void setBindPorts(int port)
+ {
+ mReceiverBindPort = port;
+ mSenderBindPort = port;
+ }
+ /// \brief Sets port numbers for the peer (remote) machine.
+ virtual void setPeerPorts(int port)
+ {
+ mSenderPeerPort = port;
+ mReceiverPeerPort = port;
+ }
+ /// \brief Set Client Name to something different that the default (JackTrip)
+ virtual void setClientName(const char* ClientName)
+ { mJackClientName = ClientName; }
+ /// \brief Set the number of audio channels
+ virtual void setNumChannels(int num_chans)
+ { mNumChans = num_chans; }
+
+ /// Set to connect or not default audio ports (only implemented in Jack)
+ virtual void setConnectDefaultAudioPorts(bool connect)
+ {mConnectDefaultAudioPorts = connect;}
+
+ virtual int getReceiverBindPort() const
+ { return mReceiverBindPort; }
+ virtual int getSenderPeerPort() const
+ { return mSenderPeerPort; }
+ virtual int getSenderBindPort() const
+ { return mSenderBindPort; }
+ virtual int getReceiverPeerPort() const
+ { return mReceiverPeerPort; }
+
+ virtual DataProtocol* getDataProtocolSender() const
+ { return mDataProtocolSender; }
+ virtual DataProtocol* getDataProtocolReceiver() const
+ { return mDataProtocolReceiver; }
+ virtual void setDataProtocolSender(DataProtocol* const DataProtocolSender)
+ { mDataProtocolSender = DataProtocolSender; }
+ virtual void setDataProtocolReceiver(DataProtocol* const DataProtocolReceiver)
+ { mDataProtocolReceiver = DataProtocolReceiver; }
+
+ virtual RingBuffer* getSendRingBuffer() const
+ { return mSendRingBuffer; }
+ virtual RingBuffer* getReceiveRingBuffer() const
+ { return mReceiveRingBuffer; }
+ virtual void setSendRingBuffer(RingBuffer* const SendRingBuffer)
+ { mSendRingBuffer = SendRingBuffer; }
+ virtual void setReceiveRingBuffer(RingBuffer* const ReceiveRingBuffer)
+ { mReceiveRingBuffer = ReceiveRingBuffer; }
+
+ virtual void setPacketHeader(PacketHeader* const PacketHeader)
+ { mPacketHeader = PacketHeader; }
+
+ virtual int getRingBuffersSlotSize()
+ { return getTotalAudioPacketSizeInBytes(); }
+
+ virtual void setAudiointerfaceMode(JackTrip::audiointerfaceModeT audiointerface_mode)
+ { mAudiointerfaceMode = audiointerface_mode; }
+ virtual void setAudioInterface(AudioInterface* const AudioInterface)
+ { mAudioInterface = AudioInterface; }
+
+
+ void setSampleRate(uint32_t sample_rate)
+ { mSampleRate = sample_rate; }
+ void setDeviceID(uint32_t device_id)
+ { mDeviceID = device_id; }
+ void setAudioBufferSizeInSamples(uint32_t buf_size)
+ { mAudioBufferSize = buf_size; }
+
+
+ JackTrip::connectionModeT getConnectionMode() const
+ { return mConnectionMode; }
+ void setConnectionMode(JackTrip::connectionModeT connection_mode)
+ { mConnectionMode = connection_mode; }
+
+ JackTrip::hubConnectionModeT getHubConnectionModeT() const
+ { return mHubConnectionModeT; }
+ void setHubConnectionModeT(JackTrip::hubConnectionModeT connection_mode)
+ { mHubConnectionModeT = connection_mode; }
+
+ JackTrip::jacktripModeT getJackTripMode() const
+ { return mJackTripMode; }
+
+ QString getPeerAddress() const
+ { return mPeerAddress; }
+
+ bool receivedConnectionFromPeer()
+ { return mReceivedConnection; }
+
+ bool tcpConnectionError()
+ { return mTcpConnectionError; }
+ //@}
+ //------------------------------------------------------------------------------------
+
+
+ //------------------------------------------------------------------------------------
+ /// \name Mediator Functions
+ //@{
+ /// \todo Document all these functions
+ virtual void createHeader(const DataProtocol::packetHeaderTypeT headertype);
+ void putHeaderInPacket(int8_t* full_packet, int8_t* audio_packet);
+ virtual int getPacketSizeInBytes();
+ void parseAudioPacket(int8_t* full_packet, int8_t* audio_packet);
+ virtual void sendNetworkPacket(const int8_t* ptrToSlot)
+ { mSendRingBuffer->insertSlotNonBlocking(ptrToSlot); }
+ virtual void receiveNetworkPacket(int8_t* ptrToReadSlot)
+ { mReceiveRingBuffer->readSlotNonBlocking(ptrToReadSlot); }
+ virtual void readAudioBuffer(int8_t* ptrToReadSlot)
+ { mSendRingBuffer->readSlotBlocking(ptrToReadSlot); }
+ virtual void writeAudioBuffer(const int8_t* ptrToSlot)
+ { mReceiveRingBuffer->insertSlotNonBlocking(ptrToSlot); }
+ uint32_t getBufferSizeInSamples() const
+ { return mAudioBufferSize; /*return mAudioInterface->getBufferSizeInSamples();*/ }
+ uint32_t getDeviceID() const
+ { return mDeviceID; /*return mAudioInterface->mDeviceID();*/ }
+
+ AudioInterface::samplingRateT getSampleRateType() const
+ { return mAudioInterface->getSampleRateType(); }
+ int getSampleRate() const
+ { return mSampleRate; /*return mAudioInterface->getSampleRate();*/ }
+
+ uint8_t getAudioBitResolution() const
+ { return mAudioBitResolution*8; /*return mAudioInterface->getAudioBitResolution();*/ }
+ unsigned int getNumInputChannels() const
+ { return mNumChans; /*return mAudioInterface->getNumInputChannels();*/ }
+ unsigned int getNumOutputChannels() const
+ { return mNumChans; /*return mAudioInterface->getNumOutputChannels();*/ }
+ unsigned int getNumChannels() const
+ {
+ if (getNumInputChannels() == getNumOutputChannels())
+ { return getNumInputChannels(); }
+ else { return 0; }
+ }
+ virtual void checkPeerSettings(int8_t* full_packet);
+ void increaseSequenceNumber()
+ { mPacketHeader->increaseSequenceNumber(); }
+ int getSequenceNumber() const
+ { return mPacketHeader->getSequenceNumber(); }
+
+ uint64_t getPeerTimeStamp(int8_t* full_packet) const
+ { return mPacketHeader->getPeerTimeStamp(full_packet); }
+
+ uint16_t getPeerSequenceNumber(int8_t* full_packet) const
+ { return mPacketHeader->getPeerSequenceNumber(full_packet); }
+
+ uint16_t getPeerBufferSize(int8_t* full_packet) const
+ { return mPacketHeader->getPeerBufferSize(full_packet); }
+
+ uint8_t getPeerSamplingRate(int8_t* full_packet) const
+ { return mPacketHeader->getPeerSamplingRate(full_packet); }
+
+ uint8_t getPeerBitResolution(int8_t* full_packet) const
+ { return mPacketHeader->getPeerBitResolution(full_packet); }
+
+ uint8_t getPeerNumChannels(int8_t* full_packet) const
+ { return mPacketHeader->getPeerNumChannels(full_packet); }
+
+ uint8_t getPeerConnectionMode(int8_t* full_packet) const
+ { return mPacketHeader->getPeerConnectionMode(full_packet); }
+
+ size_t getSizeInBytesPerChannel() const
+ { return mAudioInterface->getSizeInBytesPerChannel(); }
+ int getHeaderSizeInBytes() const
+ { return mPacketHeader->getHeaderSizeInBytes(); }
+ virtual int getTotalAudioPacketSizeInBytes() const
+ {
+#ifdef WAIR // WAIR
+ if (mNumNetRevChans)
+ return mAudioInterface->getSizeInBytesPerChannel() * mNumNetRevChans;
+ else // not wair
+#endif // endwhere
+ return mAudioInterface->getSizeInBytesPerChannel() * mNumChans;
+ }
+ //@}
+ //------------------------------------------------------------------------------------
+
+ void printTextTest() {std::cout << "=== JackTrip PRINT ===" << std::endl;}
+ void printTextTest2() {std::cout << "=== JackTrip PRINT2 ===" << std::endl;}
public slots:
- /// \brief Slot to stop all the processes and threads
- virtual void slotStopProcesses()
- {
- std::cout << "Stopping JackTrip..." << std::endl;
- mStopped = true;
- this->stop();
- }
-
- /** \brief This slot emits in turn the signal signalNoUdpPacketsForSeconds
+ /// \brief Slot to stop all the processes and threads
+ virtual void slotStopProcesses()
+ {
+ std::cout << "Stopping JackTrip..." << std::endl;
+ mStopped = true;
+ this->stop();
+ }
+
+ /** \brief This slot emits in turn the signal signalNoUdpPacketsForSeconds
* when UDP has waited for more than 30 seconds.
- *
+ *
* It is used to remove the thread from the server.
*/
- void slotUdpWatingTooLong(int wait_msec)
- {
- int wait_time = 30000; // msec
- if ( !(wait_msec%wait_time) ) {
- std::cerr << "UDP WAITED MORE THAN 30 seconds." << std::endl;
- emit signalNoUdpPacketsForSeconds();
+ void slotUdpWaitingTooLongClientGoneProbably(int wait_msec)
+ {
+ int wait_time = 10000; // msec
+ if ( !(wait_msec%wait_time) ) {
+ std::cerr << "UDP WAITED MORE THAN 10 seconds." << std::endl;
+ emit signalNoUdpPacketsForSeconds();
+ }
}
- }
- void slotPrintTest()
- { std::cout << "=== TESTING ===" << std::endl; }
- void slotReceivedConnectionFromPeer()
- { mReceivedConnection = true; }
+ void slotPrintTest()
+ { std::cout << "=== TESTING ===" << std::endl; }
+ void slotReceivedConnectionFromPeer()
+ { mReceivedConnection = true; }
signals:
- void signalUdpTimeOut();
- /// \brief Signal emitted when all the processes and threads are stopped
- void signalProcessesStopped();
- /// \brief Signal emitted when no UDP Packets have been received for a while
- void signalNoUdpPacketsForSeconds();
- void signalTcpClientConnected();
+ void signalUdpTimeOut();
+ /// \brief Signal emitted when all the processes and threads are stopped
+ void signalProcessesStopped();
+ /// \brief Signal emitted when no UDP Packets have been received for a while
+ void signalNoUdpPacketsForSeconds();
+ void signalTcpClientConnected();
public:
- /// \brief Set the AudioInteface object
- virtual void setupAudio();
- /// \brief Close the JackAudioInteface and disconnects it from JACK
- void closeAudio();
- /// \brief Set the DataProtocol objects
- virtual void setupDataProtocol();
- /// \brief Set the RingBuffer objects
- void setupRingBuffers();
- /// \brief Starts for the CLIENT mode
- void clientStart() throw(std::invalid_argument);
- /// \brief Starts for the SERVER mode
- /// \param timout Set the server to timeout after 2 seconds if no client connections are received.
- /// Usefull for the multithreaded server
- /// \return 0 on success, -1 on error
- int serverStart(bool timeout = false, int udpTimeout = gTimeOutMultiThreadedServer)
- throw(std::invalid_argument, std::runtime_error);
- /// \brief Stats for the Client to Ping Server
- /// \return -1 on error, 0 on success
- virtual int clientPingToServerStart() throw(std::invalid_argument);
+ /// \brief Set the AudioInteface object
+ virtual void setupAudio(
+ #ifdef WAIRTOMASTER // WAIR
+ int ID
+ #endif // endwhere
+ );
+ /// \brief Close the JackAudioInteface and disconnects it from JACK
+ void closeAudio();
+ /// \brief Set the DataProtocol objects
+ virtual void setupDataProtocol();
+ /// \brief Set the RingBuffer objects
+ void setupRingBuffers();
+ /// \brief Starts for the CLIENT mode
+ void clientStart() throw(std::invalid_argument);
+ /// \brief Starts for the SERVER mode
+ /// \param timout Set the server to timeout after 2 seconds if no client connections are received.
+ /// Usefull for the multithreaded server
+ /// \return 0 on success, -1 on error
+ int serverStart(bool timeout = false, int udpTimeout = gTimeOutMultiThreadedServer)
+ throw(std::invalid_argument, std::runtime_error);
+ /// \brief Stats for the Client to Ping Server
+ /// \return -1 on error, 0 on success
+ virtual int clientPingToServerStart() throw(std::invalid_argument);
private:
- //void bindReceiveSocket(QUdpSocket& UdpSocket, int bind_port,
- // QHostAddress PeerHostAddress, int peer_port)
- //throw(std::runtime_error);
-
-
- jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
- dataProtocolT mDataProtocol; ///< Data Protocol Tipe
- DataProtocol::packetHeaderTypeT mPacketHeaderType; ///< Packet Header Type
- JackTrip::audiointerfaceModeT mAudiointerfaceMode;
-
- int mNumChans; ///< Number of Channels (inputs = outputs)
- int mBufferQueueLength; ///< Audio Buffer from network queue length
- uint32_t mSampleRate; ///< Sample Rate
- uint32_t mAudioBufferSize; ///< Audio buffer size to process on each callback
- AudioInterface::audioBitResolutionT mAudioBitResolution; ///< Audio Bit Resolutions
- QString mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
-
- /// Pointer to Abstract Type DataProtocol that sends packets
- DataProtocol* mDataProtocolSender;
- /// Pointer to Abstract Type DataProtocol that receives packets
- DataProtocol* mDataProtocolReceiver;
- AudioInterface* mAudioInterface; ///< Interface to Jack Client
- PacketHeader* mPacketHeader; ///< Pointer to Packet Header
- underrunModeT mUnderRunMode; ///< underrunModeT Mode
-
- /// Pointer for the Send RingBuffer
- RingBuffer* mSendRingBuffer;
- /// Pointer for the Receive RingBuffer
- RingBuffer* mReceiveRingBuffer;
-
- int mReceiverBindPort; ///< Incoming (receiving) port for local machine
- int mSenderPeerPort; ///< Incoming (receiving) port for peer machine
- int mSenderBindPort; ///< Outgoing (sending) port for local machine
- int mReceiverPeerPort; ///< Outgoing (sending) port for peer machine
- int mTcpServerPort;
-
- unsigned int mRedundancy; ///< Redundancy factor in network data
- const char* mJackClientName; ///< JackAudio Client Name
-
- JackTrip::connectionModeT mConnectionMode; ///< Connection Mode
-
- QVector<ProcessPlugin*> mProcessPlugins; ///< Vector of ProcesPlugin<EM>s</EM>
-
- volatile bool mReceivedConnection; ///< Bool of received connection from peer
- volatile bool mTcpConnectionError;
- volatile bool mStopped;
+ //void bindReceiveSocket(QUdpSocket& UdpSocket, int bind_port,
+ // QHostAddress PeerHostAddress, int peer_port)
+ //throw(std::runtime_error);
+
+
+ jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
+ dataProtocolT mDataProtocol; ///< Data Protocol Tipe
+ DataProtocol::packetHeaderTypeT mPacketHeaderType; ///< Packet Header Type
+ JackTrip::audiointerfaceModeT mAudiointerfaceMode;
+
+ int mNumChans; ///< Number of Channels (inputs = outputs)
+#ifdef WAIR // WAIR
+ int mNumNetRevChans; ///< Number of Network Audio Channels (net comb filters)
+#endif // endwhere
+ int mBufferQueueLength; ///< Audio Buffer from network queue length
+ uint32_t mSampleRate; ///< Sample Rate
+ uint32_t mDeviceID; ///< RTAudio DeviceID
+ uint32_t mAudioBufferSize; ///< Audio buffer size to process on each callback
+ AudioInterface::audioBitResolutionT mAudioBitResolution; ///< Audio Bit Resolutions
+ QString mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
+
+ /// Pointer to Abstract Type DataProtocol that sends packets
+ DataProtocol* mDataProtocolSender;
+ /// Pointer to Abstract Type DataProtocol that receives packets
+ DataProtocol* mDataProtocolReceiver;
+ AudioInterface* mAudioInterface; ///< Interface to Jack Client
+ PacketHeader* mPacketHeader; ///< Pointer to Packet Header
+ underrunModeT mUnderRunMode; ///< underrunModeT Mode
+
+ /// Pointer for the Send RingBuffer
+ RingBuffer* mSendRingBuffer;
+ /// Pointer for the Receive RingBuffer
+ RingBuffer* mReceiveRingBuffer;
+
+ int mReceiverBindPort; ///< Incoming (receiving) port for local machine
+ int mSenderPeerPort; ///< Incoming (receiving) port for peer machine
+ int mSenderBindPort; ///< Outgoing (sending) port for local machine
+ int mReceiverPeerPort; ///< Outgoing (sending) port for peer machine
+ int mTcpServerPort;
+
+ unsigned int mRedundancy; ///< Redundancy factor in network data
+ const char* mJackClientName; ///< JackAudio Client Name
+
+ JackTrip::connectionModeT mConnectionMode; ///< Connection Mode
+ JackTrip::hubConnectionModeT mHubConnectionModeT; ///< Hub Server Jack Audio Patch Connection Mode
+
+ QVector<ProcessPlugin*> mProcessPlugins; ///< Vector of ProcesPlugin<EM>s</EM>
+
+ volatile bool mReceivedConnection; ///< Bool of received connection from peer
+ volatile bool mTcpConnectionError;
+ volatile bool mStopped;
+
+ bool mConnectDefaultAudioPorts; ///< Connect or not default audio ports
};
#endif
-
-
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//*******************************************************************************
void JackTripThread::run()
{
- JackTrip jacktrip(mJackTripMode);
- jacktrip.setAllPorts(mPortNum);
-
- if ( mJackTripMode == JackTrip::CLIENT )
+ JackTrip jacktrip(mJackTripMode);
+ jacktrip.setAllPorts(mPortNum);
+
+ if ( mJackTripMode == JackTrip::CLIENT )
{
- jacktrip.setPeerAddress(mPeerAddress);
+ jacktrip.setPeerAddress(mPeerAddress);
}
- NetKS netks;
- jacktrip.appendProcessPlugin(&netks);
- //netks.play();
+ NetKS netks;
+ jacktrip.appendProcessPlugin(&netks);
+ //netks.play();
- //QThread::sleep(1);
- jacktrip.start();
- //netks.play();
- jacktrip.wait();
+ //QThread::sleep(1);
+ jacktrip.start();
+ //netks.play();
+ jacktrip.wait();
- cout << "******** AFTER JACKTRIPTHREAD START **************" << endl;
- //QThread::sleep(9999999);
+ cout << "******** AFTER JACKTRIPTHREAD START **************" << endl;
+ //QThread::sleep(9999999);
- /*
+ /*
jack_client_t* mClient;
const char* client_name = "JackThread";
const char* server_name = NULL;
if (mClient == NULL) {
fprintf (stderr, "jack_client_open() failed, "
- "status = 0x%2.0x\n", status);
+ "status = 0x%2.0x\n", status);
if (status & JackServerFailed) {
fprintf (stderr, "Unable to connect to JACK server\n");
}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
class JackTripThread : public QThread
{
public:
- JackTripThread(JackTrip::jacktripModeT JacktripMode) : mJackTripMode(JacktripMode) {}
- virtual ~JackTripThread(){}
- void run();
+ JackTripThread(JackTrip::jacktripModeT JacktripMode) : mJackTripMode(JacktripMode) {}
+ virtual ~JackTripThread(){}
+ void run();
- void setPort(int port_num) { mPortNum = port_num; }
- void setPeerAddress(const char* PeerHostOrIP) { mPeerAddress = PeerHostOrIP; }
+ void setPort(int port_num) { mPortNum = port_num; }
+ void setPeerAddress(const char* PeerHostOrIP) { mPeerAddress = PeerHostOrIP; }
private:
- JackTrip::jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
- int mPortNum;
- const char* mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
+ JackTrip::jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
+ int mPortNum;
+ const char* mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
};
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#include "UdpMasterListener.h"
#include "NetKS.h"
#include "LoopBack.h"
+#ifdef WAIR // wair
+#include "dcblock2gain.dsp.h"
+#endif // endwhere
#ifdef __JAMTEST__
#include "JamTest.h"
#endif
using std::cout; using std::endl;
//*******************************************************************************
-JackTripWorker::JackTripWorker(UdpMasterListener* udpmasterlistener) :
- mUdpMasterListener(NULL),
- mSpawning(false),
- mID(0),
- mNumChans(1)
+JackTripWorker::JackTripWorker(UdpMasterListener* udpmasterlistener, int BufferQueueLength, JackTrip::underrunModeT UnderRunMode) :
+ mUdpMasterListener(udpmasterlistener),
+ m_connectDefaultAudioPorts(false),
+ mBufferQueueLength(BufferQueueLength),
+ mUnderRunMode(UnderRunMode),
+ mSpawning(false),
+ mID(0),
+ mNumChans(1)
+ #ifdef WAIR // wair
+ ,mNumNetRevChans(0),
+ mWAIR(false)
+ #endif // endwhere
{
- /* From the QT Documentation:
- QThreadPool supports executing the same QRunnable more than once
- by calling tryStart(this) from within QRunnable::run(). If autoDelete is
- enabled the QRunnable will be deleted when the last thread exits the
- run function. Calling start() multiple times with the same QRunnable
- when autoDelete is enabled creates a race condition and is not recommended.
- */
- mUdpMasterListener = udpmasterlistener;
- setAutoDelete(false); // stick around after calling run()
- //mNetks = new NetKS;
- //mNetks->play();
+ setAutoDelete(false); // stick around after calling run()
+ //mNetks = new NetKS;
+ //mNetks->play();
}
//*******************************************************************************
JackTripWorker::~JackTripWorker()
{
- //delete mUdpMasterListener;
+ //delete mUdpMasterListener;
}
//*******************************************************************************
-void JackTripWorker::setJackTrip(int id, uint32_t client_address,
- uint16_t server_port, uint16_t client_port,
- int num_channels)
+void JackTripWorker::setJackTrip(int id,
+ QString client_address,
+ uint16_t server_port,
+ uint16_t client_port,
+ int num_channels,
+ bool connectDefaultAudioPorts)
{
- { //Start Spawning, so lock mSpawning
- QMutexLocker locker(&mMutex);
- mSpawning = true;
- }
- mID = id;
- // Set the jacktrip address and ports
- //mClientAddress.setAddress(client_address);
- mClientAddress = client_address;
- mServerPort = server_port;
- mClientPort = client_port;
- mNumChans = num_channels;
+ { //Start Spawning, so lock mSpawning
+ QMutexLocker locker(&mMutex);
+ mSpawning = true;
+ }
+ mID = id;
+ // Set the jacktrip address and ports
+ //mClientAddress.setAddress(client_address);
+ mClientAddress = client_address;
+ mServerPort = server_port;
+ mClientPort = client_port;
+ mNumChans = num_channels;
+ m_connectDefaultAudioPorts = connectDefaultAudioPorts;
}
//*******************************************************************************
void JackTripWorker::run()
{
- /* NOTE: This is the message that qt prints when an exception is thrown:
+ /* NOTE: This is the message that qt prints when an exception is thrown:
'Qt Concurrent has caught an exception thrown from a worker thread.
This is not supported, exceptions thrown in worker threads must be
caught before control returns to Qt Concurrent.'*/
- { QMutexLocker locker(&mMutex); mSpawning = true; }
-
- QHostAddress ClientAddress;
+ { QMutexLocker locker(&mMutex); mSpawning = true; }
- // Try catching any exceptions that come from JackTrip
- try
- {
- // Local event loop. this is necesary because QRunnables don't have their own as QThreads
- QEventLoop event_loop;
+ //QHostAddress ClientAddress;
+
+ // Try catching any exceptions that come from JackTrip
+ try
+ {
+ // Local event loop. this is necesary because QRunnables don't have their own as QThreads
+ QEventLoop event_loop;
+
+ // Create and setup JackTrip Object
+ //JackTrip jacktrip(JackTrip::SERVER, JackTrip::UDP, mNumChans, 2);
+ if (gVerboseFlag) cout << "---> JackTripWorker: Creating jacktrip objects..." << endl;
+
+#ifdef WAIR // WAIR
+ // forces BufferQueueLength to 2
+ // need to parse numNetChans from incoming header
+ // but force to 16 for now
+#define FORCEBUFFERQ 2
+ if (mUdpMasterListener->isWAIR()) { // invoked with -Sw
+ mWAIR = true;
+ mNumNetRevChans = NUMNETREVCHANSbecauseNOTINRECEIVEDheader;
+ } else {};
+#endif // endwhere
- // Create and setup JackTrip Object
- //JackTrip jacktrip(JackTrip::SERVER, JackTrip::UDP, mNumChans, 2);
- cout << "---> JackTripWorker: Creating jacktip objects..." << endl;
#ifndef __JAMTEST__
- JackTrip jacktrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, mNumChans, 2);
-#endif
+#ifdef WAIR // WAIR
+ // bool tmp = mJTWorkers->at(id)->isWAIR();
+ // qDebug() << "is WAIR?" << tmp ;
+ qDebug() << "mNumNetRevChans" << mNumNetRevChans ;
+
+ JackTrip jacktrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, mNumChans,
+ mNumNetRevChans, FORCEBUFFERQ);
+ JackTrip * mJackTrip = &jacktrip;
+#else // endwhere
+ JackTrip jacktrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, mNumChans, mBufferQueueLength);
+#endif // not wair
+
+#ifdef WAIR // WAIR
+ // Add Plugins
+ if ( mWAIR ) {
+ cout << "Running in WAIR Mode..." << endl;
+ cout << gPrintSeparator << std::endl;
+ switch ( mNumNetRevChans )
+ {
+ case 16 : // freeverb
+ mJackTrip->appendProcessPlugin(new dcblock2gain(mNumChans)); // plugin slot 0
+ ///////////////
+ // mJackTrip->appendProcessPlugin(new comb16server(mNumNetChans));
+ // -S LAIR no AP mJackTrip->appendProcessPlugin(new AP8(mNumChans));
+ break;
+ default:
+ throw std::invalid_argument("Settings: mNumNetChans doesn't correspond to Faust plugin");
+ break;
+ }
+ }
+#endif // endwhere
+#endif // ifndef __JAMTEST__
+
#ifdef __JAMTEST__
- JamTest jacktrip(JackTrip::SERVERPINGSERVER); // ########### JamTest #################
- //JackTrip jacktrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, mNumChans, 2);
+ JamTest jacktrip(JackTrip::SERVERPINGSERVER); // ########### JamTest #################
+ //JackTrip jacktrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, mNumChans, 2);
#endif
- // Connect signals and slots
- // -------------------------
- cout << "---> JackTripWorker: Connecting signals and slots..." << endl;
- // Connection to terminate JackTrip when packets haven't arrive for
- // a certain amount of time
- QObject::connect(&jacktrip, SIGNAL(signalNoUdpPacketsForSeconds()),
- &jacktrip, SLOT(slotStopProcesses()), Qt::QueuedConnection);
- // Connection to terminate the local eventloop when jacktrip is done
- QObject::connect(&jacktrip, SIGNAL(signalProcessesStopped()),
- &event_loop, SLOT(quit()), Qt::QueuedConnection);
- QObject::connect(this, SIGNAL(signalRemoveThread()),
- &jacktrip, SLOT(slotStopProcesses()), Qt::QueuedConnection);
-
- ClientAddress.setAddress(mClientAddress);
- // If I don't type this line, I get a bus error in the next line.
- // I still haven't figure out why
- ClientAddress.toString().toLatin1().constData();
- jacktrip.setPeerAddress(ClientAddress.toString().toLatin1().constData());
- jacktrip.setBindPorts(mServerPort);
- //jacktrip.setPeerPorts(mClientPort);
-
- cout << "---> JackTripWorker: setJackTripFromClientHeader..." << endl;
- int PeerConnectionMode = setJackTripFromClientHeader(jacktrip);
- if ( PeerConnectionMode == -1 ) {
- mUdpMasterListener->releaseThread(mID);
- { QMutexLocker locker(&mMutex); mSpawning = false; }
- return;
- }
-
- // Start Threads and event loop
- cout << "---> JackTripWorker: startProcess..." << endl;
- jacktrip.startProcess();
- cout << "---> JackTripWorker: start..." << endl;
- jacktrip.start(); // ########### JamTest Only #################
-
- // Thread is already spawning, so release the lock
- { QMutexLocker locker(&mMutex); mSpawning = false; }
-
- event_loop.exec(); // Excecution will block here until exit() the QEventLoop
- //--------------------------------------------------------------------------
+ jacktrip.setConnectDefaultAudioPorts(m_connectDefaultAudioPorts);
+
+ // Set our underrun mode
+ jacktrip.setUnderRunMode(mUnderRunMode);
+
+ // Connect signals and slots
+ // -------------------------
+ if (gVerboseFlag) cout << "---> JackTripWorker: Connecting signals and slots..." << endl;
+ // Connection to terminate JackTrip when packets haven't arrive for
+ // a certain amount of time
+ QObject::connect(&jacktrip, SIGNAL(signalNoUdpPacketsForSeconds()),
+ &jacktrip, SLOT(slotStopProcesses()), Qt::QueuedConnection);
+ // Connection to terminate the local eventloop when jacktrip is done
+ QObject::connect(&jacktrip, SIGNAL(signalProcessesStopped()),
+ &event_loop, SLOT(quit()), Qt::QueuedConnection);
+ QObject::connect(this, SIGNAL(signalRemoveThread()),
+ &jacktrip, SLOT(slotStopProcesses()), Qt::QueuedConnection);
+
+ //ClientAddress.setAddress(mClientAddress);
+ // If I don't type this line, I get a bus error in the next line.
+ // I still haven't figure out why
+ //ClientAddress.toString().toLatin1().constData();
+ //jacktrip.setPeerAddress(ClientAddress.toString().toLatin1().constData());
+ jacktrip.setPeerAddress(mClientAddress.toLatin1().constData());
+ jacktrip.setBindPorts(mServerPort);
+ //jacktrip.setPeerPorts(mClientPort);
+
+ if (gVerboseFlag) cout << "---> JackTripWorker: setJackTripFromClientHeader..." << endl;
+ int PeerConnectionMode = setJackTripFromClientHeader(jacktrip);
+ if ( PeerConnectionMode == -1 ) {
+ mUdpMasterListener->releaseThread(mID);
+ { QMutexLocker locker(&mMutex); mSpawning = false; }
+ return;
+ }
+
+ // Start Threads and event loop
+ if (gVerboseFlag) cout << "---> JackTripWorker: startProcess..." << endl;
+ jacktrip.startProcess(
+ #ifdef WAIRTOMASTER // wair
+ mID
+ #endif // endwhere
+ );
+ // if (gVerboseFlag) cout << "---> JackTripWorker: start..." << endl;
+ // jacktrip.start(); // ########### JamTest Only #################
+
+ // Thread is already spawning, so release the lock
+ { QMutexLocker locker(&mMutex); mSpawning = false; }
+
+ event_loop.exec(); // Excecution will block here until exit() the QEventLoop
+ //--------------------------------------------------------------------------
+
+ { QMutexLocker locker(&mMutex); mSpawning = true; }
+
+ // wait for jacktrip to be done before exiting the Worker Thread
+ jacktrip.wait();
- { QMutexLocker locker(&mMutex); mSpawning = true; }
+ }
+ catch ( const std::exception & e )
+ {
+ std::cerr << "Couldn't send thread to the Pool" << endl;
+ std::cerr << e.what() << endl;
+ std::cerr << gPrintSeparator << endl;
+ mUdpMasterListener->releaseThread(mID);
+ { QMutexLocker locker(&mMutex); mSpawning = false; }
+ return;
+ }
- // wait for jacktrip to be done before exiting the Worker Thread
- jacktrip.wait();
-
- }
- catch ( const std::exception & e )
- {
- std::cerr << "Couldn't send thread to the Pool" << endl;
- std::cerr << e.what() << endl;
- std::cerr << gPrintSeparator << endl;
- mUdpMasterListener->releaseThread(mID);
- { QMutexLocker locker(&mMutex); mSpawning = false; }
- return;
- }
-
- {
- QMutexLocker locker(&mMutex);
- mUdpMasterListener->releaseThread(mID);
- }
+ {
+ QMutexLocker locker(&mMutex);
+ mUdpMasterListener->releaseThread(mID);
+ }
- cout << "JackTrip ID = " << mID << " released from the THREAD POOL" << endl;
- cout << gPrintSeparator << endl;
- {
- // Thread is already spawning, so release the lock
- QMutexLocker locker(&mMutex);
- mSpawning = false;
- }
+ cout << "JackTrip ID = " << mID << " released from the THREAD POOL" << endl;
+ cout << gPrintSeparator << endl;
+ {
+ // Thread is already spawning, so release the lock
+ QMutexLocker locker(&mMutex);
+ mSpawning = false;
+ }
}
// returns -1 on error
int JackTripWorker::setJackTripFromClientHeader(JackTrip& jacktrip)
{
- //QHostAddress peerHostAddress;
- //uint16_t peer_port;
- QUdpSocket UdpSockTemp;// Create socket to wait for client
-
- // Bind the socket
- if ( !UdpSockTemp.bind(QHostAddress::Any, mServerPort,
- QUdpSocket::DefaultForPlatform) )
- {
- std::cerr << "in JackTripWorker: Could not bind UDP socket. It may be already binded." << endl;
- throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
- }
-
- // Listen to client
- QWaitCondition sleep; // time is in milliseconds
- QMutex mutex;
- int sleepTime = 100; // ms
- int udpTimeout = gTimeOutMultiThreadedServer; // gTimeOutMultiThreadedServer mseconds
- int elapsedTime = 0;
- {
- QMutexLocker lock(&mutex);
- while ( (!UdpSockTemp.hasPendingDatagrams()) && (elapsedTime <= udpTimeout) ) {
- sleep.wait(&mutex,sleepTime);
- elapsedTime += sleepTime;
- //cout << "---------> ELAPSED TIME: " << elapsedTime << endl;
+ //QHostAddress peerHostAddress;
+ //uint16_t peer_port;
+ QUdpSocket UdpSockTemp;// Create socket to wait for client
+
+ // Bind the socket
+ if ( !UdpSockTemp.bind(QHostAddress::Any, mServerPort,
+ QUdpSocket::DefaultForPlatform) )
+ {
+ std::cerr << "in JackTripWorker: Could not bind UDP socket. It may be already binded." << endl;
+ throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
+ }
+
+ // Listen to client
+ QWaitCondition sleep; // time is in milliseconds
+ QMutex mutex;
+ int sleepTime = 100; // ms
+ int udpTimeout = gTimeOutMultiThreadedServer; // gTimeOutMultiThreadedServer mseconds
+ int elapsedTime = 0;
+ {
+ QMutexLocker lock(&mutex);
+ while ( (!UdpSockTemp.hasPendingDatagrams()) && (elapsedTime <= udpTimeout) ) {
+ sleep.wait(&mutex,sleepTime);
+ elapsedTime += sleepTime;
+ if (gVerboseFlag) cout << "---------> ELAPSED TIME: " << elapsedTime << endl;
+ }
}
- }
- // Check if we time out or not
- if (!UdpSockTemp.hasPendingDatagrams()) {
- std::cerr << "--->JackTripWorker: is not receiving Datagrams (timeout)" << endl;
- UdpSockTemp.close();
- return -1;
- }
- int packet_size = UdpSockTemp.pendingDatagramSize();
- char packet[packet_size];
- UdpSockTemp.readDatagram(packet, packet_size);
- UdpSockTemp.close(); // close the socket
- int8_t* full_packet = reinterpret_cast<int8_t*>(packet);
-
- int PeerBufferSize = jacktrip.getPeerBufferSize(full_packet);
- int PeerSamplingRate = jacktrip.getPeerSamplingRate(full_packet);
- int PeerBitResolution = jacktrip.getPeerBitResolution(full_packet);
- int PeerNumChannels = jacktrip.getPeerNumChannels(full_packet);
- int PeerConnectionMode = jacktrip.getPeerConnectionMode(full_packet);
-
- cout << "--->JackTripWorker: getPeerBufferSize = " << PeerBufferSize << endl;
- cout << "--->JackTripWorker: getPeerSamplingRate = " << PeerSamplingRate << endl;
- cout << "--->JackTripWorker: getPeerBitResolution = " << PeerBitResolution << endl;
- cout << "--->JackTripWorker: getPeerNumChannels = " << PeerNumChannels << endl;
- cout << "--->JackTripWorker: getPeerConnectionMode = " << PeerConnectionMode << endl;
-
- jacktrip.setNumChannels(PeerNumChannels);
- return PeerConnectionMode;
+ // Check if we time out or not
+ if (!UdpSockTemp.hasPendingDatagrams()) {
+ std::cerr << "--->JackTripWorker: is not receiving Datagrams (timeout)" << endl;
+ UdpSockTemp.close();
+ return -1;
+ }
+ int packet_size = UdpSockTemp.pendingDatagramSize();
+ char packet[packet_size];
+ UdpSockTemp.readDatagram(packet, packet_size);
+ UdpSockTemp.close(); // close the socket
+ int8_t* full_packet = reinterpret_cast<int8_t*>(packet);
+
+ int PeerBufferSize = jacktrip.getPeerBufferSize(full_packet);
+ int PeerSamplingRate = jacktrip.getPeerSamplingRate(full_packet);
+ int PeerBitResolution = jacktrip.getPeerBitResolution(full_packet);
+ int PeerNumChannels = jacktrip.getPeerNumChannels(full_packet);
+ int PeerConnectionMode = jacktrip.getPeerConnectionMode(full_packet);
+
+ if (gVerboseFlag) cout << "--->JackTripWorker: getPeerBufferSize = " << PeerBufferSize << endl;
+ if (gVerboseFlag) cout << "--->JackTripWorker: getPeerSamplingRate = " << PeerSamplingRate << endl;
+ if (gVerboseFlag) cout << "--->JackTripWorker: getPeerBitResolution = " << PeerBitResolution << endl;
+ cout << "--->JackTripWorker: PeerNumChannels = " << PeerNumChannels << endl;
+ if (gVerboseFlag) cout << "--->JackTripWorker: getPeerConnectionMode = " << PeerConnectionMode << endl;
+
+ jacktrip.setNumChannels(PeerNumChannels);
+ return PeerConnectionMode;
}
//*******************************************************************************
bool JackTripWorker::isSpawning()
{
- QMutexLocker locker(&mMutex);
- return mSpawning;
+ QMutexLocker locker(&mMutex);
+ return mSpawning;
}
//*******************************************************************************
void JackTripWorker::stopThread()
{
- QMutexLocker locker(&mMutex);
- emit signalRemoveThread();
+ QMutexLocker locker(&mMutex);
+ emit signalRemoveThread();
}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#include <QMutex>
#include "JackTrip.h"
+#include "jacktrip_globals.h"
//class JackTrip; // forward declaration
class UdpMasterListener; // forward declaration
-/** \brief Prototype of the worker class that will be cloned through sending threads to the
+/** \brief Prototype of the worker class that will be cloned through sending threads to the
* Thread Pool
*
- * This class can be send to the ThreadPool using the start() method. Each time
+ * This class can be send to the ThreadPool using the start() method. Each time
* it is sent, it'll became "independent" of the prototype, which means
* that the prototype state can be changed, and used to send and start
* another thread into the pool. setAutoDelete must be set to false
// inside a QThread
class JackTripWorker : public QObject, public QRunnable
{
- Q_OBJECT; // QRunnable is not a QObject, so I have to inherit from QObject as well
-
+ Q_OBJECT; // QRunnable is not a QObject, so I have to inherit from QObject as well
+
public:
- /// \brief The class constructor
- JackTripWorker(UdpMasterListener* udpmasterlistener);
- /// \brief The class destructor
- virtual ~JackTripWorker();
-
- /// \brief Implements the Thread Loop.
- /// To start the thread, call start() ( DO NOT CALL run() ).
- void run();
- /// \brief Check if the Thread is Spawning
- /// \return true is it is spawning, false if it's already running
- bool isSpawning();
- /// \brief Sets the JackTripWorker properties
- /// \param id ID number
- /// \param address
- void setJackTrip(int id, uint32_t client_address,
- uint16_t server_port, uint16_t client_port,
- int num_channels);
- /// Stop and remove thread from pool
- void stopThread();
- int getID()
- {
- return mID;
- }
+ /// \brief The class constructor
+ JackTripWorker(UdpMasterListener* udpmasterlistener, int BufferQueueLength = gDefaultQueueLength, JackTrip::underrunModeT UnderRunMode = JackTrip::WAVETABLE);
+ /// \brief The class destructor
+ virtual ~JackTripWorker();
+
+ /// \brief Implements the Thread Loop.
+ /// To start the thread, call start() ( DO NOT CALL run() ).
+ void run();
+ /// \brief Check if the Thread is Spawning
+ /// \return true is it is spawning, false if it's already running
+ bool isSpawning();
+ /// \brief Sets the JackTripWorker properties
+ /// \param id ID number
+ /// \param address
+ void setJackTrip(int id,
+ QString client_address,
+ uint16_t server_port,
+ uint16_t client_port,
+ int num_channels,
+ bool connectDefaultAudioPorts
+ );
+ /// Stop and remove thread from pool
+ void stopThread();
+ int getID()
+ {
+ return mID;
+ }
private slots:
- void slotTest()
- { std::cout << "--- JackTripWorker TEST SLOT ---" << std::endl; }
+ void slotTest()
+ { std::cout << "--- JackTripWorker TEST SLOT ---" << std::endl; }
signals:
- void signalRemoveThread();
+ void signalRemoveThread();
private:
- int setJackTripFromClientHeader(JackTrip& jacktrip);
- JackTrip::connectionModeT getConnectionModeFromHeader();
-
- UdpMasterListener* mUdpMasterListener; ///< Master Listener Socket
- //QHostAddress mClientAddress; ///< Client Address
- uint32_t mClientAddress;
- uint16_t mServerPort; ///< Server Ephemeral Incomming Port to use with Client
-
- /// Client Outgoing Port. By convention, the receving port will be <tt>mClientPort -1</tt>
- uint16_t mClientPort;
-
- /// Thread spawning internal lock.
- /// If true, the prototype is working on creating (spawning) a new thread
- volatile bool mSpawning;
- QMutex mMutex; ///< Mutex to protect mSpawning
-
- int mID; ///< ID thread number
- int mNumChans; ///< Number of Channels
+ int setJackTripFromClientHeader(JackTrip& jacktrip);
+ JackTrip::connectionModeT getConnectionModeFromHeader();
+
+ UdpMasterListener* mUdpMasterListener; ///< Master Listener Socket
+ //QHostAddress mClientAddress; ///< Client Address
+ QString mClientAddress;
+ uint16_t mServerPort; ///< Server Ephemeral Incomming Port to use with Client
+ bool m_connectDefaultAudioPorts;
+
+ /// Client Outgoing Port. By convention, the receving port will be <tt>mClientPort -1</tt>
+ uint16_t mClientPort;
+
+ /// Thread spawning internal lock.
+ /// If true, the prototype is working on creating (spawning) a new thread
+ volatile bool mSpawning;
+ QMutex mMutex; ///< Mutex to protect mSpawning
+ JackTrip::underrunModeT mUnderRunMode;
+ int mBufferQueueLength;
+
+ int mID; ///< ID thread number
+ int mNumChans; ///< Number of Channels
+#ifdef WAIR // wair
+ int mNumNetRevChans; ///< Number of Net Channels = net combs
+ bool mWAIR;
+#endif // endwhere
};
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
class JackTripWorkerMessages : public QObject
{
- Q_OBJECT;
+ Q_OBJECT;
public:
- JackTripWorkerMessages() {};
- virtual ~JackTripWorkerMessages() {};
+ JackTripWorkerMessages() {};
+ virtual ~JackTripWorkerMessages() {};
- void play()
- {
- std::cout << "********** PALYING ***********************************" << std::endl;
- QTimer *timer = new QTimer(this);
- QObject::connect(timer, SIGNAL(timeout()), this, SLOT(slotTest()), Qt::QueuedConnection);
- timer->start(300);
- }
+ void play()
+ {
+ std::cout << "********** PALYING ***********************************" << std::endl;
+ QTimer *timer = new QTimer(this);
+ QObject::connect(timer, SIGNAL(timeout()), this, SLOT(slotTest()), Qt::QueuedConnection);
+ timer->start(300);
+ }
public slots:
- void slotTest()
- {
- std::cout << "---JackTripWorkerMessages slotTest()---" << std::endl;
- }
-
+ void slotTest()
+ {
+ std::cout << "---JackTripWorkerMessages slotTest()---" << std::endl;
+ }
+
signals:
- void signalTest();
- /// Signal to stop the event loop inside the JackTripWorker Thread
- void signalStopEventLoop();
+ void signalTest();
+ /// Signal to stop the event loop inside the JackTripWorker Thread
+ void signalStopEventLoop();
};
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//*******************************************************************************
void LoopBack::compute(int nframes, float** inputs, float** outputs)
{
- for ( int i = 0; i < getNumInputs(); i++ ) {
- // Everything that comes out, copy back to inputs
- //memcpy(inputs[i], outputs[i], sizeof(sample_t) * nframes);
- memcpy(outputs[i], inputs[i], sizeof(sample_t) * nframes);
- }
+ for ( int i = 0; i < getNumInputs(); i++ ) {
+ // Everything that comes out, copy back to inputs
+ //memcpy(inputs[i], outputs[i], sizeof(sample_t) * nframes);
+ memcpy(outputs[i], inputs[i], sizeof(sample_t) * nframes);
+ }
}
-
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
class LoopBack : public ProcessPlugin
{
public:
- /// \brief The class constructor sets the number of channels to connect as loopback
- LoopBack(int numchans) { mNumChannels = numchans; };
- /// \brief The class destructor
- virtual ~LoopBack() {};
+ /// \brief The class constructor sets the number of channels to connect as loopback
+ LoopBack(int numchans) { mNumChannels = numchans; };
+ /// \brief The class destructor
+ virtual ~LoopBack() {};
- virtual int getNumInputs() { return(mNumChannels); };
- virtual int getNumOutputs() { return(mNumChannels); };
- virtual void compute(int nframes, float** inputs, float** outputs);
+ virtual int getNumInputs() { return(mNumChannels); };
+ virtual int getNumOutputs() { return(mNumChannels); };
+ virtual void compute(int nframes, float** inputs, float** outputs);
private:
- int mNumChannels;
+ int mNumChannels;
};
#endif
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*/
class NetKS : public ProcessPlugin
{
- Q_OBJECT;
+ Q_OBJECT;
public:
- /*
+ /*
void play()
{
std::cout << "********** PALYING ***********************************" << std::endl;
private slots:
- /// \brief Stlot to excite (play) the string
- void exciteString()
- {
- std::cout << "========= EXTICING STRING ===========" << std::endl;
- fbutton0 = 1.0;
- //std::cout << fbutton0 << std::endl;
- QThread::usleep(280000); /// \todo Define this number based on the sampling rate and buffer size
- fbutton0 = 0.0;
- //std::cout << fbutton0 << std::endl;
- }
-
- //=========== FROM FAUST ===================================================
- private:
- float fbutton0;
- float fVec0[2];
- float fRec0[2];
- int iRec1[2];
- float fVec1[2];
- public:
- virtual int getNumInputs() { return 1; }
- virtual int getNumOutputs() { return 1; }
- static void classInit(int /*samplingFreq*/) {}
- virtual void instanceInit(int samplingFreq) {
- fSamplingFreq = samplingFreq;
- fbutton0 = 0.0;
- for (int i=0; i<2; i++) fVec0[i] = 0;
- for (int i=0; i<2; i++) fRec0[i] = 0;
- for (int i=0; i<2; i++) iRec1[i] = 0;
- for (int i=0; i<2; i++) fVec1[i] = 0;
- }
- virtual void init(int samplingFreq) {
- classInit(samplingFreq);
- instanceInit(samplingFreq);
- }
- /*
- virtual void buildUserInterface(UI* interface) {
- interface->openVerticalBox("excitator");
- interface->addButton("play", &fbutton0);
- interface->closeBox();
- }
+ /// \brief Stlot to excite (play) the string
+ void exciteString()
+ {
+ std::cout << "========= EXTICING STRING ===========" << std::endl;
+ fbutton0 = 1.0;
+ //std::cout << fbutton0 << std::endl;
+ QThread::usleep(280000); /// \todo Define this number based on the sampling rate and buffer size
+ fbutton0 = 0.0;
+ //std::cout << fbutton0 << std::endl;
+ }
+
+ //=========== FROM FAUST ===================================================
+private:
+ float fbutton0;
+ float fVec0[2];
+ float fRec0[2];
+ int iRec1[2];
+ float fVec1[2];
+public:
+ virtual int getNumInputs() { return 1; }
+ virtual int getNumOutputs() { return 1; }
+ static void classInit(int /*samplingFreq*/) {}
+ virtual void instanceInit(int samplingFreq) {
+ fSamplingFreq = samplingFreq;
+ fbutton0 = 0.0;
+ for (int i=0; i<2; i++) fVec0[i] = 0;
+ for (int i=0; i<2; i++) fRec0[i] = 0;
+ for (int i=0; i<2; i++) iRec1[i] = 0;
+ for (int i=0; i<2; i++) fVec1[i] = 0;
+ }
+ virtual void init(int samplingFreq) {
+ classInit(samplingFreq);
+ instanceInit(samplingFreq);
+ }
+ /*
+ virtual void buildUserInterface(UI* interface) {
+ interface->openVerticalBox("excitator");
+ interface->addButton("play", &fbutton0);
+ interface->closeBox();
+ }
*/
- virtual void compute (int count, float** input, float** output) {
- float* input0 = input[0];
- float* output0 = output[0];
- float fSlow0 = fbutton0;
- for (int i=0; i<count; i++) {
- fVec0[0] = fSlow0;
- fRec0[0] = ((((fSlow0 - fVec0[1]) > 0.000000f) + fRec0[1]) - (3.333333e-03f * (fRec0[1] > 0.000000f)));
- iRec1[0] = (12345 + (1103515245 * iRec1[1]));
- float fTemp0 = ((4.190951e-10f * iRec1[0]) * (fRec0[0] > 0.000000f));
- float fTemp1 = input0[i];
- fVec1[0] = (fTemp1 + fTemp0);
- output0[i] = (0.500000f * ((fTemp0 + fTemp1) + fVec1[1]));
- // post processing
- fVec1[1] = fVec1[0];
- iRec1[1] = iRec1[0];
- fRec0[1] = fRec0[0];
- fVec0[1] = fVec0[0];
- }
- }
-
- //============================================================================
+ virtual void compute (int count, float** input, float** output) {
+ float* input0 = input[0];
+ float* output0 = output[0];
+ float fSlow0 = fbutton0;
+ for (int i=0; i<count; i++) {
+ fVec0[0] = fSlow0;
+ fRec0[0] = ((((fSlow0 - fVec0[1]) > 0.000000f) + fRec0[1]) - (3.333333e-03f * (fRec0[1] > 0.000000f)));
+ iRec1[0] = (12345 + (1103515245 * iRec1[1]));
+ float fTemp0 = ((4.190951e-10f * iRec1[0]) * (fRec0[0] > 0.000000f));
+ float fTemp1 = input0[i];
+ fVec1[0] = (fTemp1 + fTemp0);
+ output0[i] = (0.500000f * ((fTemp0 + fTemp1) + fVec1[1]));
+ // post processing
+ fVec1[1] = fVec1[0];
+ iRec1[1] = iRec1[0];
+ fRec0[1] = fRec0[0];
+ fVec0[1] = fVec0[0];
+ }
+ }
+
+ //============================================================================
};
#endif // __NETKS_H__
-
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
void GetSystemTimeAsFileTime(FILETIME*);
inline int gettimeofday(struct timeval* p, void* tz /* IGNORED */)
{
- union {
- long long ns100; /*time since 1 Jan 1601 in 100ns units */
- FILETIME ft;
- } now;
- GetSystemTimeAsFileTime( &(now.ft) );
- p->tv_usec=(long)((now.ns100 / 10LL) % 1000000LL );
- p->tv_sec= (long)((now.ns100-(116444736000000000LL))/10000000LL);
- return 0;
+ union {
+ long long ns100; /*time since 1 Jan 1601 in 100ns units */
+ FILETIME ft;
+ } now;
+ GetSystemTimeAsFileTime( &(now.ft) );
+ p->tv_usec=(long)((now.ns100 / 10LL) % 1000000LL );
+ p->tv_sec= (long)((now.ns100-(116444736000000000LL))/10000000LL);
+ return 0;
}
#else
/* Must be defined somewhere else */
//####################### PacketHeader ##################################
//#######################################################################
//***********************************************************************
-PacketHeader::PacketHeader(JackTrip* jacktrip) :
- mSeqNumber(0), mJackTrip(jacktrip)
+PacketHeader::PacketHeader(JackTrip* jacktrip) :
+ mSeqNumber(0), mJackTrip(jacktrip)
{}
//***********************************************************************
uint64_t PacketHeader::usecTime()
{
- struct timeval tv;
- gettimeofday (&tv, NULL);
- return ( (tv.tv_sec * 1000000) + // seconds
- (tv.tv_usec) ); // plus the microseconds. Type suseconds_t, range [-1, 1000000]
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ return ( (tv.tv_sec * 1000000) + // seconds
+ (tv.tv_usec) ); // plus the microseconds. Type suseconds_t, range [-1, 1000000]
}
//####################### DefaultHeader #################################
//#######################################################################
//***********************************************************************
-DefaultHeader::DefaultHeader(JackTrip* jacktrip) :
- PacketHeader(jacktrip), mJackTrip(jacktrip)
+DefaultHeader::DefaultHeader(JackTrip* jacktrip) :
+ PacketHeader(jacktrip), mJackTrip(jacktrip)
{
- mHeader.TimeStamp = 0;
- mHeader.SeqNumber = 0;
- mHeader.BufferSize = 0;
- mHeader.SamplingRate = 0;
- mHeader.BitResolution = 0;
- //mHeader.NumInChannels = 0;
- //mHeader.NumOutChannels = 0;
- mHeader.NumChannels = 0;
- mHeader.ConnectionMode = 0;
+ mHeader.TimeStamp = 0;
+ mHeader.SeqNumber = 0;
+ mHeader.BufferSize = 0;
+ mHeader.SamplingRate = 0;
+ mHeader.BitResolution = 0;
+ //mHeader.NumInChannels = 0;
+ //mHeader.NumOutChannels = 0;
+ mHeader.NumChannels = 0;
+ mHeader.ConnectionMode = 0;
}
//***********************************************************************
void DefaultHeader::fillHeaderCommonFromAudio()
{
- mHeader.TimeStamp = PacketHeader::usecTime();
- mHeader.BufferSize = mJackTrip->getBufferSizeInSamples();
- mHeader.SamplingRate = mJackTrip->getSampleRateType ();
- mHeader.BitResolution = mJackTrip->getAudioBitResolution();
- mHeader.NumChannels = mJackTrip->getNumChannels();
- mHeader.ConnectionMode = static_cast<int>(mJackTrip->getConnectionMode());
- //printHeader();
+ mHeader.TimeStamp = PacketHeader::usecTime();
+ mHeader.BufferSize = mJackTrip->getBufferSizeInSamples();
+ mHeader.SamplingRate = mJackTrip->getSampleRateType ();
+ mHeader.BitResolution = mJackTrip->getAudioBitResolution();
+ mHeader.NumChannels = mJackTrip->getNumChannels();
+ mHeader.ConnectionMode = static_cast<int>(mJackTrip->getConnectionMode());
+ //printHeader();
}
//***********************************************************************
void DefaultHeader::checkPeerSettings(int8_t* full_packet)
{
- bool error = false;
-
- DefaultHeaderStruct* peer_header;
- peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+ bool error = false;
+
+ DefaultHeaderStruct* peer_header;
+ peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+
+ // Check Buffer Size
+ if ( peer_header->BufferSize != mHeader.BufferSize )
+ {
+ std::cerr << "ERROR: Peer Buffer Size is : " << peer_header->BufferSize << endl;
+ std::cerr << " Local Buffer Size is : " << mHeader.BufferSize << endl;
+ std::cerr << "Make sure both machines use same buffer size" << endl;
+ std::cerr << gPrintSeparator << endl;
+ error = true;
+ }
- // Check Buffer Size
- if ( peer_header->BufferSize != mHeader.BufferSize )
+ // Check Sampling Rate
+ if ( peer_header->SamplingRate != mHeader.SamplingRate )
{
- std::cerr << "ERROR: Peer Buffer Size is : " << peer_header->BufferSize << endl;
- std::cerr << " Local Buffer Size is : " << mHeader.BufferSize << endl;
- std::cerr << "Make sure both machines use same buffer size" << endl;
- std::cerr << gPrintSeparator << endl;
- error = true;
+ std::cerr << "ERROR: Peer Sampling Rate is : " <<
+ AudioInterface::getSampleRateFromType
+ ( static_cast<AudioInterface::samplingRateT>(peer_header->SamplingRate) ) << endl;
+ std::cerr << " Local Sampling Rate is : " <<
+ AudioInterface::getSampleRateFromType
+ ( static_cast<AudioInterface::samplingRateT>(mHeader.SamplingRate) ) << endl;
+ std::cerr << "Make sure both machines use the same Sampling Rate" << endl;
+ std::cerr << gPrintSeparator << endl;
+ error = true;
}
- // Check Sampling Rate
- if ( peer_header->SamplingRate != mHeader.SamplingRate )
- {
- std::cerr << "ERROR: Peer Sampling Rate is : " <<
- AudioInterface::getSampleRateFromType
- ( static_cast<AudioInterface::samplingRateT>(peer_header->SamplingRate) ) << endl;
- std::cerr << " Local Sampling Rate is : " <<
- AudioInterface::getSampleRateFromType
- ( static_cast<AudioInterface::samplingRateT>(mHeader.SamplingRate) ) << endl;
- std::cerr << "Make sure both machines use the same Sampling Rate" << endl;
- std::cerr << gPrintSeparator << endl;
- error = true;
- }
-
- // Check Audio Bit Resolution
- if ( peer_header->BitResolution != mHeader.BitResolution )
+ // Check Audio Bit Resolution
+ if ( peer_header->BitResolution != mHeader.BitResolution )
{
- std::cerr << "ERROR: Peer Audio Bit Resolution is : "
- << static_cast<int>(peer_header->BitResolution) << endl;
- std::cerr << " Local Audio Bit Resolution is : "
- << static_cast<int>(mHeader.BitResolution) << endl;
- std::cerr << "Make sure both machines use the same Bit Resolution" << endl;
- std::cerr << gPrintSeparator << endl;
- error = true;
+ std::cerr << "ERROR: Peer Audio Bit Resolution is : "
+ << static_cast<int>(peer_header->BitResolution) << endl;
+ std::cerr << " Local Audio Bit Resolution is : "
+ << static_cast<int>(mHeader.BitResolution) << endl;
+ std::cerr << "Make sure both machines use the same Bit Resolution" << endl;
+ std::cerr << gPrintSeparator << endl;
+ error = true;
}
- // Exit program if error
- if (error)
+ // Exit program if error
+ if (error)
{
- //std::cerr << "Exiting program..." << endl;
- //std::exit(1);
- //throw std::logic_error("Local and Peer Settings don't match");
- emit signalError("Local and Peer Settings don't match");
+ //std::cerr << "Exiting program..." << endl;
+ //std::exit(1);
+ //throw std::logic_error("Local and Peer Settings don't match");
+ emit signalError("Local and Peer Settings don't match");
}
- /// \todo Check number of channels and other parameters
+ /// \todo Check number of channels and other parameters
}
//***********************************************************************
void DefaultHeader::printHeader() const
{
- cout << "Default Packet Header:" << endl;
- cout << "Buffer Size = " << static_cast<int>(mHeader.BufferSize) << endl;
- // Get the sample rate in Hz form the AudioInterface::samplingRateT
- int sample_rate =
- AudioInterface::getSampleRateFromType
- ( static_cast<AudioInterface::samplingRateT>(mHeader.SamplingRate) );
- cout << "Sampling Rate = " << sample_rate << endl;
- cout << "Audio Bit Resolutions = " << static_cast<int>(mHeader.BitResolution) << endl;
- //cout << "Number of Input Channels = " << static_cast<int>(mHeader.NumInChannels) << endl;
- //cout << "Number of Output Channels = " << static_cast<int>(mHeader.NumOutChannels) << endl;
- cout << "Number of Channels = " << static_cast<int>(mHeader.NumChannels) << endl;
- cout << "Sequence Number = " << static_cast<int>(mHeader.SeqNumber) << endl;
- cout << "Time Stamp = " << mHeader.TimeStamp << endl;
- cout << "Connection Mode = " << static_cast<int>(mHeader.ConnectionMode) << endl;
- cout << gPrintSeparator << endl;
- //cout << sizeof(mHeader) << endl;
+ cout << "Default Packet Header:" << endl;
+ cout << "Buffer Size = " << static_cast<int>(mHeader.BufferSize) << endl;
+ // Get the sample rate in Hz form the AudioInterface::samplingRateT
+ int sample_rate =
+ AudioInterface::getSampleRateFromType
+ ( static_cast<AudioInterface::samplingRateT>(mHeader.SamplingRate) );
+ cout << "Sampling Rate = " << sample_rate << endl;
+ cout << "Audio Bit Resolutions = " << static_cast<int>(mHeader.BitResolution) << endl;
+ //cout << "Number of Input Channels = " << static_cast<int>(mHeader.NumInChannels) << endl;
+ //cout << "Number of Output Channels = " << static_cast<int>(mHeader.NumOutChannels) << endl;
+ cout << "Number of Channels = " << static_cast<int>(mHeader.NumChannels) << endl;
+ cout << "Sequence Number = " << static_cast<int>(mHeader.SeqNumber) << endl;
+ cout << "Time Stamp = " << mHeader.TimeStamp << endl;
+ cout << "Connection Mode = " << static_cast<int>(mHeader.ConnectionMode) << endl;
+ cout << gPrintSeparator << endl;
+ //cout << sizeof(mHeader) << endl;
}
//***********************************************************************
uint64_t DefaultHeader::getPeerTimeStamp(int8_t* full_packet) const
{
- DefaultHeaderStruct* peer_header;
- peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
- return peer_header->TimeStamp;
+ DefaultHeaderStruct* peer_header;
+ peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+ return peer_header->TimeStamp;
}
//***********************************************************************
uint16_t DefaultHeader::getPeerSequenceNumber(int8_t* full_packet) const
{
- DefaultHeaderStruct* peer_header;
- peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
- return peer_header->SeqNumber;
+ DefaultHeaderStruct* peer_header;
+ peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+ return peer_header->SeqNumber;
}
//***********************************************************************
uint16_t DefaultHeader::getPeerBufferSize(int8_t* full_packet) const
{
- DefaultHeaderStruct* peer_header;
- peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
- return peer_header->BufferSize;
+ DefaultHeaderStruct* peer_header;
+ peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+ return peer_header->BufferSize;
}
//***********************************************************************
uint8_t DefaultHeader::getPeerSamplingRate(int8_t* full_packet) const
{
- DefaultHeaderStruct* peer_header;
- peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
- return peer_header->SamplingRate;
+ DefaultHeaderStruct* peer_header;
+ peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+ return peer_header->SamplingRate;
}
//***********************************************************************
uint8_t DefaultHeader::getPeerBitResolution(int8_t* full_packet) const
{
- DefaultHeaderStruct* peer_header;
- peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
- return peer_header->BitResolution;
+ DefaultHeaderStruct* peer_header;
+ peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+ return peer_header->BitResolution;
}
//***********************************************************************
uint8_t DefaultHeader::getPeerNumChannels(int8_t* full_packet) const
{
- DefaultHeaderStruct* peer_header;
- peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
- return peer_header->NumChannels;
+ DefaultHeaderStruct* peer_header;
+ peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+ return peer_header->NumChannels;
}
//***********************************************************************
uint8_t DefaultHeader::getPeerConnectionMode(int8_t* full_packet) const
{
- DefaultHeaderStruct* peer_header;
- peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
- return static_cast<uint8_t>(peer_header->ConnectionMode);
+ DefaultHeaderStruct* peer_header;
+ peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+ return static_cast<uint8_t>(peer_header->ConnectionMode);
}
//#######################################################################
//***********************************************************************
JamLinkHeader::JamLinkHeader(JackTrip* jacktrip) :
- PacketHeader(jacktrip), mJackTrip(jacktrip)
+ PacketHeader(jacktrip), mJackTrip(jacktrip)
{
- mHeader.Common = 0;
- mHeader.SeqNumber = 0;
- mHeader.TimeStamp = 0;
+ mHeader.Common = 0;
+ mHeader.SeqNumber = 0;
+ mHeader.TimeStamp = 0;
}
//***********************************************************************
void JamLinkHeader::fillHeaderCommonFromAudio()
{
- // Check number of channels
- int num_inchannels = mJackTrip->getNumInputChannels();
- if ( num_inchannels != 1 ) {
- //std::cerr << "ERROR: JamLink only support ONE channel. Run JackTrip using only one channel"
- // << endl;
- //std::exit(1);
- //std::cerr << "WARINING: JamLink only support ONE channel. Run JackTrip using only one channel" << endl;
- //throw std::logic_error("JamLink only support ONE channel. Run JackTrip using only one channel");
- emit signalError("JamLink only support ONE channel. Run JackTrip using only one channel");
-
- }
-
- // Sampling Rate
- int rate_type = mJackTrip->getSampleRateType();
- if ( rate_type != AudioInterface::SR48 ) {
- //std::cerr << "WARINING: JamLink only support 48kHz for communication with JackTrip at the moment." << endl;
- //throw std::logic_error("ERROR: JamLink only support 48kHz for communication with JackTrip at the moment.");
- emit signalError("ERROR: JamLink only support 48kHz for communication with JackTrip at the moment.");
- }
-
- // Check Buffer Size
- int buf_size = mJackTrip->getBufferSizeInSamples();
- if ( buf_size != 64 ) {
- //std::cerr << "WARINING: JamLink only support 64 buffer size for communication with JackTrip at the moment." << endl;
- //throw std::logic_error("ERROR: JamLink only support 64 buffer size for communication with JackTrip at the moment.");
- emit signalError("ERROR: JamLink only support 64 buffer size for communication with JackTrip at the moment.");
- }
-
- mHeader.Common = (ETX_MONO | ETX_16BIT | ETX_XTND) + 64;
- switch (rate_type)
+ // Check number of channels
+ int num_inchannels = mJackTrip->getNumInputChannels();
+ if ( num_inchannels != 1 ) {
+ //std::cerr << "ERROR: JamLink only support ONE channel. Run JackTrip using only one channel"
+ // << endl;
+ //std::exit(1);
+ //std::cerr << "WARINING: JamLink only support ONE channel. Run JackTrip using only one channel" << endl;
+ //throw std::logic_error("JamLink only support ONE channel. Run JackTrip using only one channel");
+ emit signalError("JamLink only support ONE channel. Run JackTrip using only one channel");
+
+ }
+
+ // Sampling Rate
+ int rate_type = mJackTrip->getSampleRateType();
+ if ( rate_type != AudioInterface::SR48 ) {
+ //std::cerr << "WARINING: JamLink only support 48kHz for communication with JackTrip at the moment." << endl;
+ //throw std::logic_error("ERROR: JamLink only support 48kHz for communication with JackTrip at the moment.");
+ emit signalError("ERROR: JamLink only support 48kHz for communication with JackTrip at the moment.");
+ }
+
+ // Check Buffer Size
+ int buf_size = mJackTrip->getBufferSizeInSamples();
+ if ( buf_size != 64 ) {
+ //std::cerr << "WARINING: JamLink only support 64 buffer size for communication with JackTrip at the moment." << endl;
+ //throw std::logic_error("ERROR: JamLink only support 64 buffer size for communication with JackTrip at the moment.");
+ emit signalError("ERROR: JamLink only support 64 buffer size for communication with JackTrip at the moment.");
+ }
+
+ mHeader.Common = (ETX_MONO | ETX_16BIT | ETX_XTND) + 64;
+ switch (rate_type)
{
case AudioInterface::SR48 :
- mHeader.Common = (mHeader.Common | ETX_48KHZ);
- break;
+ mHeader.Common = (mHeader.Common | ETX_48KHZ);
+ break;
case AudioInterface::SR44 :
- mHeader.Common = (mHeader.Common | ETX_44KHZ);
- break;
+ mHeader.Common = (mHeader.Common | ETX_44KHZ);
+ break;
case AudioInterface::SR32 :
- mHeader.Common = (mHeader.Common | ETX_32KHZ);
- break;
+ mHeader.Common = (mHeader.Common | ETX_32KHZ);
+ break;
case AudioInterface::SR22 :
- mHeader.Common = (mHeader.Common | ETX_22KHZ);
- break;
+ mHeader.Common = (mHeader.Common | ETX_22KHZ);
+ break;
default:
- //std::cerr << "ERROR: Sample rate not supported by JamLink" << endl;
- //std::exit(1);
- //throw std::out_of_range("Sample rate not supported by JamLink");
- emit signalError("Sample rate not supported by JamLink.");
- break;
+ //std::cerr << "ERROR: Sample rate not supported by JamLink" << endl;
+ //std::exit(1);
+ //throw std::out_of_range("Sample rate not supported by JamLink");
+ emit signalError("Sample rate not supported by JamLink.");
+ break;
}
}
//#######################################################################
//***********************************************************************
EmptyHeader::EmptyHeader(JackTrip* jacktrip) :
- PacketHeader(jacktrip), mJackTrip(jacktrip)
+ PacketHeader(jacktrip), mJackTrip(jacktrip)
{}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
struct DefaultHeaderStruct : public HeaderStruct
{
public:
- // watch out for alignment...
- uint64_t TimeStamp; ///< Time Stamp
- uint16_t SeqNumber; ///< Sequence Number
- uint16_t BufferSize; ///< Buffer Size in Samples
- uint8_t SamplingRate; ///< Sampling Rate in JackAudioInterface::samplingRateT
- uint8_t BitResolution; ///< Audio Bit Resolution
- //uint8_t NumInChannels; ///< Number of Input Channels
- //uint8_t NumOutChannels; ///< Number of Output Channels
- uint8_t NumChannels; ///< Number of Channels, we assume input and outputs are the same
- uint8_t ConnectionMode;
+ // watch out for alignment...
+ uint64_t TimeStamp; ///< Time Stamp
+ uint16_t SeqNumber; ///< Sequence Number
+ uint16_t BufferSize; ///< Buffer Size in Samples
+ uint8_t SamplingRate; ///< Sampling Rate in JackAudioInterface::samplingRateT
+ uint8_t BitResolution; ///< Audio Bit Resolution
+ //uint8_t NumInChannels; ///< Number of Input Channels
+ //uint8_t NumOutChannels; ///< Number of Output Channels
+ uint8_t NumChannels; ///< Number of Channels, we assume input and outputs are the same
+ uint8_t ConnectionMode;
};
//---------------------------------------------------------
/* Its bit map is as follows: (b15-msb) */
/* B15:reserved, B14:extended header, B13 Stereo, B12 not 16-bit */
/* B11-B9: 0-48 Khz, 1-44 Khz, 2-32 Khz, 3-24 Khz, */
-/* 4-22 Khz, 5-16 Khz, 6-11 Khz, 7-8 Khz */
+/* 4-22 Khz, 5-16 Khz, 6-11 Khz, 7-8 Khz */
/* B8-0: Samples in packet */
/************************************************************************/
const unsigned short ETX_RSVD = (0<<15);
/// \brief JamLink Header Struct
struct JamLinkHeaderStuct : public HeaderStruct
{
- // watch out for alignment -- need to be on 4 byte chunks
- uint16_t Common; ///< Common part of the header, 16 bit
- uint16_t SeqNumber; ///< Sequence Number
- uint32_t TimeStamp; ///< Time Stamp
+ // watch out for alignment -- need to be on 4 byte chunks
+ uint16_t Common; ///< Common part of the header, 16 bit
+ uint16_t SeqNumber; ///< Sequence Number
+ uint32_t TimeStamp; ///< Time Stamp
};
*/
class PacketHeader : public QObject
{
- Q_OBJECT;
+ Q_OBJECT;
public:
- /// \brief The class Constructor
- PacketHeader(JackTrip* jacktrip);
- /// \brief The class Destructor
- virtual ~PacketHeader() {}
-
- /// \brief Return a time stamp in microseconds
- /// \return Time stamp: microseconds since midnight (0 hour), January 1, 1970
- static uint64_t usecTime();
- /// \todo Implement this using a JackTrip Method (Mediator) member instead of the
- /// reference to JackAudio
- virtual void fillHeaderCommonFromAudio() = 0;
- /// \brief Parse the packet header and take appropriate measures (like change settings, or
- /// quit the program if peer settings don't match)
- virtual void parseHeader() = 0;
- virtual void checkPeerSettings(int8_t* full_packet) = 0;
-
- virtual uint64_t getPeerTimeStamp(int8_t* full_packet) const = 0;
- virtual uint16_t getPeerSequenceNumber(int8_t* full_packet) const = 0;
- virtual uint16_t getPeerBufferSize(int8_t* full_packet) const = 0;
- virtual uint8_t getPeerSamplingRate(int8_t* full_packet) const = 0;
- virtual uint8_t getPeerBitResolution(int8_t* full_packet) const = 0;
- virtual uint8_t getPeerNumChannels(int8_t* full_packet) const = 0;
- virtual uint8_t getPeerConnectionMode(int8_t* full_packet) const = 0;
-
- /// \brief Increase sequence number for counter, a 16bit number
- virtual void increaseSequenceNumber()
- { mSeqNumber++; }
- /// \brief Returns the current sequence number
- /// \return 16bit Sequence number
- virtual uint16_t getSequenceNumber() const
- { return mSeqNumber; }
- /// \brief Get the header size in bytes
- virtual int getHeaderSizeInBytes() const = 0;
- virtual void putHeaderInPacketBaseClass(int8_t* full_packet,
- const HeaderStruct& header_struct)
- {
- std::memcpy(full_packet, reinterpret_cast<const void*>(&header_struct),
- getHeaderSizeInBytes() );
- }
- /// \brief Put the header in buffer pointed by full_packet
- /// \param full_packet Pointer to full packet (audio+header). Size must be
- /// sizeof(header part) + sizeof(audio part)
- virtual void putHeaderInPacket(int8_t* full_packet) = 0;
+ /// \brief The class Constructor
+ PacketHeader(JackTrip* jacktrip);
+ /// \brief The class Destructor
+ virtual ~PacketHeader() {}
+
+ /// \brief Return a time stamp in microseconds
+ /// \return Time stamp: microseconds since midnight (0 hour), January 1, 1970
+ static uint64_t usecTime();
+ /// \todo Implement this using a JackTrip Method (Mediator) member instead of the
+ /// reference to JackAudio
+ virtual void fillHeaderCommonFromAudio() = 0;
+ /// \brief Parse the packet header and take appropriate measures (like change settings, or
+ /// quit the program if peer settings don't match)
+ virtual void parseHeader() = 0;
+ virtual void checkPeerSettings(int8_t* full_packet) = 0;
+
+ virtual uint64_t getPeerTimeStamp(int8_t* full_packet) const = 0;
+ virtual uint16_t getPeerSequenceNumber(int8_t* full_packet) const = 0;
+ virtual uint16_t getPeerBufferSize(int8_t* full_packet) const = 0;
+ virtual uint8_t getPeerSamplingRate(int8_t* full_packet) const = 0;
+ virtual uint8_t getPeerBitResolution(int8_t* full_packet) const = 0;
+ virtual uint8_t getPeerNumChannels(int8_t* full_packet) const = 0;
+ virtual uint8_t getPeerConnectionMode(int8_t* full_packet) const = 0;
+
+ /// \brief Increase sequence number for counter, a 16bit number
+ virtual void increaseSequenceNumber()
+ { mSeqNumber++; }
+ /// \brief Returns the current sequence number
+ /// \return 16bit Sequence number
+ virtual uint16_t getSequenceNumber() const
+ { return mSeqNumber; }
+ /// \brief Get the header size in bytes
+ virtual int getHeaderSizeInBytes() const = 0;
+ virtual void putHeaderInPacketBaseClass(int8_t* full_packet,
+ const HeaderStruct& header_struct)
+ {
+ std::memcpy(full_packet, reinterpret_cast<const void*>(&header_struct),
+ getHeaderSizeInBytes() );
+ }
+ /// \brief Put the header in buffer pointed by full_packet
+ /// \param full_packet Pointer to full packet (audio+header). Size must be
+ /// sizeof(header part) + sizeof(audio part)
+ virtual void putHeaderInPacket(int8_t* full_packet) = 0;
signals:
- void signalError(const char* error_message);
+ void signalError(const char* error_message);
private:
- uint16_t mSeqNumber;
- JackTrip* mJackTrip; ///< JackTrip mediator class
+ uint16_t mSeqNumber;
+ JackTrip* mJackTrip; ///< JackTrip mediator class
};
{
public:
- DefaultHeader(JackTrip* jacktrip);
- virtual ~DefaultHeader() {}
-
- virtual void fillHeaderCommonFromAudio();
- virtual void parseHeader() {}
- virtual void checkPeerSettings(int8_t* full_packet);
- virtual void increaseSequenceNumber()
- { mHeader.SeqNumber++; }
- virtual uint16_t getSequenceNumber() const
- { return mHeader.SeqNumber; }
- virtual int getHeaderSizeInBytes() const { return sizeof(mHeader); }
- virtual void putHeaderInPacket(int8_t* full_packet)
- { putHeaderInPacketBaseClass(full_packet, mHeader); }
- void printHeader() const;
- uint8_t getConnectionMode() const
- { return mHeader.ConnectionMode; }
- uint8_t getNumChannels() const
- { return mHeader.NumChannels; }
-
-
- virtual uint64_t getPeerTimeStamp(int8_t* full_packet) const;
- virtual uint16_t getPeerSequenceNumber(int8_t* full_packet) const;
- virtual uint16_t getPeerBufferSize(int8_t* full_packet) const;
- virtual uint8_t getPeerSamplingRate(int8_t* full_packet) const;
- virtual uint8_t getPeerBitResolution(int8_t* full_packet) const;
- virtual uint8_t getPeerNumChannels(int8_t* full_packet) const;
- virtual uint8_t getPeerConnectionMode(int8_t* full_packet) const;
+ DefaultHeader(JackTrip* jacktrip);
+ virtual ~DefaultHeader() {}
+
+ virtual void fillHeaderCommonFromAudio();
+ virtual void parseHeader() {}
+ virtual void checkPeerSettings(int8_t* full_packet);
+ virtual void increaseSequenceNumber()
+ { mHeader.SeqNumber++; }
+ virtual uint16_t getSequenceNumber() const
+ { return mHeader.SeqNumber; }
+ virtual int getHeaderSizeInBytes() const { return sizeof(mHeader); }
+ virtual void putHeaderInPacket(int8_t* full_packet)
+ { putHeaderInPacketBaseClass(full_packet, mHeader); }
+ void printHeader() const;
+ uint8_t getConnectionMode() const
+ { return mHeader.ConnectionMode; }
+ uint8_t getNumChannels() const
+ { return mHeader.NumChannels; }
+
+
+ virtual uint64_t getPeerTimeStamp(int8_t* full_packet) const;
+ virtual uint16_t getPeerSequenceNumber(int8_t* full_packet) const;
+ virtual uint16_t getPeerBufferSize(int8_t* full_packet) const;
+ virtual uint8_t getPeerSamplingRate(int8_t* full_packet) const;
+ virtual uint8_t getPeerBitResolution(int8_t* full_packet) const;
+ virtual uint8_t getPeerNumChannels(int8_t* full_packet) const;
+ virtual uint8_t getPeerConnectionMode(int8_t* full_packet) const;
private:
- DefaultHeaderStruct mHeader;///< Default Header Struct
- JackTrip* mJackTrip; ///< JackTrip mediator class
+ DefaultHeaderStruct mHeader;///< Default Header Struct
+ JackTrip* mJackTrip; ///< JackTrip mediator class
};
class JamLinkHeader : public PacketHeader
{
public:
-
- JamLinkHeader(JackTrip* jacktrip);
- virtual ~JamLinkHeader() {}
-
- virtual void fillHeaderCommonFromAudio();
- virtual void parseHeader() {}
- virtual void checkPeerSettings(int8_t* /*full_packet*/) {}
-
- virtual uint64_t getPeerTimeStamp(int8_t* /*full_packet*/) const { return 0; }
- virtual uint16_t getPeerSequenceNumber(int8_t* /*full_packet*/) const { return 0; }
- virtual uint16_t getPeerBufferSize(int8_t* /*full_packet*/) const { return 0; }
- virtual uint8_t getPeerSamplingRate(int8_t* /*full_packet*/) const { return 0; }
- virtual uint8_t getPeerBitResolution(int8_t* /*full_packet*/) const { return 0; }
- virtual uint8_t getPeerNumChannels(int8_t* /*full_packet*/) const { return 0; }
- virtual uint8_t getPeerConnectionMode(int8_t* /*full_packet*/) const { return 0; }
-
- virtual void increaseSequenceNumber() {}
- virtual int getHeaderSizeInBytes() const { return sizeof(mHeader); }
- virtual void putHeaderInPacket(int8_t* full_packet)
- { putHeaderInPacketBaseClass(full_packet, mHeader); }
+
+ JamLinkHeader(JackTrip* jacktrip);
+ virtual ~JamLinkHeader() {}
+
+ virtual void fillHeaderCommonFromAudio();
+ virtual void parseHeader() {}
+ virtual void checkPeerSettings(int8_t* /*full_packet*/) {}
+
+ virtual uint64_t getPeerTimeStamp(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint16_t getPeerSequenceNumber(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint16_t getPeerBufferSize(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint8_t getPeerSamplingRate(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint8_t getPeerBitResolution(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint8_t getPeerNumChannels(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint8_t getPeerConnectionMode(int8_t* /*full_packet*/) const { return 0; }
+
+ virtual void increaseSequenceNumber() {}
+ virtual int getHeaderSizeInBytes() const { return sizeof(mHeader); }
+ virtual void putHeaderInPacket(int8_t* full_packet)
+ { putHeaderInPacketBaseClass(full_packet, mHeader); }
private:
- JamLinkHeaderStuct mHeader; ///< JamLink Header Struct
- JackTrip* mJackTrip; ///< JackTrip mediator class
+ JamLinkHeaderStuct mHeader; ///< JamLink Header Struct
+ JackTrip* mJackTrip; ///< JackTrip mediator class
};
class EmptyHeader : public PacketHeader
{
public:
-
- EmptyHeader(JackTrip* jacktrip);
- virtual ~EmptyHeader() {}
-
- virtual void fillHeaderCommonFromAudio() {}
- virtual void parseHeader() {}
- virtual void checkPeerSettings(int8_t* /*full_packet*/) {}
- virtual void increaseSequenceNumber() {}
- virtual int getHeaderSizeInBytes() const { return 0; }
-
- virtual uint64_t getPeerTimeStamp(int8_t* /*full_packet*/) const { return 0; }
- virtual uint16_t getPeerSequenceNumber(int8_t* /*full_packet*/) const { return 0; }
- virtual uint16_t getPeerBufferSize(int8_t* /*full_packet*/) const { return 0; }
- virtual uint8_t getPeerSamplingRate(int8_t* /*full_packet*/) const { return 0; }
- virtual uint8_t getPeerBitResolution(int8_t* /*full_packet*/) const { return 0; }
- virtual uint8_t getPeerNumChannels(int8_t* /*full_packet*/) const { return 0; }
- virtual uint8_t getPeerConnectionMode(int8_t* /*full_packet*/) const { return 0; }
-
- virtual void putHeaderInPacket(int8_t* /*full_packet*/) {}
+
+ EmptyHeader(JackTrip* jacktrip);
+ virtual ~EmptyHeader() {}
+
+ virtual void fillHeaderCommonFromAudio() {}
+ virtual void parseHeader() {}
+ virtual void checkPeerSettings(int8_t* /*full_packet*/) {}
+ virtual void increaseSequenceNumber() {}
+ virtual int getHeaderSizeInBytes() const { return 0; }
+
+ virtual uint64_t getPeerTimeStamp(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint16_t getPeerSequenceNumber(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint16_t getPeerBufferSize(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint8_t getPeerSamplingRate(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint8_t getPeerBitResolution(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint8_t getPeerNumChannels(int8_t* /*full_packet*/) const { return 0; }
+ virtual uint8_t getPeerConnectionMode(int8_t* /*full_packet*/) const { return 0; }
+
+ virtual void putHeaderInPacket(int8_t* /*full_packet*/) {}
private:
- JackTrip* mJackTrip; ///< JackTrip mediator class
+ JackTrip* mJackTrip; ///< JackTrip mediator class
};
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#include <jack/jack.h>
#include <QThread>
-/** \brief Interface for the process plugins to add to the JACK callback process in
+/** \brief Interface for the process plugins to add to the JACK callback process in
* JackAudioInterface
*
* This class contains the same methods of the FAUST dsp class. A mydsp class can inherit from
* this class the same way it inherits from dsp. Subclass should implement all methods
- * except init, which is optional for processing that are sampling rate dependent or
+ * except init, which is optional for processing that are sampling rate dependent or
* that need specific initialization.
*/
class ProcessPlugin : public QThread
{
public:
- /// \brief The Class Constructor
- ProcessPlugin() {};
- /// \brief The Class Destructor
- virtual ~ProcessPlugin() {};
-
- /// \brief Return Number of Input Channels
- virtual int getNumInputs() = 0;
- /// \brief Return Number of Output Channels
- virtual int getNumOutputs() = 0;
+ /// \brief The Class Constructor
+ ProcessPlugin() {};
+ /// \brief The Class Destructor
+ virtual ~ProcessPlugin() {};
- //virtual void buildUserInterface(UI* interface) = 0;
+ /// \brief Return Number of Input Channels
+ virtual int getNumInputs() = 0;
+ /// \brief Return Number of Output Channels
+ virtual int getNumOutputs() = 0;
- /** \brief Do proper Initialization of members and class instances. By default this
+ //virtual void buildUserInterface(UI* interface) = 0;
+
+ /** \brief Do proper Initialization of members and class instances. By default this
* initializes the Sampling Frequency. If a class instance depends on the
* sampling frequency, it should be initialize here.
*/
- virtual void init(int samplingRate) { fSamplingFreq = samplingRate; };
-
- /// \brief Compute process
- virtual void compute(int nframes, float** inputs, float** outputs) = 0;
-
+ virtual void init(int samplingRate) { fSamplingFreq = samplingRate; };
+
+ /// \brief Compute process
+ virtual void compute(int nframes, float** inputs, float** outputs) = 0;
+
protected:
- int fSamplingFreq; ///< Faust Data member, Sampling Rate
+ int fSamplingFreq; ///< Faust Data member, Sampling Rate
};
#endif
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//*******************************************************************************
-RingBuffer::RingBuffer(int SlotSize, int NumSlots) :
- mSlotSize(SlotSize),
- mNumSlots(NumSlots),
- mTotalSize(mSlotSize*mNumSlots),
- mReadPosition(0),
- mWritePosition(0),
- mFullSlots(0),
- mRingBuffer(new int8_t[mTotalSize]),
- mLastReadSlot(new int8_t[mSlotSize])
+RingBuffer::RingBuffer(int SlotSize, int NumSlots) :
+ mSlotSize(SlotSize),
+ mNumSlots(NumSlots),
+ mTotalSize(mSlotSize*mNumSlots),
+ mReadPosition(0),
+ mWritePosition(0),
+ mFullSlots(0),
+ mRingBuffer(new int8_t[mTotalSize]),
+ mLastReadSlot(new int8_t[mSlotSize])
{
- //QMutexLocker locker(&mMutex); // lock the mutex
-
- // Verify if there's enough space to for the buffers
- if ( (mRingBuffer == NULL) || (mLastReadSlot == NULL) ) {
- //std::cerr << "ERROR: RingBuffer out of memory!" << endl;
- //std::cerr << "Exiting program..." << endl;
- //std::exit(1);
- throw std::length_error("RingBuffer out of memory!");
- }
-
- // Set the buffers to zeros
- /*
+ //QMutexLocker locker(&mMutex); // lock the mutex
+
+ // Verify if there's enough space to for the buffers
+ if ( (mRingBuffer == NULL) || (mLastReadSlot == NULL) ) {
+ //std::cerr << "ERROR: RingBuffer out of memory!" << endl;
+ //std::cerr << "Exiting program..." << endl;
+ //std::exit(1);
+ throw std::length_error("RingBuffer out of memory!");
+ }
+
+ // Set the buffers to zeros
+ /*
for (int i=0; i<mTotalSize; i++) {
mRingBuffer[i] = 0; // Initialize all elements to zero.
}
*/
- std::memset(mRingBuffer, 0, mTotalSize); // set buffer to 0
- /*
+ std::memset(mRingBuffer, 0, mTotalSize); // set buffer to 0
+ /*
for (int i=0; i<mSlotSize; i++) {
mLastReadSlot[i] = 0; // Initialize all elements to zero.
}
*/
- std::memset(mLastReadSlot, 0, mSlotSize); // set buffer to 0
-
-
- // Advance write position to half of the RingBuffer
- mWritePosition = ( (NumSlots/2) * SlotSize ) % mTotalSize;
- // Udpate Full Slots accordingly
- mFullSlots = (NumSlots/2);
+ std::memset(mLastReadSlot, 0, mSlotSize); // set buffer to 0
+
+
+ // Advance write position to half of the RingBuffer
+ mWritePosition = ( (NumSlots/2) * SlotSize ) % mTotalSize;
+ // Udpate Full Slots accordingly
+ mFullSlots = (NumSlots/2);
}
//*******************************************************************************
RingBuffer::~RingBuffer()
{
- delete[] mRingBuffer; // Free memory
- mRingBuffer = NULL; // Clear to prevent using invalid memory reference
- delete[] mLastReadSlot;
- mLastReadSlot = NULL;
+ delete[] mRingBuffer; // Free memory
+ mRingBuffer = NULL; // Clear to prevent using invalid memory reference
+ delete[] mLastReadSlot;
+ mLastReadSlot = NULL;
}
//*******************************************************************************
void RingBuffer::insertSlotBlocking(const int8_t* ptrToSlot)
{
- QMutexLocker locker(&mMutex); // lock the mutex
-
- // Check if there is space available to write a slot
- // If the Ringbuffer is full, it waits for the bufferIsNotFull condition
- while (mFullSlots == mNumSlots) {
- //std::cout << "OUPUT OVERFLOW BLOCKING" << std::endl;
- mBufferIsNotFull.wait(&mMutex);
- }
-
- // Copy mSlotSize bytes to mRingBuffer
- std::memcpy(mRingBuffer+mWritePosition, ptrToSlot, mSlotSize);
- // Update write position
- mWritePosition = (mWritePosition+mSlotSize) % mTotalSize;
- mFullSlots++; //update full slots
- // Wake threads waitng for bufferIsNotFull condition
- mBufferIsNotEmpty.wakeAll();
+ QMutexLocker locker(&mMutex); // lock the mutex
+
+ // Check if there is space available to write a slot
+ // If the Ringbuffer is full, it waits for the bufferIsNotFull condition
+ while (mFullSlots == mNumSlots) {
+ //std::cout << "OUPUT OVERFLOW BLOCKING" << std::endl;
+ mBufferIsNotFull.wait(&mMutex);
+ }
+
+ // Copy mSlotSize bytes to mRingBuffer
+ std::memcpy(mRingBuffer+mWritePosition, ptrToSlot, mSlotSize);
+ // Update write position
+ mWritePosition = (mWritePosition+mSlotSize) % mTotalSize;
+ mFullSlots++; //update full slots
+ // Wake threads waitng for bufferIsNotFull condition
+ mBufferIsNotEmpty.wakeAll();
}
//*******************************************************************************
void RingBuffer::readSlotBlocking(int8_t* ptrToReadSlot)
{
- QMutexLocker locker(&mMutex); // lock the mutex
-
- // Check if there are slots available to read
- // If the Ringbuffer is empty, it waits for the bufferIsNotEmpty condition
- while (mFullSlots == 0) {
- //std::cerr << "READ UNDER-RUN BLOCKING before" << endl;
- mBufferIsNotEmpty.wait(&mMutex);
- }
-
- // Copy mSlotSize bytes to ReadSlot
- std::memcpy(ptrToReadSlot, mRingBuffer+mReadPosition, mSlotSize);
- // Always save memory of the last read slot
- std::memcpy(mLastReadSlot, mRingBuffer+mReadPosition, mSlotSize);
- // Update write position
- mReadPosition = (mReadPosition+mSlotSize) % mTotalSize;
- mFullSlots--; //update full slots
- // Wake threads waitng for bufferIsNotFull condition
- mBufferIsNotFull.wakeAll();
+ QMutexLocker locker(&mMutex); // lock the mutex
+
+ // Check if there are slots available to read
+ // If the Ringbuffer is empty, it waits for the bufferIsNotEmpty condition
+ while (mFullSlots == 0) {
+ //std::cerr << "READ UNDER-RUN BLOCKING before" << endl;
+ mBufferIsNotEmpty.wait(&mMutex);
+ }
+
+ // Copy mSlotSize bytes to ReadSlot
+ std::memcpy(ptrToReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+ // Always save memory of the last read slot
+ std::memcpy(mLastReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+ // Update write position
+ mReadPosition = (mReadPosition+mSlotSize) % mTotalSize;
+ mFullSlots--; //update full slots
+ // Wake threads waitng for bufferIsNotFull condition
+ mBufferIsNotFull.wakeAll();
}
//*******************************************************************************
void RingBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot)
{
- QMutexLocker locker(&mMutex); // lock the mutex
-
- // Check if there is space available to write a slot
- // If the Ringbuffer is full, it returns without writing anything
- // and resets the buffer
- /// \todo It may be better here to insert the slot anyways,
- /// instead of not writing anything
- if (mFullSlots == mNumSlots) {
- //std::cout << "OUPUT OVERFLOW NON BLOCKING = " << mNumSlots << std::endl;
- overflowReset();
- return;
- }
-
- // Copy mSlotSize bytes to mRingBuffer
- std::memcpy(mRingBuffer+mWritePosition, ptrToSlot, mSlotSize);
- // Update write position
- mWritePosition = (mWritePosition+mSlotSize) % mTotalSize;
- mFullSlots++; //update full slots
- // Wake threads waitng for bufferIsNotFull condition
- mBufferIsNotEmpty.wakeAll();
+ QMutexLocker locker(&mMutex); // lock the mutex
+
+ // Check if there is space available to write a slot
+ // If the Ringbuffer is full, it returns without writing anything
+ // and resets the buffer
+ /// \todo It may be better here to insert the slot anyways,
+ /// instead of not writing anything
+ if (mFullSlots == mNumSlots) {
+ //std::cout << "OUPUT OVERFLOW NON BLOCKING = " << mNumSlots << std::endl;
+ overflowReset();
+ return;
+ }
+
+ // Copy mSlotSize bytes to mRingBuffer
+ std::memcpy(mRingBuffer+mWritePosition, ptrToSlot, mSlotSize);
+ // Update write position
+ mWritePosition = (mWritePosition+mSlotSize) % mTotalSize;
+ mFullSlots++; //update full slots
+ // Wake threads waitng for bufferIsNotFull condition
+ mBufferIsNotEmpty.wakeAll();
}
//*******************************************************************************
void RingBuffer::readSlotNonBlocking(int8_t* ptrToReadSlot)
{
- QMutexLocker locker(&mMutex); // lock the mutex
-
-
- // Check if there are slots available to read
- // If the Ringbuffer is empty, it returns a buffer of zeros and rests the buffer
- if (mFullSlots == 0) {
- // Returns a buffer of zeros if there's nothing to read
- //std::cerr << "READ UNDER-RUN NON BLOCKING = " << mNumSlots << endl;
- //std::memset(ptrToReadSlot, 0, mSlotSize);
- setUnderrunReadSlot(ptrToReadSlot);
- underrunReset();
- return;
- }
-
- // Copy mSlotSize bytes to ReadSlot
- std::memcpy(ptrToReadSlot, mRingBuffer+mReadPosition, mSlotSize);
- // Always save memory of the last read slot
- std::memcpy(mLastReadSlot, mRingBuffer+mReadPosition, mSlotSize);
- // Update write position
- mReadPosition = (mReadPosition+mSlotSize) % mTotalSize;
- mFullSlots--; //update full slots
- // Wake threads waitng for bufferIsNotFull condition
- mBufferIsNotFull.wakeAll();
+ QMutexLocker locker(&mMutex); // lock the mutex
+
+
+ // Check if there are slots available to read
+ // If the Ringbuffer is empty, it returns a buffer of zeros and rests the buffer
+ if (mFullSlots == 0) {
+ // Returns a buffer of zeros if there's nothing to read
+ //std::cerr << "READ UNDER-RUN NON BLOCKING = " << mNumSlots << endl;
+ //std::memset(ptrToReadSlot, 0, mSlotSize);
+ setUnderrunReadSlot(ptrToReadSlot);
+ underrunReset();
+ return;
+ }
+
+ // Copy mSlotSize bytes to ReadSlot
+ std::memcpy(ptrToReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+ // Always save memory of the last read slot
+ std::memcpy(mLastReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+ // Update write position
+ mReadPosition = (mReadPosition+mSlotSize) % mTotalSize;
+ mFullSlots--; //update full slots
+ // Wake threads waitng for bufferIsNotFull condition
+ mBufferIsNotFull.wakeAll();
}
//*******************************************************************************
void RingBuffer::setUnderrunReadSlot(int8_t* ptrToReadSlot)
{
- std::memset(ptrToReadSlot, 0, mSlotSize);
+ std::memset(ptrToReadSlot, 0, mSlotSize);
}
//*******************************************************************************
void RingBuffer::setMemoryInReadSlotWithLastReadSlot(int8_t* ptrToReadSlot)
{
- std::memcpy(ptrToReadSlot, mLastReadSlot, mSlotSize);
+ std::memcpy(ptrToReadSlot, mLastReadSlot, mSlotSize);
}
// Under-run happens when there's nothing to read.
void RingBuffer::underrunReset()
{
- // Advance the write pointer 1/2 the ring buffer
- //mWritePosition = ( mReadPosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
- //mWritePosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
- //mFullSlots += mNumSlots/2;
- // There's nothing new to read, so we clear the whole buffer (Set the entire buffer to 0)
- std::memset(mRingBuffer, 0, mTotalSize);
+ // Advance the write pointer 1/2 the ring buffer
+ //mWritePosition = ( mReadPosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
+ //mWritePosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
+ //mFullSlots += mNumSlots/2;
+ // There's nothing new to read, so we clear the whole buffer (Set the entire buffer to 0)
+ std::memset(mRingBuffer, 0, mTotalSize);
}
// Over-flow happens when there's no space to write more slots.
void RingBuffer::overflowReset()
{
- // Advance the read pointer 1/2 the ring buffer
- //mReadPosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
- mReadPosition = ( mReadPosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
- mFullSlots -= mNumSlots/2;
+ // Advance the read pointer 1/2 the ring buffer
+ //mReadPosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
+ mReadPosition = ( mReadPosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
+ mFullSlots -= mNumSlots/2;
}
//*******************************************************************************
void RingBuffer::debugDump() const
{
- cout << "mTotalSize = " << mTotalSize << endl;
- cout << "mReadPosition = " << mReadPosition << endl;
- cout << "mWritePosition = " << mWritePosition << endl;
- cout << "mFullSlots = " << mFullSlots << endl;
+ cout << "mTotalSize = " << mTotalSize << endl;
+ cout << "mReadPosition = " << mReadPosition << endl;
+ cout << "mWritePosition = " << mWritePosition << endl;
+ cout << "mFullSlots = " << mFullSlots << endl;
}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* asynchronously (blocking) or synchronously (non-blocking).
*
* The RingBuffer is an array of \b NumSlots slots of memory
- * each of which is of size \b SlotSize bytes (8-bits). Slots can be read and
+ * each of which is of size \b SlotSize bytes (8-bits). Slots can be read and
* written asynchronously/synchronously by multiple threads.
*/
class RingBuffer
{
public:
- /** \brief The class constructor
+ /** \brief The class constructor
* \param SlotSize Size of one slot in bytes
* \param NumSlots Number of slots
*/
- RingBuffer(int SlotSize, int NumSlots);
+ RingBuffer(int SlotSize, int NumSlots);
- /** \brief The class destructor
+ /** \brief The class destructor
*/
- virtual ~RingBuffer();
-
- /** \brief Insert a slot into the RingBuffer from ptrToSlot. This method will block until
+ virtual ~RingBuffer();
+
+ /** \brief Insert a slot into the RingBuffer from ptrToSlot. This method will block until
* there's space in the buffer.
*
* The caller is responsible to make sure sizeof(WriteSlot) = SlotSize. This
- * method should be use when the caller can block against its output, like
+ * method should be use when the caller can block against its output, like
* sending/receiving UDP packets. It shouldn't be used by audio. For that, use the
* insertSlotNonBlocking.
* \param ptrToSlot Pointer to slot to insert into the RingBuffer
*/
- void insertSlotBlocking(const int8_t* ptrToSlot);
-
- /** \brief Read a slot from the RingBuffer into ptrToReadSlot. This method will block until
+ void insertSlotBlocking(const int8_t* ptrToSlot);
+
+ /** \brief Read a slot from the RingBuffer into ptrToReadSlot. This method will block until
* there's space in the buffer.
*
* The caller is responsible to make sure sizeof(ptrToReadSlot) = SlotSize. This
- * method should be use when the caller can block against its input, like
+ * method should be use when the caller can block against its input, like
* sending/receiving UDP packets. It shouldn't be used by audio. For that, use the
- * readSlotNonBlocking.
+ * readSlotNonBlocking.
* \param ptrToReadSlot Pointer to read slot from the RingBuffer
*/
- void readSlotBlocking(int8_t* ptrToReadSlot);
-
- /** \brief Same as insertSlotBlocking but non-blocking (asynchronous)
+ void readSlotBlocking(int8_t* ptrToReadSlot);
+
+ /** \brief Same as insertSlotBlocking but non-blocking (asynchronous)
* \param ptrToSlot Pointer to slot to insert into the RingBuffer
*/
- void insertSlotNonBlocking(const int8_t* ptrToSlot);
-
- /** \brief Same as readSlotBlocking but non-blocking (asynchronous)
+ void insertSlotNonBlocking(const int8_t* ptrToSlot);
+
+ /** \brief Same as readSlotBlocking but non-blocking (asynchronous)
* \param ptrToReadSlot Pointer to read slot from the RingBuffer
*/
- void readSlotNonBlocking(int8_t* ptrToReadSlot);
+ void readSlotNonBlocking(int8_t* ptrToReadSlot);
protected:
- /** \brief Sets the memory in the Read Slot when uderrun occurs. By default,
+ /** \brief Sets the memory in the Read Slot when uderrun occurs. By default,
* this sets it to 0. Override this method in a subclass for a different behavior.
* \param ptrToReadSlot Pointer to read slot from the RingBuffer
*/
- virtual void setUnderrunReadSlot(int8_t* ptrToReadSlot);
+ virtual void setUnderrunReadSlot(int8_t* ptrToReadSlot);
- /** \brief Uses the last read slot to set the memory in the Read Slot.
- *
- * The last read slot is the last packet that arrived, so if no new packets are received,
+ /** \brief Uses the last read slot to set the memory in the Read Slot.
+ *
+ * The last read slot is the last packet that arrived, so if no new packets are received,
* it keeps looping the same packet.
* \param ptrToReadSlot Pointer to read slot from the RingBuffer
*/
- virtual void setMemoryInReadSlotWithLastReadSlot(int8_t* ptrToReadSlot);
+ virtual void setMemoryInReadSlotWithLastReadSlot(int8_t* ptrToReadSlot);
private:
- /// \brief Resets the ring buffer for reads under-runs non-blocking
- void underrunReset();
- /// \brief Resets the ring buffer for writes over-flows non-blocking
- void overflowReset();
- /// \brief Helper method to debug, prints member variables to terminal
- void debugDump() const;
-
- const int mSlotSize; ///< The size of one slot in byes
- const int mNumSlots; ///< Number of Slots
- const int mTotalSize; ///< Total size of the mRingBuffer = mSlotSize*mNumSlotss
- int mReadPosition; ///< Read Positions in the RingBuffer (Tail)
- int mWritePosition; ///< Write Position in the RingBuffer (Head)
- int mFullSlots; ///< Number of used (full) slots, in slot-size
- int8_t* mRingBuffer; ///< 8-bit array of data (1-byte)
- int8_t* mLastReadSlot; ///< Last slot read
-
- // Thread Synchronization Private Members
- QMutex mMutex; ///< Mutex to protect read and write operations
- QWaitCondition mBufferIsNotFull; ///< Buffer not full condition to monitor threads
- QWaitCondition mBufferIsNotEmpty; ///< Buffer not empty condition to monitor threads
+ /// \brief Resets the ring buffer for reads under-runs non-blocking
+ void underrunReset();
+ /// \brief Resets the ring buffer for writes over-flows non-blocking
+ void overflowReset();
+ /// \brief Helper method to debug, prints member variables to terminal
+ void debugDump() const;
+
+ const int mSlotSize; ///< The size of one slot in byes
+ const int mNumSlots; ///< Number of Slots
+ const int mTotalSize; ///< Total size of the mRingBuffer = mSlotSize*mNumSlotss
+ int mReadPosition; ///< Read Positions in the RingBuffer (Tail)
+ int mWritePosition; ///< Write Position in the RingBuffer (Head)
+ int mFullSlots; ///< Number of used (full) slots, in slot-size
+ int8_t* mRingBuffer; ///< 8-bit array of data (1-byte)
+ int8_t* mLastReadSlot; ///< Last slot read
+
+ // Thread Synchronization Private Members
+ QMutex mMutex; ///< Mutex to protect read and write operations
+ QWaitCondition mBufferIsNotFull; ///< Buffer not full condition to monitor threads
+ QWaitCondition mBufferIsNotEmpty; ///< Buffer not empty condition to monitor threads
};
#endif
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
class RingBufferWavetable : public RingBuffer
{
public:
- /** \brief The class constructor
+ /** \brief The class constructor
* \param SlotSize Size of one slot in bytes
* \param NumSlots Number of slots
*/
- RingBufferWavetable(int SlotSize, int NumSlots) : RingBuffer(SlotSize, NumSlots) {}
+ RingBufferWavetable(int SlotSize, int NumSlots) : RingBuffer(SlotSize, NumSlots) {}
- /** \brief The class destructor
+ /** \brief The class destructor
*/
- virtual ~RingBufferWavetable() {}
+ virtual ~RingBufferWavetable() {}
protected:
- /** \brief Sets the memory in the Read Slot when uderrun occurs. This loops as a
+ /** \brief Sets the memory in the Read Slot when uderrun occurs. This loops as a
* wavetable in the last received packet.
* \param ptrToReadSlot Pointer to read slot from the RingBuffer
*/
- virtual void setUnderrunReadSlot(int8_t* ptrToReadSlot)
- {
- setMemoryInReadSlotWithLastReadSlot(ptrToReadSlot);
- }
+ virtual void setUnderrunReadSlot(int8_t* ptrToReadSlot)
+ {
+ setMemoryInReadSlotWithLastReadSlot(ptrToReadSlot);
+ }
};
RtAudioInterface::RtAudioInterface(JackTrip* jacktrip,
int NumInChans, int NumOutChans,
audioBitResolutionT AudioBitResolution) :
-AudioInterface(jacktrip,
- NumInChans, NumOutChans,
- AudioBitResolution),
-mJackTrip(jacktrip),
-mRtAudio(NULL)
+ AudioInterface(jacktrip,
+ NumInChans, NumOutChans,
+ AudioBitResolution),
+ mJackTrip(jacktrip),
+ mRtAudio(NULL)
{}
//*******************************************************************************
RtAudioInterface::~RtAudioInterface()
{
- delete mRtAudio;
+ delete mRtAudio;
}
//*******************************************************************************
void RtAudioInterface::setup()
{
- // Initialize Buffer array to read and write audio and members
- mNumInChans = getNumInputChannels();
- mNumOutChans = getNumOutputChannels();
- mInBuffer.resize(getNumInputChannels());
- mOutBuffer.resize(getNumOutputChannels());
-
- cout << "Settin Up Default RtAudio Interface" << endl;
- cout << gPrintSeparator << endl;
- mRtAudio = new RtAudio;
- if ( mRtAudio->getDeviceCount() < 1 ) {
- cout << "No audio devices found!" << endl;
- std::exit(0);
- }
+ // Initialize Buffer array to read and write audio and members
+ mNumInChans = getNumInputChannels();
+ mNumOutChans = getNumOutputChannels();
+ mInBuffer.resize(getNumInputChannels());
+ mOutBuffer.resize(getNumOutputChannels());
+
+ cout << "Settin Up Default RtAudio Interface" << endl;
+ cout << gPrintSeparator << endl;
+ mRtAudio = new RtAudio;
+ if ( mRtAudio->getDeviceCount() < 1 ) {
+ cout << "No audio devices found!" << endl;
+ std::exit(0);
+ }
- // Get and print default devices
- RtAudio::DeviceInfo info_input;
- RtAudio::DeviceInfo info_output;
-
- int deviceId_input; int deviceId_output;
- // use default devices
- deviceId_input = mRtAudio->getDefaultInputDevice();
- deviceId_output = mRtAudio->getDefaultOutputDevice();
-
- cout << "DEFAULT INPUT DEVICE : " << endl;
- printDeviceInfo(deviceId_input);
- cout << gPrintSeparator << endl;
- cout << "DEFAULT OUTPUT DEVICE : " << endl;
- printDeviceInfo(deviceId_output);
- cout << gPrintSeparator << endl;
-
- RtAudio::StreamParameters in_params, out_params;
- in_params.deviceId = mRtAudio->getDefaultInputDevice();
- out_params.deviceId = mRtAudio->getDefaultOutputDevice();
- in_params.nChannels = getNumInputChannels();
- out_params.nChannels = getNumOutputChannels();
-
- RtAudio::StreamOptions options;
- //The second flag affects linux and mac only
- options.flags = RTAUDIO_NONINTERLEAVED | RTAUDIO_SCHEDULE_REALTIME;
+ // Get and print default devices
+ RtAudio::DeviceInfo info_input;
+ RtAudio::DeviceInfo info_output;
+
+ uint32_t deviceId_input; uint32_t deviceId_output;
+ // use default devices
+ deviceId_input = mJackTrip->getDeviceID();
+ deviceId_output = mJackTrip->getDeviceID();
+
+ cout << "DEFAULT INPUT DEVICE : " << endl;
+ printDeviceInfo(deviceId_input);
+ cout << gPrintSeparator << endl;
+ cout << "DEFAULT OUTPUT DEVICE : " << endl;
+ printDeviceInfo(deviceId_output);
+ cout << gPrintSeparator << endl;
+
+ RtAudio::StreamParameters in_params, out_params;
+ in_params.deviceId = deviceId_input;
+ out_params.deviceId = deviceId_output;
+ in_params.nChannels = getNumInputChannels();
+ out_params.nChannels = getNumOutputChannels();
+
+ RtAudio::StreamOptions options;
+ //The second flag affects linux and mac only
+ options.flags = RTAUDIO_NONINTERLEAVED | RTAUDIO_SCHEDULE_REALTIME;
#ifdef __WIN_32__
- options.flags = options.flags | RTAUDIO_MINIMIZE_LATENCY;
+ options.flags = options.flags | RTAUDIO_MINIMIZE_LATENCY;
#endif
- //linux only
- options.priority = 99;
-
- unsigned int sampleRate = getSampleRate();//mSamplingRate;
- unsigned int bufferFrames = getBufferSizeInSamples();//mBufferSize;
-
- try {
- // IMPORTANT NOTE: It's VERY important to remember to pass this
- // as the user data in the process callback, otherwise memeber won't
- // be accessible
- mRtAudio->openStream(&out_params, &in_params, RTAUDIO_FLOAT32,
- sampleRate, &bufferFrames,
- &RtAudioInterface::wrapperRtAudioCallback, this, &options);
- }
- catch ( RtError& e ) {
- std::cout << '\n' << e.getMessage() << '\n' << std::endl;
- exit( 0 );
- }
+ //linux only
+ options.priority = 99;
+
+ unsigned int sampleRate = getSampleRate();//mSamplingRate;
+ unsigned int bufferFrames = getBufferSizeInSamples();//mBufferSize;
+
+ try {
+ // IMPORTANT NOTE: It's VERY important to remember to pass this
+ // as the user data in the process callback, otherwise memeber won't
+ // be accessible
+ mRtAudio->openStream(&out_params, &in_params, RTAUDIO_FLOAT32,
+ sampleRate, &bufferFrames,
+ &RtAudioInterface::wrapperRtAudioCallback, this, &options);
+ }
+ catch ( RtAudioError & e ) {
+ std::cout << '\n' << e.getMessage() << '\n' << std::endl;
+ exit( 0 );
+ }
- // Setup parent class
- AudioInterface::setup();
+ // Setup parent class
+ AudioInterface::setup();
}
//*******************************************************************************
void RtAudioInterface::listAllInterfaces()
{
- RtAudio rtaudio;
- if ( rtaudio.getDeviceCount() < 1 ) {
- cout << "No audio devices found!" << endl; }
- else {
- for (unsigned int i = 0; i < rtaudio.getDeviceCount(); i++) {
- printDeviceInfo(i);
- cout << gPrintSeparator << endl;
+ RtAudio rtaudio;
+ if ( rtaudio.getDeviceCount() < 1 ) {
+ cout << "No audio devices found!" << endl; }
+ else {
+ for (unsigned int i = 0; i < rtaudio.getDeviceCount(); i++) {
+ printDeviceInfo(i);
+ cout << gPrintSeparator << endl;
+ }
}
- }
}
//*******************************************************************************
void RtAudioInterface::printDeviceInfo(unsigned int deviceId)
{
- RtAudio rtaudio;
- RtAudio::DeviceInfo info;
- int i = deviceId;
- info = rtaudio.getDeviceInfo(i);
- std::vector<unsigned int> sampleRates;
- cout << "Audio Device [" << i << "] : " << info.name << endl;
- cout << " Output Channels : " << info.outputChannels << endl;
- cout << " Input Channels : " << info.inputChannels << endl;
- sampleRates = info.sampleRates;
- cout << " Supported Sampling Rates: ";
- for (unsigned int ii = 0; ii<sampleRates.size();ii++) {
- cout << sampleRates[ii] << " ";
- }
- cout << endl;
- if (info.isDefaultOutput) {
- cout << " --Default Output Device--" << endl; }
- if (info.isDefaultInput) {
- cout << " --Default Intput Device--" << endl; }
- if (info.probed) {
- cout << " --Probed Successful--" << endl; }
+ RtAudio rtaudio;
+ RtAudio::DeviceInfo info;
+ int i = deviceId;
+ info = rtaudio.getDeviceInfo(i);
+ std::vector<unsigned int> sampleRates;
+ cout << "Audio Device [" << i << "] : " << info.name << endl;
+ cout << " Output Channels : " << info.outputChannels << endl;
+ cout << " Input Channels : " << info.inputChannels << endl;
+ sampleRates = info.sampleRates;
+ cout << " Supported Sampling Rates: ";
+ for (unsigned int ii = 0; ii<sampleRates.size();ii++) {
+ cout << sampleRates[ii] << " ";
+ }
+ cout << endl;
+ if (info.isDefaultOutput) {
+ cout << " --Default Output Device--" << endl; }
+ if (info.isDefaultInput) {
+ cout << " --Default Intput Device--" << endl; }
+ if (info.probed) {
+ cout << " --Probed Successful--" << endl; }
}
unsigned int nFrames,
double /*streamTime*/, RtAudioStreamStatus /*status*/)
{
- sample_t* inputBuffer_sample = (sample_t*) inputBuffer;
- sample_t* outputBuffer_sample = (sample_t*) outputBuffer;
-
- // Get input and output buffers
- //-------------------------------------------------------------------
- for (int i = 0; i < mNumInChans; i++) {
- // Input Ports are READ ONLY
- mInBuffer[i] = inputBuffer_sample+(nFrames*i);
- }
- for (int i = 0; i < mNumOutChans; i++) {
- // Output Ports are WRITABLE
- mOutBuffer[i] = outputBuffer_sample+(nFrames*i);
- }
+ sample_t* inputBuffer_sample = (sample_t*) inputBuffer;
+ sample_t* outputBuffer_sample = (sample_t*) outputBuffer;
+
+ // Get input and output buffers
+ //-------------------------------------------------------------------
+ for (int i = 0; i < mNumInChans; i++) {
+ // Input Ports are READ ONLY
+ mInBuffer[i] = inputBuffer_sample+(nFrames*i);
+ }
+ for (int i = 0; i < mNumOutChans; i++) {
+ // Output Ports are WRITABLE
+ mOutBuffer[i] = outputBuffer_sample+(nFrames*i);
+ }
- AudioInterface::callback(mInBuffer, mOutBuffer, nFrames);
- return 0;
+ AudioInterface::callback(mInBuffer, mOutBuffer, nFrames);
+ return 0;
}
unsigned int nFrames, double streamTime,
RtAudioStreamStatus status, void *userData)
{
- return static_cast<RtAudioInterface*>(userData)->RtAudioCallback(outputBuffer,inputBuffer,
- nFrames,
- streamTime, status);
+ return static_cast<RtAudioInterface*>(userData)->RtAudioCallback(outputBuffer,inputBuffer,
+ nFrames,
+ streamTime, status);
}
//*******************************************************************************
int RtAudioInterface::startProcess() const
{
- try { mRtAudio->startStream(); }
- catch ( RtError& e ) {
- std::cout << '\n' << e.getMessage() << '\n' << std::endl;
- return(-1);
- }
- return(0);
+ try { mRtAudio->startStream(); }
+ catch ( RtAudioError& e ) {
+ std::cout << '\n' << e.getMessage() << '\n' << std::endl;
+ return(-1);
+ }
+ return(0);
}
//*******************************************************************************
int RtAudioInterface::stopProcess() const
{
- try { mRtAudio->closeStream(); }
- catch ( RtError& e ) {
- std::cout << '\n' << e.getMessage() << '\n' << std::endl;
- return(-1);
- }
- return 0;
+ try { mRtAudio->closeStream(); }
+ catch ( RtAudioError& e ) {
+ std::cout << '\n' << e.getMessage() << '\n' << std::endl;
+ return(-1);
+ }
+ return 0;
}
- //mTestJackTrip->printTextTest();
+//mTestJackTrip->printTextTest();
- //if (mJackTrip != NULL)
- // cout << "(mJackTrip != NULL)" << endl;
+//if (mJackTrip != NULL)
+// cout << "(mJackTrip != NULL)" << endl;
- //if (mJackTrip == NULL) { cout << " === JACKTRIPNULL === " << endl; }
+//if (mJackTrip == NULL) { cout << " === JACKTRIPNULL === " << endl; }
- //const int8_t* caca;
- //mJackTrip->sendNetworkPacket( mInputPacket );
+//const int8_t* caca;
+//mJackTrip->sendNetworkPacket( mInputPacket );
- //in_buffer = mInBuffer.data();
- //mInBuffer.data() = (float*) inputBuffer;
+//in_buffer = mInBuffer.data();
+//mInBuffer.data() = (float*) inputBuffer;
- //mInBuffer[0] = static_cast<float*>(outputBuffer);
- //mOutBuffer[0] = static_cast<sample_t*>(inputBuffer);
- //float* in_buffer = static_cast<float*>(inputBuffer);
- //float* out_buffer = static_cast<float*>(outputBuffer);
+//mInBuffer[0] = static_cast<float*>(outputBuffer);
+//mOutBuffer[0] = static_cast<sample_t*>(inputBuffer);
+//float* in_buffer = static_cast<float*>(inputBuffer);
+//float* out_buffer = static_cast<float*>(outputBuffer);
- //cout << "nFrames = ==================== = = = = = = = ======== " << this->getBufferSizeInSamples() << endl;
- //int8_t* input_packet = new int8_t[nFrames*2];
+//cout << "nFrames = ==================== = = = = = = = ======== " << this->getBufferSizeInSamples() << endl;
+//int8_t* input_packet = new int8_t[nFrames*2];
- //tmp_sample = floor( (*input) * 32768.0 ); // 2^15 = 32768.0
+//tmp_sample = floor( (*input) * 32768.0 ); // 2^15 = 32768.0
- //JackAudioInterface::fromSampleToBitConversion(in_buffer, input_packet, BIT16);
- //for (int i = 0; i<nFrames; i++) {
- // cout << in_buffer[i] << endl;
- //}
- //mJackTrip->sendNetworkPacket(input_packet);
- //cout << mJackTrip->getRingBuffersSlotSize() << endl;
- //delete[] input_packet;
+//JackAudioInterface::fromSampleToBitConversion(in_buffer, input_packet, BIT16);
+//for (int i = 0; i<nFrames; i++) {
+// cout << in_buffer[i] << endl;
+//}
+//mJackTrip->sendNetworkPacket(input_packet);
+//cout << mJackTrip->getRingBuffersSlotSize() << endl;
+//delete[] input_packet;
- //mOutputPacket = static_cast<int8_t*>(inputBuffer);
- //mInputPacket = static_cast<int8_t*>(outputBuffer);
+//mOutputPacket = static_cast<int8_t*>(inputBuffer);
+//mInputPacket = static_cast<int8_t*>(outputBuffer);
- // Allocate the Process Callback
- //-------------------------------------------------------------------
- // 1) First, process incoming packets
- // ----------------------------------
- /*
+// Allocate the Process Callback
+//-------------------------------------------------------------------
+// 1) First, process incoming packets
+// ----------------------------------
+/*
mJackTrip->receiveNetworkPacket( mOutputPacket );
// Extract separate channels to send to Jack
for (int i = 0; i < getNumInputChannels(); i++) {
*/
- // 3) Finally, send packets to peer
- // --------------------------------
- // Input Process (from JACK to NETWORK)
- // ----------------------------------------------------------------
- // Concatenate all the channels from jack to form packet
- /*
+// 3) Finally, send packets to peer
+// --------------------------------
+// Input Process (from JACK to NETWORK)
+// ----------------------------------------------------------------
+// Concatenate all the channels from jack to form packet
+/*
for (int i = 0; i < getNumOutputChannels(); i++) {
//--------
// This should be faster for 32 bits
//mInRingBuffer->insertSlotNonBlocking( mInputPacket );
mJackTrip->sendNetworkPacket( mInputPacket );
*/
- //return 0;
+//return 0;
//}
#ifndef __RTAUDIOINTERFACE_H__
#define __RTAUDIOINTERFACE_H__
-#include "RtAudio.h"
+#include <RtAudio.h>
#include "AudioInterface.h"
#include "jacktrip_globals.h"
{
public:
- /** \brief The class constructor
+ /** \brief The class constructor
* \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
* \param NumInChans Number of Input Channels
* \param NumOutChans Number of Output Channels
* \param AudioBitResolution Audio Sample Resolutions in bits
*/
- RtAudioInterface(JackTrip* jacktrip,
- int NumInChans = gDefaultNumInChannels,
- int NumOutChans = gDefaultNumOutChannels,
- audioBitResolutionT AudioBitResolution = BIT16);
- /// \brief The class destructor
- virtual ~RtAudioInterface();
-
- /// \brief List all avialable audio interfaces, with its properties
- virtual void listAllInterfaces();
- virtual void setup();
- virtual int startProcess() const;
- virtual int stopProcess() const;
- /// \brief This has no effect in RtAudio
- virtual void connectDefaultPorts() {}
-
- //--------------SETTERS---------------------------------------------
- /// \brief This has no effect in RtAudio
- virtual void setClientName(const char* /*ClientName*/) {}
- //------------------------------------------------------------------
-
- //--------------GETTERS---------------------------------------------
- //------------------------------------------------------------------
+ RtAudioInterface(JackTrip* jacktrip,
+ int NumInChans = gDefaultNumInChannels,
+ int NumOutChans = gDefaultNumOutChannels,
+ audioBitResolutionT AudioBitResolution = BIT16);
+ /// \brief The class destructor
+ virtual ~RtAudioInterface();
+
+ /// \brief List all avialable audio interfaces, with its properties
+ virtual void listAllInterfaces();
+ virtual void setup();
+ virtual int startProcess() const;
+ virtual int stopProcess() const;
+ /// \brief This has no effect in RtAudio
+ virtual void connectDefaultPorts() {}
+
+ //--------------SETTERS---------------------------------------------
+ /// \brief This has no effect in RtAudio
+ virtual void setClientName(const char* /*ClientName*/) {}
+ //------------------------------------------------------------------
+
+ //--------------GETTERS---------------------------------------------
+ //------------------------------------------------------------------
private:
- int RtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames,
- double streamTime, RtAudioStreamStatus status);
- static int wrapperRtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames,
- double streamTime, RtAudioStreamStatus status, void *userData);
- void printDeviceInfo(unsigned int deviceId);
-
- JackTrip* mJackTrip; ///< JackTrip Mediator Class pointer
- int mNumInChans;///< Number of Input Channels
- int mNumOutChans; ///< Number of Output Channels
- QVarLengthArray<float*> mInBuffer; ///< Vector of Input buffers/channel read from JACK
- QVarLengthArray<float*> mOutBuffer; ///< Vector of Output buffer/channel to write to JACK
- RtAudio* mRtAudio; ///< RtAudio class
+ int RtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames,
+ double streamTime, RtAudioStreamStatus status);
+ static int wrapperRtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames,
+ double streamTime, RtAudioStreamStatus status, void *userData);
+ void printDeviceInfo(unsigned int deviceId);
+
+ JackTrip* mJackTrip; ///< JackTrip Mediator Class pointer
+ int mNumInChans;///< Number of Input Channels
+ int mNumOutChans; ///< Number of Output Channels
+ QVarLengthArray<float*> mInBuffer; ///< Vector of Input buffers/channel read from JACK
+ QVarLengthArray<float*> mOutBuffer; ///< Vector of Output buffer/channel to write to JACK
+ RtAudio* mRtAudio; ///< RtAudio class
};
#endif // __RTAUDIOINTERFACE_H__
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#include "Settings.h"
#include "LoopBack.h"
#include "NetKS.h"
+
+#ifdef WAIR // wair
+#include "ap8x2.dsp.h"
+#include "Stk16.dsp.h"
+#endif // endwhere
+
#include "UdpMasterListener.h"
#include "JackTripWorker.h"
#include "jacktrip_globals.h"
mClientName(NULL),
mUnderrrunZero(false),
mLoopBack(false),
+ #ifdef WAIR // WAIR
+ mNumNetRevChans(0),
+ mWAIR(false),
+ #endif // endwhere
mJamLink(false),
mEmptyHeader(false),
mJackTripServer(false),
mRedundancy(1),
mUseJack(true),
mChanfeDefaultSR(false),
- mChanfeDefaultBS(false)
+ mChanfeDefaultID(0),
+ mChanfeDefaultBS(false),
+ mHubConnectionMode(JackTrip::SERVERTOCLIENT),
+ mConnectDefaultAudioPorts(true)
{}
//*******************************************************************************
// options descriptor
//----------------------------------------------------------------------------
static struct option longopts[] = {
- // These options set a flag, has to be sepcified as a long option --verbose
- { "verbose", no_argument, &gVerboseFlag, 1 },
// These options don't set a flag.
- { "numchannels", required_argument, NULL, 'n' }, // Number of input and output channels
- { "server", no_argument, NULL, 's' }, // Run in server mode
- { "client", required_argument, NULL, 'c' }, // Run in client mode, set server IP address
- { "localaddress", required_argument, NULL, 'L' }, // set local address e.g., 127.0.0.2 for second instance on same host
- { "jacktripserver", no_argument, NULL, 'S' }, // Run in JamLink mode
- { "pingtoserver", required_argument, NULL, 'C' }, // Run in ping to server mode, set server IP address
- { "portoffset", required_argument, NULL, 'o' }, // Port Offset from 4464
- { "bindport", required_argument, NULL, 'B' }, // Port Offset from 4464
- { "peerport", required_argument, NULL, 'P' }, // Port Offset from 4464
- { "queue", required_argument, NULL, 'q' }, // Queue Length
- { "redundancy", required_argument, NULL, 'r' }, // Redundancy
- { "bitres", required_argument, NULL, 'b' }, // Audio Bit Resolution
- { "zerounderrun", no_argument, NULL, 'z' }, // Use Underrun to Zeros Mode
- { "loopback", no_argument, NULL, 'l' }, // Run in loopback mode
- { "jamlink", no_argument, NULL, 'j' }, // Run in JamLink mode
- { "emptyheader", no_argument, NULL, 'e' }, // Run in JamLink mode
- { "clientname", required_argument, NULL, 'J' }, // Run in JamLink mode
- { "rtaudio", no_argument, NULL, 'R' }, // Run in JamLink mode
- { "srate", required_argument, NULL, 'T' }, // Set Sample Rate
- { "bufsize", required_argument, NULL, 'F' }, // Set buffer Size
- { "version", no_argument, NULL, 'v' }, // Version Number
- { "help", no_argument, NULL, 'h' }, // Print Help
- { NULL, 0, NULL, 0 }
- };
+ { "numchannels", required_argument, NULL, 'n' }, // Number of input and output channels
+#ifdef WAIR // WAIR
+ { "wair", no_argument, NULL, 'w' }, // Run in LAIR mode, sets numnetrevchannels
+ { "addcombfilterlength", required_argument, NULL, 'N' }, // added comb filter length
+ { "combfilterfeedback", required_argument, NULL, 'H' }, // comb filter feedback
+#endif // endwhere
+ { "server", no_argument, NULL, 's' }, // Run in server mode
+ { "client", required_argument, NULL, 'c' }, // Run in client mode, set server IP address
+ { "localaddress", required_argument, NULL, 'L' }, // set local address e.g., 127.0.0.2 for second instance on same host
+ { "jacktripserver", no_argument, NULL, 'S' }, // Run in JamLink mode
+ { "pingtoserver", required_argument, NULL, 'C' }, // Run in ping to server mode, set server IP address
+ { "portoffset", required_argument, NULL, 'o' }, // Port Offset from 4464
+ { "bindport", required_argument, NULL, 'B' }, // Port Offset from 4464
+ { "peerport", required_argument, NULL, 'P' }, // Port Offset from 4464
+ { "queue", required_argument, NULL, 'q' }, // Queue Length
+ { "redundancy", required_argument, NULL, 'r' }, // Redundancy
+ { "bitres", required_argument, NULL, 'b' }, // Audio Bit Resolution
+ { "zerounderrun", no_argument, NULL, 'z' }, // Use Underrun to Zeros Mode
+ { "loopback", no_argument, NULL, 'l' }, // Run in loopback mode
+ { "jamlink", no_argument, NULL, 'j' }, // Run in JamLink mode
+ { "emptyheader", no_argument, NULL, 'e' }, // Run in JamLink mode
+ { "clientname", required_argument, NULL, 'J' }, // Run in JamLink mode
+ { "rtaudio", no_argument, NULL, 'R' }, // Run in JamLink mode
+ { "srate", required_argument, NULL, 'T' }, // Set Sample Rate
+ { "deviceid", required_argument, NULL, 'd' }, // Set RTAudio device id to use
+ { "bufsize", required_argument, NULL, 'F' }, // Set buffer Size
+ { "nojackportsconnect" , no_argument, NULL, 'D'}, // Don't connect default Audio Ports
+ { "version", no_argument, NULL, 'v' }, // Version Number
+ { "verbose", no_argument, NULL, 'V' }, // Verbose mode
+ { "hubpatch", required_argument, NULL, 'p' }, // Set hubConnectionMode for auto patch in Jack
+ { "help", no_argument, NULL, 'h' }, // Print Help
+ { NULL, 0, NULL, 0 }
+};
// Parse Command Line Arguments
//----------------------------------------------------------------------------
/// \todo Specify mandatory arguments
int ch;
while ( (ch = getopt_long(argc, argv,
- "n:sc:SC:o:B:P:q:r:b:zljeJ:RT:F:vh", longopts, NULL)) != -1 )
+ "n:N:H:sc:SC:o:B:P:q:r:b:zlwjeJ:RTd:F:p:DvVh", longopts, NULL)) != -1 )
switch (ch) {
case 'n': // Number of input and output channels
//-------------------------------------------------------
mNumChans = atoi(optarg);
break;
+#ifdef WAIR
+ case 'w':
+ //-------------------------------------------------------
+ mWAIR = true;
+ mNumNetRevChans = gDefaultNumNetRevChannels; // fixed amount sets number of network channels and comb filters for WAIR
+ break;
+ case 'N':
+ //-------------------------------------------------------
+ mClientAddCombLen = atoi(optarg); // cmd line comb length adjustment
+ break;
+ case 'H': // comb feedback adjustment
+ //-------------------------------------------------------
+ mClientRoomSize = atof(optarg); // cmd line comb feedback adjustment
+ break;
+#endif // endwhere
case 's': // Run in server mode
//-------------------------------------------------------
mJackTripMode = JackTrip::SERVER;
else if ( atoi(optarg) == 32 ) {
mAudioBitResolution = AudioInterface::BIT32; }
else {
- std::cerr << "--bitres ERROR: Wrong bit resolutions: "
+ std::cerr << "--bitres ERROR: Wrong bit resolution: "
<< atoi(optarg) << " is not supported." << endl;
printUsage();
std::exit(1); }
case 'q':
//-------------------------------------------------------
if ( atoi(optarg) <= 0 ) {
- std::cerr << "--queue ERROR: The queue has to be equal or greater that 2" << endl;
+ std::cerr << "--queue ERROR: The queue has to be equal or greater than 2" << endl;
printUsage();
std::exit(1); }
else {
mChanfeDefaultSR = true;
mSampleRate = atoi(optarg);
break;
+ case 'd': // RTAudio device id
+ //-------------------------------------------------------
+ mChanfeDefaultID = true;
+ mDeviceID = atoi(optarg);
+ break;
case 'F': // Buffer Size
//-------------------------------------------------------
mChanfeDefaultBS = true;
mAudioBufferSize = atoi(optarg);
break;
+ case 'D':
+ //-------------------------------------------------------
+ mConnectDefaultAudioPorts = false;
+ break;
case 'v':
//-------------------------------------------------------
cout << "JackTrip VERSION: " << gVersion << endl;
- cout << "Copyright (c) 2008-2009 Juan-Pablo Caceres, Chris Chafe." << endl;
+ cout << "Copyright (c) 2008-2018 Juan-Pablo Caceres, Chris Chafe." << endl;
cout << "SoundWIRE group at CCRMA, Stanford University" << endl;
cout << "" << endl;
std::exit(0);
break;
+ case 'V':
+ //-------------------------------------------------------
+ gVerboseFlag = true;
+ if (gVerboseFlag) std::cout << "Verbose mode" << std::endl;
+ break;
+ case 'p':
+ //-------------------------------------------------------
+ if ( atoi(optarg) == 0 ) {
+ mHubConnectionMode = JackTrip::SERVERTOCLIENT; }
+ else if ( atoi(optarg) == 1 ) {
+ mHubConnectionMode = JackTrip::CLIENTECHO; }
+ else if ( atoi(optarg) == 2 ) {
+ mHubConnectionMode = JackTrip::CLIENTFOFI; }
+ else if ( atoi(optarg) == 3 ) {
+ mHubConnectionMode = JackTrip::RESERVEDMATRIX; }
+ else if ( atoi(optarg) == 4 ) {
+ mHubConnectionMode = JackTrip::FULLMIX; }
+ else {
+ std::cerr << "-p ERROR: Wrong HubConnectionMode: "
+ << atoi(optarg) << " is not supported." << endl;
+ printUsage();
+ std::exit(1); }
+ break;
case 'h':
//-------------------------------------------------------
printUsage();
//----------------------------------------------------------------------------
if (optind < argc) {
cout << gPrintSeparator << endl;
- cout << "WARINING: The following entered options have no effect" << endl;
+ cout << "WARINING: The following entered options have no effect." << endl;
cout << " They will be ignored!" << endl;
- cout << " Type jacktrip to see options." << endl;
+ cout << " Type 'jacktrip' to see options." << endl;
for( ; optind < argc; optind++) {
- printf("argument: %s\n", argv[optind]);
+ cout << "argument: " << argv[optind] << endl;
}
cout << gPrintSeparator << endl;
}
cout << "" << endl;
cout << "JackTrip: A System for High-Quality Audio Network Performance" << endl;
cout << "over the Internet" << endl;
- cout << "Copyright (c) 2008-2015 Juan-Pablo Caceres, Chris Chafe." << endl;
+ cout << "Copyright (c) 2008-2018 Juan-Pablo Caceres, Chris Chafe." << endl;
cout << "SoundWIRE group at CCRMA, Stanford University" << endl;
cout << "VERSION: " << gVersion << endl;
- cout << "-----------------------------------------------------------------------------" << endl;
cout << "" << endl;
cout << "Usage: jacktrip [-s|-c host] [options]" << endl;
cout << "" << endl;
cout << "Options: " << endl;
cout << "REQUIRED ARGUMENTS: " << endl;
- cout << "===================" << endl;
cout << " -s, --server Run in Server Mode" << endl;
- cout << " -c, --client <peer_host_IP_number> Run in Client Mode" << endl;
+ cout << " -c, --client <peer_hostname_or_IP_num> Run in Client Mode" << endl;
+ cout << " -S, --jacktripserver Run in Hub Server Mode" << endl;
+ cout << " -C, --pingtoserver <peer_name_or_IP> Run in Hub Client Mode" << endl;
cout << endl;
cout << "OPTIONAL ARGUMENTS: " << endl;
- cout << "===================" << endl;
- cout << " -n, --numchannels # Number of Input and Output Channels (default "
+ cout << " -n, --numchannels # Number of Input and Output Channels (default: "
<< 2 << ")" << endl;
- cout << " -q, --queue # (2 or more) Queue Buffer Length, in Packet Size (default "
+#ifdef WAIR // WAIR
+ cout << " -w, --wair Run in WAIR Mode" << endl;
+ cout << " -N, --addcombfilterlength # comb length adjustment for WAIR (default "
+ << gDefaultAddCombFilterLength << ")" << endl;
+ cout << " -H, --combfilterfeedback # comb feedback adjustment for WAIR (default "
+ << gDefaultCombFilterFeedback << ")" << endl;
+#endif // endwhere
+ cout << " -q, --queue # (2 or more) Queue Buffer Length, in Packet Size (default: "
<< gDefaultQueueLength << ")" << endl;
- cout << " -r, --redundancy # (1 or more) Packet Redundancy to avoid glitches with packet losses (defaul 1)"
+ cout << " -r, --redundancy # (1 or more) Packet Redundancy to avoid glitches with packet losses (default: 1)"
<< endl;
cout << " -o, --portoffset # Receiving port offset from base port " << gDefaultPort << endl;
- cout << " --bindport # Set only the bind port number (default to 4464)" << endl;
- cout << " --peerport # Set only the Peer port number (default to 4464)" << endl;
- cout << " -b, --bitres # (8, 16, 24, 32) Audio Bit Rate Resolutions (default 16)" << endl;
- cout << " -z, --zerounderrun Set buffer to zeros when underrun occurs (defaults to wavetable)" << endl;
+ cout << " --bindport # Set only the bind port number (default: 4464)" << endl;
+ cout << " --peerport # Set only the Peer port number (default: 4464)" << endl;
+ cout << " -b, --bitres # (8, 16, 24, 32) Audio Bit Rate Resolutions (default: 16)" << endl;
+ cout << " -p, --hubpatch # (0, 1, 2, 3, 4) Hub auto audio patch, only has effect if running HUB SERVER mode, 0=server-to-clients, 1=client loopback, 2=client fan out/in but not loopback, 3=reserved for TUB, 4=full mix (default: 0)" << endl;
+ cout << " -z, --zerounderrun Set buffer to zeros when underrun occurs (default: wavetable)" << endl;
cout << " -l, --loopback Run in Loop-Back Mode" << endl;
cout << " -j, --jamlink Run in JamLink Mode (Connect to a JamLink Box)" << endl;
- cout << " --clientname Change default client name (default is JackTrip)" << endl;
- cout << " --localaddress Change default local host IP address (127.0.0.1)" << endl;
+ cout << " --clientname Change default client name (default: JackTrip)" << endl;
+ cout << " --localaddress Change default local host IP address (default: 127.0.0.1)" << endl;
+ cout << " --nojackportsconnect Don't connect default audio ports in jack" << endl;
cout << endl;
- cout << "ARGUMENTS TO USE IT WITHOUT JACK:" << endl;
- cout << "=================================" << endl;
- cout << " --rtaudio Use defaul sound system instead of Jack" << endl;
- cout << " --srate # Set the sampling rate, works on --rtaudio mode only (defaults 48000)" << endl;
- cout << " --bufsize # Set the buffer size, works on --rtaudio mode only (defaults 128)" << endl;
+ cout << "ARGUMENTS TO USE JACKTRIP WITHOUT JACK:" << endl;
+ cout << " --rtaudio Use system's default sound system instead of Jack" << endl;
+ cout << " --srate # Set the sampling rate, works on --rtaudio mode only (default: 48000)" << endl;
+ cout << " --bufsize # Set the buffer size, works on --rtaudio mode only (default: 128)" << endl;
+ cout << " --deviceid # The rtaudio device id --rtaudio mode only (default: 0)" << endl;
cout << endl;
cout << "HELP ARGUMENTS: " << endl;
- cout << "===============" << endl;
cout << " -v, --version Prints Version Number" << endl;
+ cout << " -V, --verbose Verbose mode, prints debug messages" << endl;
cout << " -h, --help Prints this Help" << endl;
cout << "" << endl;
}
/// \todo Change this, just here to test
if ( mJackTripServer ) {
UdpMasterListener* udpmaster = new UdpMasterListener;
+#ifdef WAIR // WAIR
+ udpmaster->setWAIR(mWAIR);
+#endif // endwhere
+ udpmaster->setHubPatch(mHubConnectionMode);
+ udpmaster->setConnectDefaultAudioPorts(mConnectDefaultAudioPorts);
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip before udpmaster->start" << std::endl;
+ // Set buffers to zero when underrun
+ if ( mUnderrrunZero ) {
+ cout << "Setting buffers to zero when underrun..." << endl;
+ cout << gPrintSeparator << std::endl;
+ udpmaster->setUnderRunMode(JackTrip::ZEROS);
+ }
+ udpmaster->setBufferQueueLength(mBufferQueueLength);
udpmaster->start();
//---Thread Pool Test--------------------------------------------
//JackTrip jacktrip(mJackTripMode, mDataProtocol, mNumChans,
// mBufferQueueLength, mAudioBitResolution);
+#ifdef WAIR // WAIR
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip mNumNetRevChans = " << mNumNetRevChans << std::endl;
+#endif // endwhere
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip before new JackTrip" << std::endl;
mJackTrip = new JackTrip(mJackTripMode, mDataProtocol, mNumChans,
+ #ifdef WAIR // wair
+ mNumNetRevChans,
+ #endif // endwhere
mBufferQueueLength, mRedundancy, mAudioBitResolution);
+ // Set connect or not default audio ports. Only work for jack
+ mJackTrip->setConnectDefaultAudioPorts(mConnectDefaultAudioPorts);
+
// Connect Signals and Slots
QObject::connect(mJackTrip, SIGNAL( signalProcessesStopped() ),
this, SLOT( slotExitProgram() ));
if ( mJackTripMode == JackTrip::CLIENT || mJackTripMode == JackTrip::CLIENTTOPINGSERVER ) {
mJackTrip->setPeerAddress(mPeerAddress.toLatin1().data()); }
-// if(mLocalAddress!=QString()) // default
-// mJackTrip->setLocalAddress(QHostAddress(mLocalAddress.toLatin1().data()));
-// else
-// mJackTrip->setLocalAddress(QHostAddress::Any);
+ // if(mLocalAddress!=QString()) // default
+ // mJackTrip->setLocalAddress(QHostAddress(mLocalAddress.toLatin1().data()));
+ // else
+ // mJackTrip->setLocalAddress(QHostAddress::Any);
// Set Ports
//cout << "SETTING ALL PORTS" << endl;
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->setBindPorts" << std::endl;
mJackTrip->setBindPorts(mBindPortNum);
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->setPeerPorts" << std::endl;
mJackTrip->setPeerPorts(mPeerPortNum);
// Set in JamLink Mode
mJackTrip->setSampleRate(mSampleRate);
}
+ // Chanfe defualt device ID
+ if (mChanfeDefaultID) {
+ mJackTrip->setDeviceID(mDeviceID);
+ }
+
// Chanfe default Buffer Size
if (mChanfeDefaultBS) {
mJackTrip->setAudioBufferSizeInSamples(mAudioBufferSize);
// -------------------------------------------------------------
}
+#ifdef WAIR // WAIR
+ if ( mWAIR ) {
+ cout << "Running in WAIR Mode..." << endl;
+ cout << gPrintSeparator << std::endl;
+ switch ( mNumNetRevChans )
+ {
+ case 16 :
+ {
+ mJackTrip->appendProcessPlugin(new ap8x2(mNumChans)); // plugin slot 0
+ /////////////////////////////////////////////////////////
+ Stk16* plugin = new Stk16(mNumNetRevChans);
+ plugin->Stk16::initCombClient(mClientAddCombLen, mClientRoomSize);
+ mJackTrip->appendProcessPlugin(plugin); // plugin slot 1
+ }
+ break;
+ default:
+ throw std::invalid_argument("Settings: mNumNetRevChans doesn't correspond to Faust plugin");
+ break;
+ }
+ }
+#endif // endwhere
+
// Start JackTrip
- mJackTrip->startProcess();
- mJackTrip->start();
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->startProcess" << std::endl;
+ mJackTrip->startProcess(
+ #ifdef WAIRTOMASTER // WAIR
+ 0 // for WAIR compatibility, ID in jack client name
+ #endif // endwhere
+ );
+ // if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->start" << std::endl;
+ // this is a noop
+ // mJackTrip->start();
/*
sleep(10);
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*/
class Settings : public QThread
{
- Q_OBJECT;
+ Q_OBJECT;
public:
- Settings();
- virtual ~Settings();
+ Settings();
+ virtual ~Settings();
- /// \brief Parses command line input
- void parseInput(int argc, char** argv);
+ /// \brief Parses command line input
+ void parseInput(int argc, char** argv);
- void startJackTrip();
- void stopJackTrip();
+ void startJackTrip();
+ void stopJackTrip();
- /// \brief Prints usage help
- void printUsage();
+ /// \brief Prints usage help
+ void printUsage();
- bool getLoopBack() { return mLoopBack; }
+ bool getLoopBack() { return mLoopBack; }
public slots:
- void slotExitProgram()
- {
- std::cerr << "Exiting JackTrip..." << std::endl;
- std::exit(1);
- }
+ void slotExitProgram()
+ {
+ std::cerr << "Exiting JackTrip..." << std::endl;
+ std::exit(1);
+ }
private:
- JackTrip* mJackTrip; ///< JackTrip class
- JackTrip::jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
- JackTrip::dataProtocolT mDataProtocol; ///< Data Protocol
- int mNumChans; ///< Number of Channels (inputs = outputs)
- int mBufferQueueLength; ///< Audio Buffer from network queue length
- AudioInterface::audioBitResolutionT mAudioBitResolution;
- QString mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
- int mBindPortNum; ///< Bind Port Number
- int mPeerPortNum; ///< Peer Port Number
- char* mClientName; ///< JackClient Name
- bool mUnderrrunZero; ///< Use Underrun to Zero mode
-
- bool mLoopBack; ///< Loop-back mode
- bool mJamLink; ///< JamLink mode
- bool mEmptyHeader; ///< EmptyHeader mode
- bool mJackTripServer; ///< JackTrip Server mode
- QString mLocalAddress; ///< Local Address
- unsigned int mRedundancy; ///< Redundancy factor for data in the network
- bool mUseJack; ///< Use or not JackAduio
- bool mChanfeDefaultSR; ///< Change Default Sampling Rate
- bool mChanfeDefaultBS; ///< Change Default Buffer Size
- unsigned int mSampleRate;
- unsigned int mAudioBufferSize;
+ JackTrip* mJackTrip; ///< JackTrip class
+ JackTrip::jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
+ JackTrip::dataProtocolT mDataProtocol; ///< Data Protocol
+ int mNumChans; ///< Number of Channels (inputs = outputs)
+ int mBufferQueueLength; ///< Audio Buffer from network queue length
+ AudioInterface::audioBitResolutionT mAudioBitResolution;
+ QString mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
+ int mBindPortNum; ///< Bind Port Number
+ int mPeerPortNum; ///< Peer Port Number
+ char* mClientName; ///< JackClient Name
+ bool mUnderrrunZero; ///< Use Underrun to Zero mode
+
+#ifdef WAIR // wair
+ int mNumNetRevChans; ///< Number of Network Audio Channels (net comb filters)
+ int mClientAddCombLen; ///< cmd line adjustment of net comb
+ double mClientRoomSize; ///< freeverb room size
+ bool mWAIR; ///< WAIR mode
+#endif // endwhere
+
+ bool mLoopBack; ///< Loop-back mode
+ bool mJamLink; ///< JamLink mode
+ bool mEmptyHeader; ///< EmptyHeader mode
+ bool mJackTripServer; ///< JackTrip Server mode
+ QString mLocalAddress; ///< Local Address
+ unsigned int mRedundancy; ///< Redundancy factor for data in the network
+ bool mUseJack; ///< Use or not JackAduio
+ bool mChanfeDefaultSR; ///< Change Default Sampling Rate
+ bool mChanfeDefaultID; ///< Change Default device ID
+ bool mChanfeDefaultBS; ///< Change Default Buffer Size
+ unsigned int mSampleRate;
+ unsigned int mDeviceID;
+ unsigned int mAudioBufferSize;
+ unsigned int mHubConnectionMode;
+ bool mConnectDefaultAudioPorts; ///< Connect or not jack audio ports
};
#endif
class TestRingBufferWrite : public QThread
{
public:
-
- void run()
- {
- int8_t* writeSlot;
- writeSlot = new int8_t[2];
- writeSlot[0] = *"a";
- writeSlot[1] = *"b";
- while (true) {
- //std::cout << "writing BEFORE" << std::endl;
- rb.insertSlotBlocking(writeSlot);
- //std::cout << "writing AFTER" << std::endl;
+
+ void run()
+ {
+ int8_t* writeSlot;
+ writeSlot = new int8_t[2];
+ writeSlot[0] = *"a";
+ writeSlot[1] = *"b";
+ while (true) {
+ //std::cout << "writing BEFORE" << std::endl;
+ rb.insertSlotBlocking(writeSlot);
+ //std::cout << "writing AFTER" << std::endl;
+ }
}
- }
};
class TestRingBufferRead : public QThread
{
public:
-
- void run()
- {
- int8_t* readSlot;
- readSlot = new int8_t[2];
- while (true) {
- //std::cout << "reading BEFORE" << std::endl;
- rb.readSlotBlocking(readSlot);
- //std::cout << "reading AFTER" << std::endl;
- //std::cout << *(readSlot) << std::endl;
- //std::cout << *(readSlot+1) << std::endl;
+
+ void run()
+ {
+ int8_t* readSlot;
+ readSlot = new int8_t[2];
+ while (true) {
+ //std::cout << "reading BEFORE" << std::endl;
+ rb.readSlotBlocking(readSlot);
+ //std::cout << "reading AFTER" << std::endl;
+ //std::cout << *(readSlot) << std::endl;
+ //std::cout << *(readSlot+1) << std::endl;
+ }
}
- }
};
#endif
-
class ThreadPoolTest : public QObject, public QRunnable
-//class ThreadPoolTest : public QThread
+ //class ThreadPoolTest : public QThread
{
- Q_OBJECT;
-
+ Q_OBJECT;
+
public:
- ThreadPoolTest()
- {
- setAutoDelete(false);
- }
-
- void run()
- {
- JackTripWorkerMessages jtm;
- QThread testThread;
- //jtm.moveToThread(&testThread);
-
- //QObject::connect(&jtm, SIGNAL(signalTest()), &jtm, SLOT(slotTest()), Qt::QueuedConnection);
- testThread.start();
- jtm.play();
- //testThread.wait();
-
- //std::cout << "--------------- BEFORE ---------------" << std::endl;
- //NetKS netks;
- //netks.play();
- //std::cout << "--------------- AFTER ---------------" << std::endl;
-
- QEventLoop loop;
- //QObject::connect(this, SIGNAL(stopELoop()), &loop, SLOT(quit()), Qt::QueuedConnection);
- loop.exec();
- //std::cout << "--------------- EXITING QRUNNABLE---------------" << std::endl;
- /*
+ ThreadPoolTest()
+ {
+ setAutoDelete(false);
+ }
+
+ void run()
+ {
+ JackTripWorkerMessages jtm;
+ QThread testThread;
+ //jtm.moveToThread(&testThread);
+
+ //QObject::connect(&jtm, SIGNAL(signalTest()), &jtm, SLOT(slotTest()), Qt::QueuedConnection);
+ testThread.start();
+ jtm.play();
+ //testThread.wait();
+
+ //std::cout << "--------------- BEFORE ---------------" << std::endl;
+ //NetKS netks;
+ //netks.play();
+ //std::cout << "--------------- AFTER ---------------" << std::endl;
+
+ QEventLoop loop;
+ //QObject::connect(this, SIGNAL(stopELoop()), &loop, SLOT(quit()), Qt::QueuedConnection);
+ loop.exec();
+ //std::cout << "--------------- EXITING QRUNNABLE---------------" << std::endl;
+ /*
while (true) {
std::cout << "Hello world from thread" << std::endl;
sleep(1);
}
*/
- }
+ }
- void stop()
- {
- std::cout << "--------------- ELOOP STOP---------------" << std::endl;
- emit stopELoop();
- }
+ void stop()
+ {
+ std::cout << "--------------- ELOOP STOP---------------" << std::endl;
+ emit stopELoop();
+ }
signals:
- void stopELoop();
+ void stopELoop();
private slots:
- void fromServer()
- {
- std::cout << "--------------- SIGNAL RECEIVED ---------------" << std::endl;
- }
+ void fromServer()
+ {
+ std::cout << "--------------- SIGNAL RECEIVED ---------------" << std::endl;
+ }
};
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#include <cerrno>
#include <stdexcept>
#ifdef __WIN_32__
-#include <winsock.h>
+//#include <winsock.h>
+#include <winsock2.h> //cc need SD_SEND
+#include <ws2tcpip.h> // for IPv6
#endif
#if defined (__LINUX__) || (__MAC__OSX__)
#include <sys/socket.h> // for POSIX Sockets
UdpDataProtocol::UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode,
int bind_port, int peer_port,
unsigned int udp_redundancy_factor) :
-DataProtocol(jacktrip, runmode, bind_port, peer_port),
-mBindPort(bind_port), mPeerPort(peer_port),
-mRunMode(runmode),
-mAudioPacket(NULL), mFullPacket(NULL),
-mUdpRedundancyFactor(udp_redundancy_factor)
+ DataProtocol(jacktrip, runmode, bind_port, peer_port),
+ mBindPort(bind_port), mPeerPort(peer_port),
+ mRunMode(runmode),
+ mAudioPacket(NULL), mFullPacket(NULL),
+ mUdpRedundancyFactor(udp_redundancy_factor)
{
- mStopped = false;
- if (mRunMode == RECEIVER) {
- QObject::connect(this, SIGNAL(signalWatingTooLong(int)),
- jacktrip, SLOT(slotUdpWatingTooLong(int)), Qt::QueuedConnection);
- }
+ mStopped = false;
+ mIPv6 = false;
+ std::memset(&mPeerAddr, 0, sizeof(mPeerAddr));
+ std::memset(&mPeerAddr6, 0, sizeof(mPeerAddr6));
+ mPeerAddr.sin_port = htons(mPeerPort);
+ mPeerAddr6.sin6_port = htons(mPeerPort);
+
+ if (mRunMode == RECEIVER) {
+ QObject::connect(this, SIGNAL(signalWaitingTooLong(int)),
+ jacktrip, SLOT(slotUdpWaitingTooLongClientGoneProbably(int)), Qt::QueuedConnection);
+ }
}
//*******************************************************************************
UdpDataProtocol::~UdpDataProtocol()
{
- delete[] mAudioPacket;
- delete[] mFullPacket;
- wait();
-}
+ delete[] mAudioPacket;
+ delete[] mFullPacket;
+ wait();
+}
//*******************************************************************************
void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP) throw(std::invalid_argument)
{
- // Get DNS Address
- QHostInfo info = QHostInfo::fromName(peerHostOrIP);
- if (!info.addresses().isEmpty()) {
- // use the first IP address
- mPeerAddress = info.addresses().first();
- //cout << "UdpDataProtocol::setPeerAddress IP Address Number: "
- // << mPeerAddress.toString().toStdString() << endl;
- }
+ // Get DNS Address
+#if defined (__LINUX__) || (__MAC__OSX__)
+ //Don't make the following code conditional on windows
+ //(Addresses a weird timing bug when in hub client mode)
+ if (!mPeerAddress.setAddress(peerHostOrIP)) {
+#endif
+ QHostInfo info = QHostInfo::fromName(peerHostOrIP);
+ if (!info.addresses().isEmpty()) {
+ // use the first IP address
+ mPeerAddress = info.addresses().first();
+ }
+ //cout << "UdpDataProtocol::setPeerAddress IP Address Number: "
+ // << mPeerAddress.toString().toStdString() << endl;
+#if defined (__LINUX__) || (__MAC__OSX__)
+ }
+#endif
- // check if the ip address is valid
- if ( mPeerAddress.isNull() ) {
- QString error_message = "Incorrect presentation format address\n '";
- error_message.append(peerHostOrIP);
- error_message.append("' is not a valid IP address or Host Name");
- //std::cerr << "ERROR: Incorrect presentation format address" << endl;
- //std::cerr << "'" << peerHostOrIP <<"' does not seem to be a valid IP address" << endl;
- //throw std::invalid_argument("Incorrect presentation format address");
- throw std::invalid_argument( error_message.toStdString());
- }
- /*
- else {
- std::cout << "Peer Address set to: "
- << mPeerAddress.toString().toStdString() << std::endl;
- cout << gPrintSeparator << endl;
- usleep(100);
- }
- */
+ // check if the ip address is valid
+ if ( mPeerAddress.protocol() == QAbstractSocket::IPv6Protocol ) {
+ mIPv6 = true;
+ } else if ( mPeerAddress.protocol() != QAbstractSocket::IPv4Protocol ) {
+ QString error_message = "Incorrect presentation format address\n '";
+ error_message.append(peerHostOrIP);
+ error_message.append("' is not a valid IP address or Host Name");
+ //std::cerr << "ERROR: Incorrect presentation format address" << endl;
+ //std::cerr << "'" << peerHostOrIP <<"' does not seem to be a valid IP address" << endl;
+ //throw std::invalid_argument("Incorrect presentation format address");
+ throw std::invalid_argument( error_message.toStdString());
+ }
+ /*
+ else {
+ std::cout << "Peer Address set to: "
+ << mPeerAddress.toString().toStdString() << std::endl;
+ cout << gPrintSeparator << endl;
+ usleep(100);
+ }
+ */
+
+ // Save our address as an appropriate address structure
+ if (mIPv6) {
+ mPeerAddr6.sin6_family = AF_INET6;
+ ::inet_pton(AF_INET6, mPeerAddress.toString().toLatin1().constData(),
+ &mPeerAddr6.sin6_addr);
+ } else {
+ mPeerAddr.sin_family = AF_INET;
+ ::inet_pton(AF_INET, mPeerAddress.toString().toLatin1().constData(),
+ &mPeerAddr.sin_addr);
+ }
+}
+
+#if defined (__WIN_32__)
+void UdpDataProtocol::setSocket(SOCKET &socket) throw(std::runtime_error)
+#else
+void UdpDataProtocol::setSocket(int &socket) throw(std::runtime_error)
+#endif
+{
+ //If we haven't been passed a valid socket, then we should bind one.
+#if defined (__WIN_32__)
+ if (socket == INVALID_SOCKET) {
+#else
+ if (socket == -1) {
+#endif
+ try {
+ if (gVerboseFlag) std::cout << " UdpDataProtocol:run" << mRunMode << " before bindSocket(UdpSocket)" << std::endl;
+ socket = bindSocket(); // Bind Socket
+ } catch ( const std::exception & e ) {
+ emit signalError( e.what() );
+ return;
+ }
+ }
+ mSocket = socket;
}
//*******************************************************************************
-void UdpDataProtocol::bindSocket(QUdpSocket& UdpSocket) throw(std::runtime_error)
+#if defined (__WIN_32__)
+SOCKET UdpDataProtocol::bindSocket() throw(std::runtime_error)
+#else
+int UdpDataProtocol::bindSocket() throw(std::runtime_error)
+#endif
{
- QMutexLocker locker(&sUdpMutex);
+ QMutexLocker locker(&sUdpMutex);
#if defined __WIN_32__
- WORD wVersionRequested;
- WSADATA wsaData;
- int err;
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
- wVersionRequested = MAKEWORD( 1, 1 );
+ wVersionRequested = MAKEWORD( 1, 1 );
- err = WSAStartup( wVersionRequested, &wsaData );
- if ( err != 0 ) {
- // Tell the user that we couldn't find a useable
- // winsock.dll.
+ err = WSAStartup( wVersionRequested, &wsaData );
+ if ( err != 0 ) {
+ // Tell the user that we couldn't find a useable
+ // winsock.dll.
- return;
- }
+ return INVALID_SOCKET;
+ }
- // Confirm that the Windows Sockets DLL supports 1.1. or higher
+ // Confirm that the Windows Sockets DLL supports 1.1. or higher
- if ( LOBYTE( wsaData.wVersion ) != 1 ||
- HIBYTE( wsaData.wVersion ) != 1 ) {
- // Tell the user that we couldn't find a useable
- // winsock.dll.
- WSACleanup( );
- return;
- }
+ if ( LOBYTE( wsaData.wVersion ) != 1 ||
+ HIBYTE( wsaData.wVersion ) != 1 ) {
+ // Tell the user that we couldn't find a useable
+ // winsock.dll.
+ WSACleanup( );
+ return INVALID_SOCKET;
+ }
- // Creat socket descriptor
- SOCKET sock_fd;
- SOCKADDR_IN local_addr;
+ SOCKET sock_fd;
#endif
#if defined ( __LINUX__ ) || (__MAC_OSX__)
- int sock_fd;
- //Set local IPv4 Address
- struct sockaddr_in local_addr;
+ int sock_fd;
#endif
- // Creat socket descriptor
- sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
-
- //::bzero(&local_addr, sizeof(local_addr));
- std::memset(&local_addr, 0, sizeof(local_addr)); // set buffer to 0
- local_addr.sin_family = AF_INET; //AF_INET: IPv4 Protocol
- local_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY: let the kernel decide the active address
- local_addr.sin_port = htons(mBindPort); //set local port
+ //Set local IPv4 or IPv6 Address
+ struct sockaddr_in local_addr;
+ struct sockaddr_in6 local_addr6;
+
+ // Create socket descriptor
+ if (mIPv6) {
+ sock_fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ std::memset(&local_addr6, 0, sizeof(local_addr6));
+ local_addr6.sin6_family = AF_INET6;
+ local_addr6.sin6_addr = in6addr_any;
+ local_addr6.sin6_port = htons(mBindPort);
+ } else {
+ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ //::bzero(&local_addr, sizeof(local_addr));
+ std::memset(&local_addr, 0, sizeof(local_addr)); // set buffer to 0
+ local_addr.sin_family = AF_INET; //AF_INET: IPv4 Protocol
+ local_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY: let the kernel decide the active address
+ local_addr.sin_port = htons(mBindPort); //set local port
+ }
- // Set socket to be reusable, this is platform dependent
- int one = 1;
+ // Set socket to be reusable, this is platform dependent
+ int one = 1;
#if defined ( __LINUX__ )
- ::setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+ ::setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
#endif
#if defined ( __MAC_OSX__ )
- // This option is not avialable on Linux, and without it MAC OS X
- // has problems rebinding a socket
- ::setsockopt(sock_fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
+ // This option is not avialable on Linux, and without it MAC OS X
+ // has problems rebinding a socket
+ ::setsockopt(sock_fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
#endif
#if defined (__WIN_32__)
- //make address/port reusable
- setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one));
+ //make address/port reusable
+ setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one));
#endif
- // Bind the Socket
-#if defined ( __LINUX__ ) || ( __MAC_OSX__ )
- if ( (::bind(sock_fd, (struct sockaddr *) &local_addr, sizeof(local_addr))) < 0 )
- { throw std::runtime_error("ERROR: UDP Socket Bind Error"); }
-#endif
-#if defined (__WIN_32__)
- //int bound;
- //bound = bind(sock_fd, (SOCKADDR *) &local_addr, sizeof(local_addr));
- if ( (bind(sock_fd, (SOCKADDR *) &local_addr, sizeof(local_addr))) == SOCKET_ERROR )
- { throw std::runtime_error("ERROR: UDP Socket Bind Error"); }
-#endif
+ // Bind the Socket
+ if (mIPv6) {
+ if ( (::bind(sock_fd, (struct sockaddr *) &local_addr6, sizeof(local_addr6))) < 0 )
+ { throw std::runtime_error("ERROR: UDP Socket Bind Error"); }
+ } else {
+ if ( (::bind(sock_fd, (struct sockaddr *) &local_addr, sizeof(local_addr))) < 0 )
+ { throw std::runtime_error("ERROR: UDP Socket Bind Error"); }
+ }
- // To be able to use the two UDP sockets bound to the same port number,
- // we connect the receiver and issue a SHUT_WR.
- if (mRunMode == SENDER) {
- // We use the sender as an unconnected UDP socket
- UdpSocket.setSocketDescriptor(sock_fd, QUdpSocket::BoundState,
- QUdpSocket::WriteOnly);
- }
- else if (mRunMode == RECEIVER) {
+ // To be able to use the two UDP sockets bound to the same port number,
+ // we connect the receiver and issue a SHUT_WR.
+
+ // This didn't work for IPv6, so we'll instead share a full duplex socket.
+ /*if (mRunMode == SENDER) {
+ // We use the sender as an unconnected UDP socket
+ UdpSocket.setSocketDescriptor(sock_fd, QUdpSocket::BoundState,
+ QUdpSocket::WriteOnly);
+ }*/
+ if (!mIPv6) {
+ // Connect only if we're using IPv4.
+ // (Connecting presents an issue when a host has multiple IP addresses and the peer decides to send from
+ // a different address. While this generally won't be a problem for IPv4, it will for IPv6.)
+ if ( (::connect(sock_fd, (struct sockaddr *) &mPeerAddr, sizeof(mPeerAddr))) < 0)
+ { throw std::runtime_error("ERROR: Could not connect UDP socket"); }
#if defined (__LINUX__) || (__MAC_OSX__)
- // Set peer IPv4 Address
- struct sockaddr_in peer_addr;
- bzero(&peer_addr, sizeof(peer_addr));
- peer_addr.sin_family = AF_INET; //AF_INET: IPv4 Protocol
- peer_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY: let the kernel decide the active address
- peer_addr.sin_port = htons(mPeerPort); //set local port
- // Connect the socket and issue a Write shutdown (to make it a
- // reader socket only)
- if ( (::inet_pton(AF_INET, mPeerAddress.toString().toLatin1().constData(),
- &peer_addr.sin_addr)) < 1 )
- { throw std::runtime_error("ERROR: Invalid address presentation format"); }
- if ( (::connect(sock_fd, (struct sockaddr *) &peer_addr, sizeof(peer_addr))) < 0)
- { throw std::runtime_error("ERROR: Could not connect UDP socket"); }
- if ( (::shutdown(sock_fd,SHUT_WR)) < 0)
- { throw std::runtime_error("ERROR: Could suntdown SHUT_WR UDP socket"); }
+ //if ( (::shutdown(sock_fd,SHUT_WR)) < 0)
+ //{ throw std::runtime_error("ERROR: Could shutdown SHUT_WR UDP socket"); }
#endif
#if defined __WIN_32__
- // Set peer IPv4 Address
- SOCKADDR_IN peer_addr;
- std::memset(&peer_addr, 0, sizeof(peer_addr)); // set buffer to 0
- peer_addr.sin_family = AF_INET; //AF_INET: IPv4 Protocol
- peer_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY: let the kernel decide the active address
- peer_addr.sin_port = htons(mPeerPort); //set local port
- // Connect the socket and issue a Write shutdown (to make it a
- // reader socket only)
- peer_addr.sin_addr.s_addr = inet_addr(mPeerAddress.toString().toLatin1().constData());
- int con = (::connect(sock_fd, (struct sockaddr *) &peer_addr, sizeof(peer_addr)));
- if ( con < 0)
- {
- fprintf(stderr, "ERROR: Could not connect UDP socket");
- throw std::runtime_error("ERROR: Could not connect UDP socket");
- }
- //cout<<"connect returned: "<<con<<endl;
- int shut_sr = shutdown(sock_fd, SD_SEND); //shut down sender's receive function
- if ( shut_sr< 0)
- {
- fprintf(stderr, "ERROR: Could not shutdown SD_SEND UDP socket");
- throw std::runtime_error("ERROR: Could not shutdown SD_SEND UDP socket");
- }
+ /*int shut_sr = shutdown(sock_fd, SD_SEND); //shut down sender's receive function
+ if ( shut_sr< 0)
+ {
+ fprintf(stderr, "ERROR: Could not shutdown SD_SEND UDP socket");
+ throw std::runtime_error("ERROR: Could not shutdown SD_SEND UDP socket");
+ }*/
#endif
+ }
- UdpSocket.setSocketDescriptor(sock_fd, QUdpSocket::ConnectedState,
- QUdpSocket::ReadOnly);
- cout << "UDP Socket Receiving in Port: " << mBindPort << endl;
- cout << gPrintSeparator << endl;
- }
+ return sock_fd;
- // OLD CODE WITHOUT POSIX FIX--------------------------------------------------
- /*
+ // OLD CODE WITHOUT POSIX FIX--------------------------------------------------
+ /*
/// \todo if port is already used, try binding in a different port
QUdpSocket::BindMode bind_mode;
if (mRunMode == RECEIVER) {
}
}
*/
- // ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
}
//*******************************************************************************
int UdpDataProtocol::receivePacket(QUdpSocket& UdpSocket, char* buf, const size_t n)
{
- // Block until There's something to read
- while ( (UdpSocket.pendingDatagramSize() < n) && !mStopped ) { QThread::usleep(100); }
- int n_bytes = UdpSocket.readDatagram(buf, n);
- return n_bytes;
+ // Block until There's something to read
+ while ( (UdpSocket.pendingDatagramSize() < n) && !mStopped ) { QThread::usleep(100); }
+ int n_bytes = UdpSocket.readDatagram(buf, n);
+ return n_bytes;
}
//*******************************************************************************
-int UdpDataProtocol::sendPacket(QUdpSocket& UdpSocket, const QHostAddress& PeerAddress,
- const char* buf, const size_t n)
+int UdpDataProtocol::sendPacket(const char* buf, const size_t n)
{
- int n_bytes = UdpSocket.writeDatagram(buf, n, PeerAddress, mPeerPort);
- return n_bytes;
+/*#if defined (__WIN_32__)
+ //Alternative windows specific code that uses winsock equivalents of the bsd socket functions.
+ DWORD n_bytes;
+ WSABUF buffer;
+ int error;
+ buffer.len = n;
+ buffer.buf = (char *)buf;
+
+ if (mIPv6) {
+ error = WSASendTo(mSocket, &buffer, 1, &n_bytes, 0, (struct sockaddr *) &mPeerAddr6, sizeof(mPeerAddr6), 0, 0);
+ } else {
+ error = WSASend(mSocket, &buffer, 1, &n_bytes, 0, 0, 0);
+ }
+ if (error == SOCKET_ERROR) {
+ cout << "Socket Error: " << WSAGetLastError() << endl;
+ }
+ return (int)n_bytes;
+#else*/
+ int n_bytes;
+ if (mIPv6) {
+ n_bytes = ::sendto(mSocket, buf, n, 0, (struct sockaddr *) &mPeerAddr6, sizeof(mPeerAddr6));
+ } else {
+ n_bytes = ::send(mSocket, buf, n, 0);
+ }
+ return n_bytes;
+//#endif
}
QHostAddress& peerHostAddress,
uint16_t& port)
{
- while ( !UdpSocket.hasPendingDatagrams() ) {
- msleep(100);
- }
- char buf[1];
- UdpSocket.readDatagram(buf, 1, &peerHostAddress, &port);
+ while ( !UdpSocket.hasPendingDatagrams() ) {
+ msleep(100);
+ }
+ char buf[1];
+ UdpSocket.readDatagram(buf, 1, &peerHostAddress, &port);
}
//*******************************************************************************
void UdpDataProtocol::run()
{
- //QObject::connect(this, SIGNAL(signalError(const char*)),
- // mJackTrip, SLOT(slotStopProcesses()),
- // Qt::QueuedConnection);
-
- // Creat and bind sockets
- QUdpSocket UdpSocket;
- try {
- bindSocket(UdpSocket); // Bind Socket
- } catch ( const std::exception & e ) {
- emit signalError( e.what() );
- return;
- }
+ if (gVerboseFlag) switch ( mRunMode )
+ {
+ case RECEIVER : {
+ std::cout << "step 3" << std::endl;
+ break; }
+
+ case SENDER : {
+ std::cout << "step 4" << std::endl;
+ break; }
+ }
+ //QObject::connect(this, SIGNAL(signalError(const char*)),
+ // mJackTrip, SLOT(slotStopProcesses()),
+ // Qt::QueuedConnection);
+
+ //Wrap our socket in a QUdpSocket object if we're the receiver, for convenience.
+ //If we're the sender, we'll just write directly to our socket.
+ QUdpSocket UdpSocket;
+ if (mRunMode == RECEIVER) {
+ if (mIPv6) {
+ UdpSocket.setSocketDescriptor(mSocket, QUdpSocket::BoundState,
+ QUdpSocket::ReadOnly);
+ } else {
+ UdpSocket.setSocketDescriptor(mSocket, QUdpSocket::ConnectedState,
+ QUdpSocket::ReadOnly);
+ }
+ cout << "UDP Socket Receiving in Port: " << mBindPort << endl;
+ cout << gPrintSeparator << endl;
+ }
- QHostAddress PeerAddress;
- PeerAddress = mPeerAddress;
-
- // Setup Audio Packet buffer
- size_t audio_packet_size = getAudioPacketSizeInBites();
- //cout << "audio_packet_size: " << audio_packet_size << endl;
- mAudioPacket = new int8_t[audio_packet_size];
- std::memset(mAudioPacket, 0, audio_packet_size); // set buffer to 0
-
- // Setup Full Packet buffer
- int full_packet_size = mJackTrip->getPacketSizeInBytes();
- //cout << "full_packet_size: " << full_packet_size << endl;
- mFullPacket = new int8_t[full_packet_size];
- std::memset(mFullPacket, 0, full_packet_size); // set buffer to 0
-
- bool timeout = false; // Time out flag for packets that arrive too late
-
- // Put header in first packet
- mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
-
- // Redundancy Variables
- // (Algorithm explained at the end of this file)
- // ---------------------------------------------
- int full_redundant_packet_size = full_packet_size * mUdpRedundancyFactor;
- int8_t* full_redundant_packet;
- full_redundant_packet = new int8_t[full_redundant_packet_size];
- std::memset(full_redundant_packet, 0, full_redundant_packet_size); // Initialize to 0
-
- // Set realtime priority (function in jacktrip_globals.h)
- set_crossplatform_realtime_priority();
-
- switch ( mRunMode )
- {
- case RECEIVER : {
- // Connect signals and slots for packets arriving too late notifications
- QObject::connect(this, SIGNAL(signalWatingTooLong(int)),
- this, SLOT(printUdpWaitedTooLong(int)),
- Qt::QueuedConnection);
- //-----------------------------------------------------------------------------------
- // Wait for the first packet to be ready and obtain address
- // from that packet
- std::cout << "Waiting for Peer..." << std::endl;
- // This blocks waiting for the first packet
- while ( !UdpSocket.hasPendingDatagrams() ) {
- if (mStopped) { return; }
- QThread::msleep(100);
- }
- int first_packet_size = UdpSocket.pendingDatagramSize();
- // The following line is the same as
- int8_t* first_packet = new int8_t[first_packet_size];
- /// \todo fix this to avoid memory leaks
- // but avoids memory leaks
- //std::tr1::shared_ptr<int8_t> first_packet(new int8_t[first_packet_size]);
- receivePacket( UdpSocket, reinterpret_cast<char*>(first_packet), first_packet_size);
- // Check that peer has the same audio settings
- mJackTrip->checkPeerSettings(first_packet);
- mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
- std::cout << "Received Connection for Peer!" << std::endl;
- emit signalReceivedConnectionFromPeer();
-
- // Redundancy Variables
- // --------------------
- // NOTE: These types need to be the same unsigned integer as the sequence
- // number in the header. That way, they wrap around in the "same place"
- uint16_t current_seq_num = 0; // Store current sequence number
- uint16_t last_seq_num = 0; // Store last package sequence number
- uint16_t newer_seq_num = 0; // Store newer sequence number
-
- while ( !mStopped )
- {
- // Timer to report packets arriving too late
- // This QT method gave me a lot of trouble, so I replaced it with my own 'waitForReady'
- // that uses signals and slots and can also report with packets have not
- // arrive for a longer time
- //timeout = UdpSocket.waitForReadyRead(30);
- timeout = waitForReady(UdpSocket, 60000); //60 seconds
-
- // OLD CODE WITHOUT REDUNDANCY----------------------------------------------------
- /*
+ if (gVerboseFlag) std::cout << " UdpDataProtocol:run" << mRunMode << " before Setup Audio Packet buffer, Full Packet buffer, Redundancy Variables" << std::endl;
+ // Setup Audio Packet buffer
+ size_t audio_packet_size = getAudioPacketSizeInBites();
+ //cout << "audio_packet_size: " << audio_packet_size << endl;
+ mAudioPacket = new int8_t[audio_packet_size];
+ std::memset(mAudioPacket, 0, audio_packet_size); // set buffer to 0
+
+ // Setup Full Packet buffer
+ int full_packet_size = mJackTrip->getPacketSizeInBytes();
+ //cout << "full_packet_size: " << full_packet_size << endl;
+ mFullPacket = new int8_t[full_packet_size];
+ std::memset(mFullPacket, 0, full_packet_size); // set buffer to 0
+
+ // bool timeout = false; // Time out flag for packets that arrive too late
+
+ // Put header in first packet
+ mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
+
+ // Redundancy Variables
+ // (Algorithm explained at the end of this file)
+ // ---------------------------------------------
+ int full_redundant_packet_size = full_packet_size * mUdpRedundancyFactor;
+ int8_t* full_redundant_packet;
+ full_redundant_packet = new int8_t[full_redundant_packet_size];
+ std::memset(full_redundant_packet, 0, full_redundant_packet_size); // Initialize to 0
+
+ // Set realtime priority (function in jacktrip_globals.h)
+ if (gVerboseFlag) std::cout << " UdpDataProtocol:run" << mRunMode << " before setRealtimeProcessPriority()" << std::endl;
+ //std::cout << "Experimental version -- not using setRealtimeProcessPriority()" << std::endl;
+ //setRealtimeProcessPriority();
+
+ /////////////////////
+ // to see thread priorities
+ // sudo ps -eLo pri,rtprio,cls,pid,nice,cmd | grep -E 'jackd|jacktrip|rtc|RTPRI' | sort -r
+
+ // from David Runge
+
+ // It seems that it tries to apply the highest available SCHED_FIFO to
+ // jacktrip or half of it (?) [1] (although that's not what you would want,
+ // as this would mean assigning a higher priority to jacktrip than e.g. to
+ // the audio interface and e.g. IRQs that need to be taken care of).
+
+ // The version on github [2] (current 1.1) is actually worse off, as it
+ // just hardcodes RTPRIO 99 (which means jacktrip will compete with the
+ // Linux kernel watchdog, if the user trying to launch jacktrip is even
+ // allowed to use that high of a priority!).
+ // On most systems this will not work at all (aside from it being outright
+ // dangerous). On Arch (and also Ubuntu) the sane default is to allow
+ // rtprio 95 to a privileged user group (e.g. 'realtime' or 'audio', etc.)
+
+ // It would be very awesome, if setting the priority would be dealt with by
+ // a command line flag to jacktrip (e.g. `jacktrip --priority=50`) and
+ // otherwise defaulting to a much much lower number (e.g. 10), so the
+ // application can be run out-of-the-box (even without being in a
+ // privileged group).
+
+ // from Nando
+
+ // You should actually be using the priority that jack gives you when you
+ // create the realtime thread, that puts your process "behind" - so to
+ // speak - the processing that jack does on behalf of all its clients, and
+ // behind (in a properly configured system) the audio interface processing
+ // interrupt. No need to select a priority yourself.
+
+ // In a Fedora system I run jack with a priority of 65 (the Fedora packages
+ // changed the default to a much lower one which is a big no-no). The
+ // clients inherit 60, I think. Some clients that have their own internal
+ // structure of processes (jconvolver) run multiple threads and use
+ // priorities below 60 for them (ie: they start with what jack gave them).
+
+ // If you need to run a thread (not the audio thread) with higher priority
+ // you could retrieve the priority that jack gave you and add some magic
+ // number to get it to be above jack itself (10 would be fine in my
+ // experience).
+
+ //without setting it
+ // PRI RTPRIO CLS PID NI CMD
+ // 60 20 FF 4348 - /usr/bin/jackd -dalsa -dhw:CODEC -r48000 -p128 -n2 -Xseq
+ // 55 15 FF 9835 - ./jacktrip -s
+ // 19 - TS 9835 0 ./jacktrip -s
+ // 19 - TS 9835 0 ./jacktrip -s
+ // 19 - TS 9835 0 ./jacktrip -s
+ // 19 - TS 9835 0 ./jacktrip -s
+ // 19 - TS 9835 0 ./jacktrip -s
+ // 19 - TS 4348 0 /usr/bin/jackd -dalsa -dhw:CODEC -r48000 -p128 -n2 -Xseq
+ // 19 - TS 4348 0 /usr/bin/jackd -dalsa -dhw:CODEC -r48000 -p128 -n2 -Xseq
+ // 19 - TS 4348 0 /usr/bin/jackd -dalsa -dhw:CODEC -r48000 -p128 -n2 -Xseq
+ // 19 - TS 4348 0 /usr/bin/jackd -dalsa -dhw:CODEC -r48000 -p128 -n2 -Xseq
+
+ // jack puts its clients in FF at 5 points below itself
+
+ switch ( mRunMode )
+ {
+ case RECEIVER : {
+ // Connect signals and slots for packets arriving too late notifications
+ QObject::connect(this, SIGNAL(signalWaitingTooLong(int)),
+ this, SLOT(printUdpWaitedTooLong(int)),
+ Qt::QueuedConnection);
+ //-----------------------------------------------------------------------------------
+ // Wait for the first packet to be ready and obtain address
+ // from that packet
+ if (gVerboseFlag) std::cout << " UdpDataProtocol:run" << mRunMode << " before !UdpSocket.hasPendingDatagrams()" << std::endl;
+ std::cout << "Waiting for Peer..." << std::endl;
+ // This blocks waiting for the first packet
+ while ( !UdpSocket.hasPendingDatagrams() ) {
+ if (mStopped) { return; }
+ QThread::msleep(100);
+ if (gVerboseFlag) std::cout << "100ms " << std::flush;
+ }
+ int first_packet_size = UdpSocket.pendingDatagramSize();
+ // The following line is the same as
+ int8_t* first_packet = new int8_t[first_packet_size];
+ /// \todo fix this to avoid memory leaks
+ // but avoids memory leaks
+ //std::tr1::shared_ptr<int8_t> first_packet(new int8_t[first_packet_size]);
+ receivePacket( UdpSocket, reinterpret_cast<char*>(first_packet), first_packet_size);
+ // Check that peer has the same audio settings
+ if (gVerboseFlag) std::cout << std::endl << " UdpDataProtocol:run" << mRunMode << " before mJackTrip->checkPeerSettings()" << std::endl;
+ mJackTrip->checkPeerSettings(first_packet);
+ if (gVerboseFlag) std::cout << "step 7" << std::endl;
+ if (gVerboseFlag) std::cout << " UdpDataProtocol:run" << mRunMode << " before mJackTrip->parseAudioPacket()" << std::endl;
+ mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
+ std::cout << "Received Connection from Peer!" << std::endl;
+ emit signalReceivedConnectionFromPeer();
+
+ // Redundancy Variables
+ // --------------------
+ // NOTE: These types need to be the same unsigned integer as the sequence
+ // number in the header. That way, they wrap around in the "same place"
+ uint16_t current_seq_num = 0; // Store current sequence number
+ uint16_t last_seq_num = 0; // Store last package sequence number
+ uint16_t newer_seq_num = 0; // Store newer sequence number
+
+ if (gVerboseFlag) std::cout << "step 8" << std::endl;
+ while ( !mStopped )
+ {
+ // Timer to report packets arriving too late
+ // This QT method gave me a lot of trouble, so I replaced it with my own 'waitForReady'
+ // that uses signals and slots and can also report with packets have not
+ // arrive for a longer time
+ //timeout = UdpSocket.waitForReadyRead(30);
+ // timeout = cc unused!
+ waitForReady(UdpSocket, 60000); //60 seconds
+
+ // OLD CODE WITHOUT REDUNDANCY----------------------------------------------------
+ /*
// This is blocking until we get a packet...
receivePacket( UdpSocket, reinterpret_cast<char*>(mFullPacket), full_packet_size);
//mRingBuffer->insertSlotNonBlocking(mAudioPacket);
mJackTrip->writeAudioBuffer(mAudioPacket);
*/
- //----------------------------------------------------------------------------------
- receivePacketRedundancy(UdpSocket,
- full_redundant_packet,
- full_redundant_packet_size,
- full_packet_size,
- current_seq_num,
- last_seq_num,
- newer_seq_num);
- }
- break; }
-
- case SENDER : {
- //-----------------------------------------------------------------------------------
- while ( !mStopped )
- {
- // OLD CODE WITHOUT REDUNDANCY -----------------------------------------------------
- /*
+ //----------------------------------------------------------------------------------
+ receivePacketRedundancy(UdpSocket,
+ full_redundant_packet,
+ full_redundant_packet_size,
+ full_packet_size,
+ current_seq_num,
+ last_seq_num,
+ newer_seq_num);
+ }
+ break; }
+
+ case SENDER : {
+ //Make sure we don't start sending packets too soon.
+ QThread::msleep(100);
+ //-----------------------------------------------------------------------------------
+ while ( !mStopped )
+ {
+ // OLD CODE WITHOUT REDUNDANCY -----------------------------------------------------
+ /*
// We block until there's stuff available to read
mJackTrip->readAudioBuffer( mAudioPacket );
mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
//int bytes_sent = sendPacket( reinterpret_cast<char*>(mFullPacket), full_packet_size);
sendPacket( UdpSocket, PeerAddress, reinterpret_cast<char*>(mFullPacket), full_packet_size);
*/
- //----------------------------------------------------------------------------------
- sendPacketRedundancy(UdpSocket,
- PeerAddress,
- full_redundant_packet,
- full_redundant_packet_size,
- full_packet_size);
- }
- break; }
- }
+ //----------------------------------------------------------------------------------
+ sendPacketRedundancy(full_redundant_packet,
+ full_redundant_packet_size,
+ full_packet_size);
+ }
+ break; }
+ }
}
//*******************************************************************************
-bool UdpDataProtocol::waitForReady(QUdpSocket& UdpSocket, int timeout_msec)
+//bool
+void UdpDataProtocol::waitForReady(QUdpSocket& UdpSocket, int timeout_msec)
{
- int loop_resolution_usec = 100; // usecs to wait on each loop
- int emit_resolution_usec = 10000; // 10 milliseconds
- int timeout_usec = timeout_msec * 1000;
- int ellaped_time_usec = 0; // Ellapsed time in milliseconds
-
- while ( ( !(UdpSocket.hasPendingDatagrams()) && (ellaped_time_usec <= timeout_usec) )
- && !mStopped ){
- if (mStopped) { return false; }
- QThread::usleep(loop_resolution_usec);
- ellaped_time_usec += loop_resolution_usec;
-
- if ( !(ellaped_time_usec % emit_resolution_usec) ) {
- emit signalWatingTooLong(static_cast<int>(ellaped_time_usec/1000));
+ int loop_resolution_usec = 100; // usecs to wait on each loop
+ int emit_resolution_usec = 10000; // 10 milliseconds
+ int timeout_usec = timeout_msec * 1000;
+ int elapsed_time_usec = 0; // Ellapsed time in milliseconds
+
+ while ( ( !(
+ UdpSocket.hasPendingDatagrams() &&
+ (UdpSocket.pendingDatagramSize() > 0)
+ ) && (elapsed_time_usec <= timeout_usec) )
+ && !mStopped ){
+ // if (mStopped) { return false; }
+ QThread::usleep(loop_resolution_usec);
+ elapsed_time_usec += loop_resolution_usec;
+
+ if ( !(elapsed_time_usec % emit_resolution_usec) ) {
+ emit signalWaitingTooLong(static_cast<int>(elapsed_time_usec/1000));
+ }
}
- }
-
- if ( ellaped_time_usec >= timeout_usec )
- {
- emit signalWatingTooLong(ellaped_time_usec/1000);
- return false;
- }
- return true;
+ // cc under what condition?
+ // if ( elapsed_time_usec >= timeout_usec )
+ // {
+ // emit signalWaitingTooLong(elapsed_time_usec/1000);
+ // return false;
+ // }
+ // return true;
}
//*******************************************************************************
void UdpDataProtocol::printUdpWaitedTooLong(int wait_msec)
{
- int wait_time = 30; // msec
- if ( !(wait_msec%wait_time) ) {
- std::cerr << "UDP waiting too long (more than " << wait_time << "ms)..." << endl;
- }
+ int wait_time = 30; // msec
+ if ( !(wait_msec%wait_time) ) {
+ std::cerr << "UDP waiting too long (more than " << wait_time << "ms)..." << endl;
+ }
}
uint16_t& last_seq_num,
uint16_t& newer_seq_num)
{
- // This is blocking until we get a packet...
- receivePacket( UdpSocket, reinterpret_cast<char*>(full_redundant_packet),
- full_redundant_packet_size);
-
- // Get Packet Sequence Number
- newer_seq_num =
- mJackTrip->getPeerSequenceNumber(full_redundant_packet);
- current_seq_num = newer_seq_num;
-
-
- //cout << current_seq_num << " ";
- int redun_last_index = 0;
- for (unsigned int i = 1; i<mUdpRedundancyFactor; i++) {
- // Check if the package we receive is the next one expected, i.e.,
- // current_seq_num == (last_seq_num+1)
- if ( current_seq_num == (last_seq_num+1) ) { break; }
-
- // if it's not, check the next one until it is the corresponding packet
- // or there aren't more available packets
- redun_last_index = i; // index of packet to use in the redundant packet
- current_seq_num =
- mJackTrip->getPeerSequenceNumber( full_redundant_packet + (i*full_packet_size) );
+ // This is blocking until we get a packet...
+ receivePacket( UdpSocket, reinterpret_cast<char*>(full_redundant_packet),
+ full_redundant_packet_size);
+
+ // Get Packet Sequence Number
+ newer_seq_num =
+ mJackTrip->getPeerSequenceNumber(full_redundant_packet);
+ current_seq_num = newer_seq_num;
+
+
//cout << current_seq_num << " ";
- }
- //cout << endl;
+ int redun_last_index = 0;
+ for (unsigned int i = 1; i<mUdpRedundancyFactor; i++) {
+ // Check if the package we receive is the next one expected, i.e.,
+ // current_seq_num == (last_seq_num+1)
+ if ( current_seq_num == (last_seq_num+1) ) { break; }
+
+ // if it's not, check the next one until it is the corresponding packet
+ // or there aren't more available packets
+ redun_last_index = i; // index of packet to use in the redundant packet
+ current_seq_num =
+ mJackTrip->getPeerSequenceNumber( full_redundant_packet + (i*full_packet_size) );
+ //cout << current_seq_num << " ";
+ }
+ //cout << endl;
- last_seq_num = newer_seq_num; // Save last read packet
+ last_seq_num = newer_seq_num; // Save last read packet
- // Send to audio all available audio packets, in order
- for (int i = redun_last_index; i>=0; i--) {
- memcpy(mFullPacket,
- full_redundant_packet + (i*full_packet_size),
- full_packet_size);
- mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
- mJackTrip->writeAudioBuffer(mAudioPacket);
- }
+ // Send to audio all available audio packets, in order
+ for (int i = redun_last_index; i>=0; i--) {
+ memcpy(mFullPacket,
+ full_redundant_packet + (i*full_packet_size),
+ full_packet_size);
+ mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
+ mJackTrip->writeAudioBuffer(mAudioPacket);
+ }
}
//*******************************************************************************
-void UdpDataProtocol::sendPacketRedundancy(QUdpSocket& UdpSocket,
- QHostAddress& PeerAddress,
- int8_t* full_redundant_packet,
+void UdpDataProtocol::sendPacketRedundancy(int8_t* full_redundant_packet,
int full_redundant_packet_size,
int full_packet_size)
{
- mJackTrip->readAudioBuffer( mAudioPacket );
- mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
-
- // Move older packets to end of array of redundant packets
- std::memmove(full_redundant_packet+full_packet_size,
- full_redundant_packet,
- full_packet_size*(mUdpRedundancyFactor-1));
- // Copy new packet to the begining of array
- std::memcpy(full_redundant_packet,
- mFullPacket, full_packet_size);
-
- // 10% (or other number) packet lost simulation.
- // Uncomment the if to activate
- //---------------------------------------------------------------------------------
- //int random_integer = rand();
- //if ( random_integer > (RAND_MAX/10) )
- //{
- sendPacket( UdpSocket, PeerAddress, reinterpret_cast<char*>(full_redundant_packet),
- full_redundant_packet_size);
- //}
- //---------------------------------------------------------------------------------
-
- mJackTrip->increaseSequenceNumber();
+ mJackTrip->readAudioBuffer( mAudioPacket );
+ mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
+
+ // Move older packets to end of array of redundant packets
+ std::memmove(full_redundant_packet+full_packet_size,
+ full_redundant_packet,
+ full_packet_size*(mUdpRedundancyFactor-1));
+ // Copy new packet to the begining of array
+ std::memcpy(full_redundant_packet,
+ mFullPacket, full_packet_size);
+
+ // 10% (or other number) packet lost simulation.
+ // Uncomment the if to activate
+ //---------------------------------------------------------------------------------
+ //int random_integer = rand();
+ //if ( random_integer > (RAND_MAX/10) )
+ //{
+ sendPacket( reinterpret_cast<char*>(full_redundant_packet),
+ full_redundant_packet_size);
+ //}
+ //---------------------------------------------------------------------------------
+
+ mJackTrip->increaseSequenceNumber();
}
/*
The Redundancy Algorythmn works as follows. We send a packet that contains
- a mUdpRedundancyFactor number of packets (header+audio). This big packet looks
+ a mUdpRedundancyFactor number of packets (header+audio). This big packet looks
as follows
-
+
---------- ------------ -----------------------------------
- | UDP[n] | | UDP[n-1] | ... | UDP[n-(mUdpRedundancyFactor-1)] |
+ | UDP[n] | | UDP[n-1] | ... | UDP[n-(mUdpRedundancyFactor-1)] |
---------- ------------ -----------------------------------
Then, for the new audio buffer, we shift everything to the right and send:
-
+
---------- ------------ -------------------------------------
- | UDP[n+1] | | UDP[n] | ... | UDP[n-(mUdpRedundancyFactor-1)+1] |
+ | UDP[n+1] | | UDP[n] | ... | UDP[n-(mUdpRedundancyFactor-1)+1] |
---------- ------------ -------------------------------------
etc...
---------- ---------- ---------- ----------
| UDP[4] | | UDP[3] | | UDP[2] | | UDP[1] |
---------- ---------- ---------- ----------
-
+
---------- ---------- ---------- ----------
| UDP[5] | | UDP[4] | | UDP[3] | | UDP[2] |
---------- ---------- ---------- ----------
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*/
class UdpDataProtocol : public DataProtocol
{
- Q_OBJECT;
-
+ Q_OBJECT;
+
public:
-
- /** \brief The class constructor
+
+ /** \brief The class constructor
* \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
* \param runmode Sets the run mode, use either SENDER or RECEIVER
* \param bind_port Port number to bind for this socket (this is the receive or send port depending on the runmode)
* \param peer_port Peer port number (this is the receive or send port depending on the runmode)
* \param udp_redundancy_factor Number of redundant packets
*/
- UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode,
- int bind_port, int peer_port,
- unsigned int udp_redundancy_factor = 1);
-
- /** \brief The class destructor
+ UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode,
+ int bind_port, int peer_port,
+ unsigned int udp_redundancy_factor = 1);
+
+ /** \brief The class destructor
*/
- virtual ~UdpDataProtocol();
+ virtual ~UdpDataProtocol();
- /** \brief Set the Peer address to connect to
+ /** \brief Set the Peer address to connect to
* \param peerHostOrIP IPv4 number or host name
*/
- void setPeerAddress(const char* peerHostOrIP) throw(std::invalid_argument);
+ void setPeerAddress(const char* peerHostOrIP) throw(std::invalid_argument);
+
+#if defined (__WIN_32__)
+ void setSocket(SOCKET &socket) throw(std::runtime_error);
+#else
+ void setSocket(int &socket) throw(std::runtime_error);
+#endif
- /** \brief Receives a packet. It blocks until a packet is received
+ /** \brief Receives a packet. It blocks until a packet is received
*
* This function makes sure we recieve a complete packet
* of size n
* \param n size of packet to receive
* \return number of bytes read, -1 on error
*/
- //virtual int receivePacket(char* buf, const size_t n);
- virtual int receivePacket(QUdpSocket& UdpSocket, char* buf, const size_t n);
-
- /** \brief Sends a packet
+ //virtual int receivePacket(char* buf, const size_t n);
+ virtual int receivePacket(QUdpSocket& UdpSocket, char* buf, const size_t n);
+
+ /** \brief Sends a packet
*
* This function meakes sure we send a complete packet
* of size n
* \param n size of packet to receive
* \return number of bytes read, -1 on error
*/
- virtual int sendPacket(QUdpSocket& UdpSocket, const QHostAddress& PeerAddress,
- const char* buf, const size_t n);
-
- /** \brief Obtains the peer address from the first UDP packet received. This address
+ virtual int sendPacket(const char* buf, const size_t n);
+
+ /** \brief Obtains the peer address from the first UDP packet received. This address
* is used by the SERVER mode to connect back to the client.
* \param peerHostAddress QHostAddress to store the peer address
* \param port Receiving port
*/
- virtual void getPeerAddressFromFirstPacket(QUdpSocket& UdpSocket,
- QHostAddress& peerHostAddress,
- uint16_t& port);
+ virtual void getPeerAddressFromFirstPacket(QUdpSocket& UdpSocket,
+ QHostAddress& peerHostAddress,
+ uint16_t& port);
- /** \brief Sets the bind port number
+ /** \brief Sets the bind port number
*/
- void setBindPort(int port)
- { mBindPort = port; }
+ void setBindPort(int port)
+ { mBindPort = port; }
- /** \brief Sets the peer port number
+ /** \brief Sets the peer port number
*/
- void setPeerPort(int port)
- { mPeerPort = port; }
+ void setPeerPort(int port)
+ { mPeerPort = port; mPeerAddr.sin_port = htons(mPeerPort); mPeerAddr6.sin6_port = htons(mPeerPort); }
- /** \brief Implements the Thread Loop. To start the thread, call start()
+ /** \brief Implements the Thread Loop. To start the thread, call start()
* ( DO NOT CALL run() )
*
* This function creats and binds all the socket and start the connection loop thread.
*/
- virtual void run();
+ virtual void run();
private slots:
- void printUdpWaitedTooLong(int wait_msec);
+ void printUdpWaitedTooLong(int wait_msec);
signals:
- /// \brief Signals when waiting every 10 milliseconds, with the total wait on wait_msec
- /// \param wait_msec Total wait in milliseconds
- void signalWatingTooLong(int wait_msec);
+ /// \brief Signals when waiting every 10 milliseconds, with the total wait on wait_msec
+ /// \param wait_msec Total wait in milliseconds
+ void signalWaitingTooLong(int wait_msec);
-//private:
+ //private:
protected:
- /** \brief Binds the UDP socket to the available address and specified port
+ /** \brief Binds the UDP socket to the available address and specified port
*/
- void bindSocket(QUdpSocket& UdpSocket) throw(std::runtime_error);
-
- /** \brief This function blocks until data is available for reading in the
+#if defined (__WIN_32__)
+ SOCKET bindSocket() throw(std::runtime_error);
+#else
+ int bindSocket() throw(std::runtime_error);
+#endif
+
+ /** \brief This function blocks until data is available for reading in the
* QUdpSocket. The function will timeout after timeout_msec microseconds.
*
* This function is intended to replace QAbstractSocket::waitForReadyRead which has
* \return returns true if there is data available for reading;
* otherwise it returns false (if an error occurred or the operation timed out)
*/
- bool waitForReady(QUdpSocket& UdpSocket, int timeout_msec);
+ void waitForReady(QUdpSocket& UdpSocket, int timeout_msec);
- /** \brief Redundancy algorythm at the receiving end
+ /** \brief Redundancy algorythm at the receiving end
*/
- virtual void receivePacketRedundancy(QUdpSocket& UdpSocket,
- int8_t* full_redundant_packet,
- int full_redundant_packet_size,
- int full_packet_size,
- uint16_t& current_seq_num,
- uint16_t& last_seq_num,
- uint16_t& newer_seq_num);
-
- /** \brief Redundancy algorythm at the sender's end
+ virtual void receivePacketRedundancy(QUdpSocket& UdpSocket,
+ int8_t* full_redundant_packet,
+ int full_redundant_packet_size,
+ int full_packet_size,
+ uint16_t& current_seq_num,
+ uint16_t& last_seq_num,
+ uint16_t& newer_seq_num);
+
+ /** \brief Redundancy algorythm at the sender's end
*/
- virtual void sendPacketRedundancy(QUdpSocket& UdpSocket,
- QHostAddress& PeerAddress,
- int8_t* full_redundant_packet,
- int full_redundant_packet_size,
- int full_packet_size);
+ virtual void sendPacketRedundancy(int8_t* full_redundant_packet,
+ int full_redundant_packet_size,
+ int full_packet_size);
private:
- int mBindPort; ///< Local Port number to Bind
- int mPeerPort; ///< Peer Port number
- const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
-
- QHostAddress mPeerAddress; ///< The Peer Address
-
- int8_t* mAudioPacket; ///< Buffer to store Audio Packets
- int8_t* mFullPacket; ///< Buffer to store Full Packet (audio+header)
-
- unsigned int mUdpRedundancyFactor; ///< Factor of redundancy
- static QMutex sUdpMutex; ///< Mutex to make thread safe the binding process
+ int mBindPort; ///< Local Port number to Bind
+ int mPeerPort; ///< Peer Port number
+ const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
+ bool mIPv6; /// Use IPv6
+
+ QHostAddress mPeerAddress; ///< The Peer Address
+ struct sockaddr_in mPeerAddr;
+ struct sockaddr_in6 mPeerAddr6;
+#if defined (__WIN_32__)
+ SOCKET mSocket;
+#else
+ int mSocket;
+#endif
+
+ int8_t* mAudioPacket; ///< Buffer to store Audio Packets
+ int8_t* mFullPacket; ///< Buffer to store Full Packet (audio+header)
+
+ unsigned int mUdpRedundancyFactor; ///< Factor of redundancy
+ static QMutex sUdpMutex; ///< Mutex to make thread safe the binding process
};
#endif // __UDPDATAPROTOCOL_H__
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//*******************************************************************************
UdpDataProtocol::UdpDataProtocol(const runModeT runmode, const char* peerHostOrIP)
- : DataProtocol(runmode)
+ : DataProtocol(runmode)
{
- setPeerIPv4Address(peerHostOrIP);
- setBindSocket();
+ setPeerIPv4Address(peerHostOrIP);
+ setBindSocket();
}
//*******************************************************************************
void UdpDataProtocol::setBindSocket()
{
- // UDP socket creation
- mSockFd = socket(AF_INET, SOCK_DGRAM, 0);
- if ( mSockFd < 0 ) {
- std::cerr << "ERROR: UDP Socket Error" << std::endl;
- std::exit(0);
- }
-
- // Bind local address and port
- /// \todo Bind to a different port in case this one is used by a different instance
- /// of the program
- struct sockaddr_in LocalIPv4Addr = getLocalIPv4AddressStruct();
- int nBind = bind(mSockFd, (struct sockaddr *) &LocalIPv4Addr, sizeof(LocalIPv4Addr));
- if ( nBind < 0 ) {
- std::cerr << "ERROR: UDP Socket Bind Error" << std::endl;
- std::exit(0);
- }
-
- std::cout << "Successful socket creation and port binding" << std::endl;
-
- //Connected UDP
- struct sockaddr_in PeerIPv4Addr = getPeerIPv4AddressStruct();
- int nCon = ::connect(mSockFd, (struct sockaddr *) &PeerIPv4Addr, sizeof(PeerIPv4Addr));
- if ( nCon < 0) {
- std::cerr << "ERROR: UDP Socket Connect Error" << std::endl;
- std::exit(0);
- }
+ // UDP socket creation
+ mSockFd = socket(AF_INET, SOCK_DGRAM, 0);
+ if ( mSockFd < 0 ) {
+ std::cerr << "ERROR: UDP Socket Error" << std::endl;
+ std::exit(0);
+ }
+
+ // Bind local address and port
+ /// \todo Bind to a different port in case this one is used by a different instance
+ /// of the program
+ struct sockaddr_in LocalIPv4Addr = getLocalIPv4AddressStruct();
+ int nBind = bind(mSockFd, (struct sockaddr *) &LocalIPv4Addr, sizeof(LocalIPv4Addr));
+ if ( nBind < 0 ) {
+ std::cerr << "ERROR: UDP Socket Bind Error" << std::endl;
+ std::exit(0);
+ }
+
+ std::cout << "Successful socket creation and port binding" << std::endl;
+
+ //Connected UDP
+ struct sockaddr_in PeerIPv4Addr = getPeerIPv4AddressStruct();
+ int nCon = ::connect(mSockFd, (struct sockaddr *) &PeerIPv4Addr, sizeof(PeerIPv4Addr));
+ if ( nCon < 0) {
+ std::cerr << "ERROR: UDP Socket Connect Error" << std::endl;
+ std::exit(0);
+ }
}
// Page 88 (readn)
size_t UdpDataProtocol::receivePacket(char* buff, size_t n)
{
- size_t nleft;
- ssize_t nread;
- char* ptr;
-
- ptr = buff;
- nleft = n;
- while (nleft > 0) {
- if ( (nread = ::read(mSockFd, ptr, nleft)) < 0) {
- if (errno == EINTR)
- nread = 0; // and call read() again
- else
- return(-1);
- } else if (nread == 0)
- break; // EOF
-
- nleft -= nread;
- ptr += nread;
- }
- return(n - nleft);
+ size_t nleft;
+ ssize_t nread;
+ char* ptr;
+
+ ptr = buff;
+ nleft = n;
+ while (nleft > 0) {
+ if ( (nread = ::read(mSockFd, ptr, nleft)) < 0) {
+ if (errno == EINTR)
+ nread = 0; // and call read() again
+ else
+ return(-1);
+ } else if (nread == 0)
+ break; // EOF
+
+ nleft -= nread;
+ ptr += nread;
+ }
+ return(n - nleft);
}
// Write "n" bytes to a descriptor
size_t UdpDataProtocol::sendPacket(const char* buff, size_t n)
{
- size_t nleft;
- ssize_t nwritten;
- const char* ptr;
-
- ptr = buff;
- nleft = n;
- while (nleft > 0) {
- if ( (nwritten = ::write(mSockFd, ptr, nleft)) <= 0) {
- if (nwritten < 0 && errno == EINTR)
- nwritten = 0; // and call write() again
- else
- return(-1); // error
+ size_t nleft;
+ ssize_t nwritten;
+ const char* ptr;
+
+ ptr = buff;
+ nleft = n;
+ while (nleft > 0) {
+ if ( (nwritten = ::write(mSockFd, ptr, nleft)) <= 0) {
+ if (nwritten < 0 && errno == EINTR)
+ nwritten = 0; // and call write() again
+ else
+ return(-1); // error
+ }
+
+ nleft -= nwritten;
+ ptr += nwritten;
}
-
- nleft -= nwritten;
- ptr += nwritten;
- }
- return(n);
+ return(n);
}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#include "DataProtocol.h"
/** \brief UDP implementation of DataProtocol class
- *
- *
+ *
+ *
*
*/
class UdpDataProtocol : public DataProtocol
{
public:
- /** \brief The class constructor
+ /** \brief The class constructor
* \param runmode Sets the run mode, use either SENDER or RECEIVER
* \param peerHostOrIP IPv4 number or host name
*/
- UdpDataProtocol(const runModeT runmode, const char* peerHostOrIP);
+ UdpDataProtocol(const runModeT runmode, const char* peerHostOrIP);
- /** \brief The class destructor
+ /** \brief The class destructor
*/
- virtual ~UdpDataProtocol() {};
+ virtual ~UdpDataProtocol() {};
- /** \brief Receives a packet
+ /** \brief Receives a packet
*
* This function makes sure we recieve a complete packet
* of size n
* \param n size of packet to receive
* \return number of bytes read, -1 on error
*/
- virtual size_t receivePacket(char* buf, size_t n);
+ virtual size_t receivePacket(char* buf, size_t n);
- /** \brief Sends a packet
+ /** \brief Sends a packet
*
* This function meakes sure we send a complete packet
* of size n
* \param n size of packet to receive
* \return number of bytes read, -1 on error
*/
- virtual size_t sendPacket(const char* buff, size_t n);
+ virtual size_t sendPacket(const char* buff, size_t n);
- //virtual void run();
+ //virtual void run();
private:
- void setBindSocket();
+ void setBindSocket();
- int mSockFd; ///< Socket file descriptor
+ int mSockFd; ///< Socket file descriptor
};
#endif
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//mJTWorker(NULL),
mServerPort(server_port),
mStopped(false),
- mTotalRunningThreads(0)
+ #ifdef WAIR // wair
+ mWAIR(false),
+ #endif // endwhere
+ mTotalRunningThreads(0),
+ m_connectDefaultAudioPorts(false)
{
- // Register JackTripWorker with the master listener
- //mJTWorker = new JackTripWorker(this);
- mJTWorkers = new QVector<JackTripWorker*>;
- for (int i = 0; i<gMaxThreads; i++) {
- mJTWorkers->insert(i, NULL);
- }
+ // Register JackTripWorker with the master listener
+ //mJTWorker = new JackTripWorker(this);
+ mJTWorkers = new QVector<JackTripWorker*>;
+ for (int i = 0; i<gMaxThreads; i++) {
+ mJTWorkers->insert(i, NULL);
+ }
- //mJTWorkers = new JackTripWorker(this);
- mThreadPool.setExpiryTimeout(3000); // msec (-1) = forever
- // Inizialize IP addresses
- for (int i = 0; i<gMaxThreads; i++) {
- mActiveAddress[i][0] = 0; // 32-bit ints
- mActiveAddress[i][1] = 0; // 32-bit ints
- }
- // Set the base dynamic port
- // The Dynamic and/or Private Ports are those from 49152 through 65535
- // mBasePort = ( rand() % ( (65535 - gMaxThreads) - 49152 ) ) + 49152;
+ //mJTWorkers = new JackTripWorker(this);
+ mThreadPool.setExpiryTimeout(3000); // msec (-1) = forever
+ // Inizialize IP addresses
+ for (int i = 0; i<gMaxThreads; i++) {
+ mActiveAddress[i].address = ""; // Address strings
+ mActiveAddress[i].port = 0;
+ }
+ // Set the base dynamic port
+ // The Dynamic and/or Private Ports are those from 49152 through 65535
+ // mBasePort = ( rand() % ( (65535 - gMaxThreads) - 49152 ) ) + 49152;
- // SoundWIRE ports open are UDP 61000-62000
- mBasePort = 61000;
+ // SoundWIRE ports open are UDP 61000-62000
+ mBasePort = 61000;
+
+ mUnderRunMode = JackTrip::WAVETABLE;
+ mBufferQueueLength = gDefaultQueueLength;
}
//*******************************************************************************
UdpMasterListener::~UdpMasterListener()
{
- QMutexLocker lock(&mMutex);
- mThreadPool.waitForDone();
- //delete mJTWorker;
- for (int i = 0; i<gMaxThreads; i++) {
- delete mJTWorkers->at(i);
- }
- delete mJTWorkers;
+ QMutexLocker lock(&mMutex);
+ mThreadPool.waitForDone();
+ //delete mJTWorker;
+ for (int i = 0; i<gMaxThreads; i++) {
+ delete mJTWorkers->at(i);
+ }
+ delete mJTWorkers;
}
// the pool and then connect again.
void UdpMasterListener::run()
{
- mStopped = false;
-
- QHostAddress PeerAddress; // Object to store peer address
- int peer_udp_port; // Peer listening port
- int server_udp_port; // Server assigned udp port
-
- // Create and bind the TCP server
- // ------------------------------
- QTcpServer TcpServer;
- if ( !TcpServer.listen(QHostAddress::Any, mServerPort) ) {
- std::cerr << "TCP Socket Server ERROR: " << TcpServer.errorString().toStdString() << endl;
- std::exit(1);
- }
+ mStopped = false;
+
+ QHostAddress PeerAddress; // Object to store peer address
+ int peer_udp_port; // Peer listening port
+ int server_udp_port; // Server assigned udp port
+
+ // Create and bind the TCP server
+ // ------------------------------
+ QTcpServer TcpServer;
+ if ( !TcpServer.listen(QHostAddress::Any, mServerPort) ) {
+ std::cerr << "TCP Socket Server ERROR: " << TcpServer.errorString().toStdString() << endl;
+ std::exit(1);
+ }
- const int tcpTimeout = 5*1000;
+ const int tcpTimeout = 5*1000;
- cout << "JackTrip MULTI-THREADED SERVER: TCP Server Listening in Port = " << TcpServer.serverPort() << endl;
- while ( !mStopped )
- {
- cout << "JackTrip MULTI-THREADED SERVER: Waiting for client connections..." << endl;
- cout << "=======================================================" << endl;
- while ( !TcpServer.waitForNewConnection(1000) )
- { if (mStopped) { return; } } // block until a new connection is received
- cout << "JackTrip MULTI-THREADED SERVER: Client Connection Received!" << endl;
-
- // Control loop to be able to exit if UDPs or TCPs error ocurr
- for (int dum = 0; dum<1; dum++) {
- QTcpSocket *clientConnection = TcpServer.nextPendingConnection();
- if ( !clientConnection->waitForConnected(tcpTimeout) ) {
- std::cerr << clientConnection->errorString().toStdString() << endl;
- break;
- }
- PeerAddress = clientConnection->peerAddress();
- cout << "JackTrip MULTI-THREADED SERVER: Client Connect Received from Address : "
- << PeerAddress.toString().toStdString() << endl;
-
- // Get UDP port from client
- // ------------------------
- peer_udp_port = readClientUdpPort(clientConnection);
- if ( peer_udp_port == 0 ) { break; }
- cout << "JackTrip MULTI-THREADED SERVER: Client UDP Port is = " << peer_udp_port << endl;
-
- // Check is client is new or not
- // -----------------------------
- // Check if Address is not already in the thread pool
- // check by comparing 32-bit addresses
- int id = isNewAddress(PeerAddress.toIPv4Address(), peer_udp_port);
- // If the address is not new, we need to remove the client from the pool
- // before re-starting the connection
- if (id == -1) {
- int id_remove;
- id_remove = getPoolID(PeerAddress.toIPv4Address(), peer_udp_port);
- // stop the thread
- mJTWorkers->at(id_remove)->stopThread();
- // block until the thread has been removed from the pool
- while ( isNewAddress(PeerAddress.toIPv4Address(), peer_udp_port) == -1 ) {
- cout << "JackTrip MULTI-THREADED SERVER: Removing JackTripWorker from pool..." << endl;
- QThread::msleep(10);
+ cout << "JackTrip HUB SERVER: TCP Server Listening in Port = " << TcpServer.serverPort() << endl;
+ while ( !mStopped )
+ {
+ cout << "JackTrip HUB SERVER: Waiting for client connections..." << endl;
+ cout << "JackTrip HUB SERVER: Hub auto audio patch setting = " << mHubPatch << endl;
+ cout << "=======================================================" << endl;
+ while ( !TcpServer.waitForNewConnection(1000) )
+ { if (mStopped) { return; } } // block until a new connection is received
+ cout << "JackTrip HUB SERVER: Client Connection Received!" << endl;
+
+ // Control loop to be able to exit if UDPs or TCPs error ocurr
+ for (int dum = 0; dum<1; dum++) {
+ QTcpSocket *clientConnection = TcpServer.nextPendingConnection();
+ if ( !clientConnection->waitForConnected(tcpTimeout) ) {
+ std::cerr << clientConnection->errorString().toStdString() << endl;
+ break;
+ }
+ PeerAddress = clientConnection->peerAddress();
+ cout << "JackTrip HUB SERVER: Client Connect Received from Address : "
+ << PeerAddress.toString().toStdString() << endl;
+
+ // Get UDP port from client
+ // ------------------------
+ peer_udp_port = readClientUdpPort(clientConnection);
+ if ( peer_udp_port == 0 ) { break; }
+ cout << "JackTrip HUB SERVER: Client UDP Port is = " << peer_udp_port << endl;
+
+ // Check is client is new or not
+ // -----------------------------
+ // Check if Address is not already in the thread pool
+ // check by comparing address strings (To handle IPv4 and IPv6.)
+ int id = isNewAddress(PeerAddress.toString(), peer_udp_port);
+ // If the address is not new, we need to remove the client from the pool
+ // before re-starting the connection
+
+ if (id == -1) {
+ int id_remove;
+ id_remove = getPoolID(PeerAddress.toString(), peer_udp_port);
+ // stop the thread
+ mJTWorkers->at(id_remove)->stopThread();
+ // block until the thread has been removed from the pool
+ while ( isNewAddress(PeerAddress.toString(), peer_udp_port) == -1 ) {
+ cout << "JackTrip HUB SERVER: Removing JackTripWorker from pool..." << endl;
+ QThread::msleep(10);
+ }
+ // Get a new ID for this client
+ //id = isNewAddress(PeerAddress.toIPv4Address(), peer_udp_port);
+ id = getPoolID(PeerAddress.toString(), peer_udp_port);
+ }
+ // Assign server port and send it to Client
+ server_udp_port = mBasePort+id;
+ if ( sendUdpPort(clientConnection, server_udp_port) == 0 ) {
+ clientConnection->close();
+ delete clientConnection;
+ releaseThread(id);
+ break;
+ }
+
+ // Close and Delete the socket
+ // ---------------------------
+ clientConnection->close();
+ delete clientConnection;
+ cout << "JackTrip HUB SERVER: Client TCP Connection Closed!" << endl;
+
+ // Spawn Thread to Pool
+ // --------------------
+ // Register JackTripWorker with the master listener
+ delete mJTWorkers->at(id); // just in case the Worker was previously created
+ mJTWorkers->replace(id, new JackTripWorker(this, mBufferQueueLength, mUnderRunMode));
+ // redirect port and spawn listener
+ cout << "JackTrip HUB SERVER: Spawning JackTripWorker..." << endl;
+ {
+ QMutexLocker lock(&mMutex);
+ mJTWorkers->at(id)->setJackTrip(id,
+ mActiveAddress[id].address,
+ server_udp_port,
+ mActiveAddress[id].port,
+ 1,
+ m_connectDefaultAudioPorts
+ ); /// \todo temp default to 1 channel
+
+ qDebug() << "mPeerAddress" << id << mActiveAddress[id].address << mActiveAddress[id].port;
+ }
+ //send one thread to the pool
+ cout << "JackTrip HUB SERVER: Starting JackTripWorker..." << endl;
+ mThreadPool.start(mJTWorkers->at(id), QThread::TimeCriticalPriority);
+ // wait until one is complete before another spawns
+ while (mJTWorkers->at(id)->isSpawning()) { QThread::msleep(10); }
+ //mTotalRunningThreads++;
+ cout << "JackTrip HUB SERVER: Total Running Threads: " << mTotalRunningThreads << endl;
+ cout << "===============================================================" << endl;
+ QThread::msleep(100);
+#ifdef WAIR // WAIR
+ if (isWAIR()) connectMesh(true); // invoked with -Sw
+#endif // endwhere
+
+ qDebug() << "mPeerAddress" << mActiveAddress[id].address << mActiveAddress[id].port;
+
+ connectPatch(true);
}
- // Get a new ID for this client
- //id = isNewAddress(PeerAddress.toIPv4Address(), peer_udp_port);
- id = getPoolID(PeerAddress.toIPv4Address(), peer_udp_port);
- }
- // Assign server port and send it to Client
- server_udp_port = mBasePort+id;
- if ( sendUdpPort(clientConnection, server_udp_port) == 0 ) {
- clientConnection->close();
- delete clientConnection;
- releaseThread(id);
- break;
- }
-
- // Close and Delete the socket
- // ---------------------------
- clientConnection->close();
- delete clientConnection;
- cout << "JackTrip MULTI-THREADED SERVER: Client TCP Socket Closed!" << endl;
-
- // Spawn Thread to Pool
- // --------------------
- // Register JackTripWorker with the master listener
- delete mJTWorkers->at(id); // just in case the Worker was previously created
- mJTWorkers->replace(id, new JackTripWorker(this));
- // redirect port and spawn listener
- cout << "---> JackTrip MULTI-THREADED SERVER: Spawning Listener..." << endl;
- {
- QMutexLocker lock(&mMutex);
- mJTWorkers->at(id)->setJackTrip(id, mActiveAddress[id][0],
- server_udp_port, mActiveAddress[id][1],
- 1); /// \todo temp default to 1 channel
- }
- //send one thread to the pool
- cout << "---> JackTrip MULTI-THREADED SERVER: Starting Thread..." << endl;
- mThreadPool.start(mJTWorkers->at(id), QThread::TimeCriticalPriority);
- // wait until one is complete before another spawns
- while (mJTWorkers->at(id)->isSpawning()) { QThread::msleep(10); }
- //mTotalRunningThreads++;
- cout << "JackTrip MULTI-THREADED SERVER: Total Running Threads: " << mTotalRunningThreads << endl;
- cout << "===============================================================" << endl;
- QThread::msleep(100);
}
- }
- /*
+ /*
// Create objects on the stack
QUdpSocket MasterUdpSocket;
QHostAddress PeerAddress;
// Returns 0 on error
int UdpMasterListener::readClientUdpPort(QTcpSocket* clientConnection)
{
- // Read the size of the package
- // ----------------------------
- //tcpClient.waitForReadyRead();
- cout << "Reading UDP port from Server..." << endl;
- while (clientConnection->bytesAvailable() < (int)sizeof(uint16_t)) {
- if (!clientConnection->waitForReadyRead()) {
- std::cerr << "TCP Socket ERROR: " << clientConnection->errorString().toStdString() << endl;
- return 0;
+ // Read the size of the package
+ // ----------------------------
+ //tcpClient.waitForReadyRead();
+ cout << "JackTrip HUB SERVER: Reading UDP port from Client..." << endl;
+ while (clientConnection->bytesAvailable() < (int)sizeof(uint16_t)) {
+ if (!clientConnection->waitForReadyRead()) {
+ std::cerr << "TCP Socket ERROR: " << clientConnection->errorString().toStdString() << endl;
+ return 0;
+ }
}
- }
- cout << "Ready To Read From Socket!" << endl;
- // Read UDP Port Number from Server
- // --------------------------------
- int udp_port;
- int size = sizeof(udp_port);
- char port_buf[size];
- clientConnection->read(port_buf, size);
- std::memcpy(&udp_port, port_buf, size);
- return udp_port;
+ if (gVerboseFlag) cout << "Ready To Read From Client!" << endl;
+ // Read UDP Port Number from Server
+ // --------------------------------
+ int udp_port;
+ int size = sizeof(udp_port);
+ char port_buf[size];
+ clientConnection->read(port_buf, size);
+ std::memcpy(&udp_port, port_buf, size);
+ return udp_port;
}
//*******************************************************************************
int UdpMasterListener::sendUdpPort(QTcpSocket* clientConnection, int udp_port)
{
- // Send Port Number to Client
- // --------------------------
- char port_buf[sizeof(udp_port)];
- std::memcpy(port_buf, &udp_port, sizeof(udp_port));
- clientConnection->write(port_buf, sizeof(udp_port));
- while ( clientConnection->bytesToWrite() > 0 ) {
- if ( clientConnection->state() == QAbstractSocket::ConnectedState ) {
- clientConnection->waitForBytesWritten(-1);
- }
- else {
- return 0;
+ // Send Port Number to Client
+ // --------------------------
+ char port_buf[sizeof(udp_port)];
+ std::memcpy(port_buf, &udp_port, sizeof(udp_port));
+ clientConnection->write(port_buf, sizeof(udp_port));
+ while ( clientConnection->bytesToWrite() > 0 ) {
+ if ( clientConnection->state() == QAbstractSocket::ConnectedState ) {
+ clientConnection->waitForBytesWritten(-1);
+ }
+ else {
+ return 0;
+ }
}
- }
- return 1;
- cout << "Port sent to Client" << endl;
+ return 1;
+ cout << "Port sent to Client" << endl;
}
//*******************************************************************************
void UdpMasterListener::bindUdpSocket(QUdpSocket& udpsocket, int port) throw(std::runtime_error)
{
- // QHostAddress::Any : let the kernel decide the active address
- if ( !udpsocket.bind(QHostAddress::Any,
- port, QUdpSocket::DefaultForPlatform) ) {
- //std::cerr << "ERROR: could not bind UDP socket" << endl;
- //std::exit(1);
- throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
- }
- else {
- cout << "UDP Socket Receiving in Port: " << port << endl;
- }
+ // QHostAddress::Any : let the kernel decide the active address
+ if ( !udpsocket.bind(QHostAddress::Any,
+ port, QUdpSocket::DefaultForPlatform) ) {
+ //std::cerr << "ERROR: could not bind UDP socket" << endl;
+ //std::exit(1);
+ throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
+ }
+ else {
+ cout << "UDP Socket Receiving in Port: " << port << endl;
+ }
}
//*******************************************************************************
// check by comparing 32-bit addresses
-int UdpMasterListener::isNewAddress(uint32_t address, uint16_t port)
+int UdpMasterListener::isNewAddress(QString address, uint16_t port)
{
- QMutexLocker lock(&mMutex);
- bool busyAddress = false;
- int id = 0;
+ QMutexLocker lock(&mMutex);
+ bool busyAddress = false;
+ int id = 0;
- /*
+ /*
while ( !busyAddress && (id<mThreadPool.activeThreadCount()) )
{
if ( address==mActiveAddress[id][0] && port==mActiveAddress[id][1]) { busyAddress = true; }
id++;
}
*/
- for (int i = 0; i<gMaxThreads; i++) {
- if ( address==mActiveAddress[i][0] && port==mActiveAddress[i][1]) {
- id = i;
- busyAddress = true;
+ for (int i = 0; i<gMaxThreads; i++) {
+ if ( address==mActiveAddress[i].address && port==mActiveAddress[i].port) {
+ id = i;
+ busyAddress = true;
+ }
}
- }
- if ( !busyAddress ) {
- /*
+ if ( !busyAddress ) {
+ /*
mActiveAddress[id][0] = address;
mActiveAddress[id][1] = port;
} else {
*/
- id = 0;
- bool foundEmptyAddress = false;
- while ( !foundEmptyAddress && (id<gMaxThreads) ) {
- if ( (mActiveAddress[id][0] == 0) && (mActiveAddress[id][1] == 0) ) {
- foundEmptyAddress = true;
- mActiveAddress[id][0] = address;
- mActiveAddress[id][1] = port;
- } else {
- id++;
- }
+ id = 0;
+ bool foundEmptyAddress = false;
+ while ( !foundEmptyAddress && (id<gMaxThreads) ) {
+ if ( mActiveAddress[id].address.isEmpty() && (mActiveAddress[id].port == 0) ) {
+ foundEmptyAddress = true;
+ mActiveAddress[id].address = address;
+ mActiveAddress[id].port = port;
+ } else {
+ id++;
+ }
+ }
}
- }
- if (!busyAddress) {
- mTotalRunningThreads++;
- }
- return ((busyAddress) ? -1 : id);
+ if (!busyAddress) {
+ mTotalRunningThreads++;
+ }
+ return ((busyAddress) ? -1 : id);
}
//*******************************************************************************
-int UdpMasterListener::getPoolID(uint32_t address, uint16_t port)
+int UdpMasterListener::getPoolID(QString address, uint16_t port)
{
- QMutexLocker lock(&mMutex);
- //for (int id = 0; id<mThreadPool.activeThreadCount(); id++ )
- for (int id = 0; id<gMaxThreads; id++ )
- {
- if ( address==mActiveAddress[id][0] && port==mActiveAddress[id][1])
- { return id; }
- }
- return -1;
+ QMutexLocker lock(&mMutex);
+ //for (int id = 0; id<mThreadPool.activeThreadCount(); id++ )
+ for (int id = 0; id<gMaxThreads; id++ )
+ {
+ if ( address==mActiveAddress[id].address && port==mActiveAddress[id].port)
+ { return id; }
+ }
+ return -1;
}
//*******************************************************************************
int UdpMasterListener::releaseThread(int id)
-{
- QMutexLocker lock(&mMutex);
- mActiveAddress[id][0] = 0;
- mActiveAddress[id][1] = 0;
- mTotalRunningThreads--;
- return 0; /// \todo Check if we really need to return an argument here
+{
+ QMutexLocker lock(&mMutex);
+ mActiveAddress[id].address = "";
+ mActiveAddress[id].port = 0;
+ mTotalRunningThreads--;
+#ifdef WAIR // wair
+ if (isWAIR()) connectMesh(false); // invoked with -Sw
+#endif // endwhere
+ if (getHubPatch()) connectPatch(false); // invoked with -p > 0
+ return 0; /// \todo Check if we really need to return an argument here
+}
+
+#ifdef WAIR // wair
+#include "JMess.h"
+//*******************************************************************************
+void UdpMasterListener::connectMesh(bool spawn)
+{
+ cout << ((spawn)?"spawning":"releasing") << " jacktripWorker so change mesh" << endl;
+ JMess tmp;
+ tmp.connectSpawnedPorts(gDefaultNumInChannels); // change gDefaultNumInChannels if more than stereo LAIR interconnects
+ // tmp.disconnectAll();
+ // enumerateRunningThreadIDs();
+}
+
+//*******************************************************************************
+void UdpMasterListener::enumerateRunningThreadIDs()
+{
+ for (int id = 0; id<gMaxThreads; id++ )
+ {
+ if ( !mActiveAddress[id].address.isEmpty() )
+ { qDebug() << id; }
+ }
}
+#endif // endwhere
+#include "JMess.h"
+void UdpMasterListener::connectPatch(bool spawn)
+{
+ cout << ((spawn)?"spawning":"releasing") << " jacktripWorker so change patch" << endl;
+ JMess tmp;
+ // default is patch 0, which connects server audio to all clients
+ // these are the other cases:
+ if (getHubPatch() == JackTrip::RESERVEDMATRIX) // special patch for TU Berlin ensemble
+ tmp.connectTUB(gDefaultNumInChannels);
+ else if ((getHubPatch() == JackTrip::CLIENTECHO) || // client loopback for testing
+ (getHubPatch() == JackTrip::CLIENTFOFI) || // all clients to all clients except self
+ (getHubPatch() == JackTrip::FULLMIX)) // all clients to all clients including self
+ tmp.connectSpawnedPorts(gDefaultNumInChannels,getHubPatch());
+ // FIXME: need change to gDefaultNumInChannels if more than stereo
+}
// TODO:
// USE bool QAbstractSocket::isValid () const to check if socket is connect. if not, exit loop
-
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#include <QTcpServer>
#include <QMutex>
+#include "JackTrip.h"
#include "jacktrip_types.h"
#include "jacktrip_globals.h"
class JackTripWorker; // forward declaration
+typedef struct {
+ QString address;
+ int16_t port;
+} addressPortPair;
/** \brief Master UDP listener on the Server.
*
- * This creates a server that will listen on the well know port (the server port) and will
+ * This creates a server that will listen on the well know port (the server port) and will
* spawn JackTrip threads into the Thread pool. Clients request a connection.
*/
class UdpMasterListener : public QThread
{
- Q_OBJECT;
+ Q_OBJECT;
public:
- UdpMasterListener(int server_port = gServerUdpPort);
- virtual ~UdpMasterListener();
-
- /// \brief Implements the Thread Loop. To start the thread, call start()
- /// ( DO NOT CALL run() )
- void run();
+ UdpMasterListener(int server_port = gServerUdpPort);
+ virtual ~UdpMasterListener();
+
+ /// \brief Implements the Thread Loop. To start the thread, call start()
+ /// ( DO NOT CALL run() )
+ void run();
+
+ /// \brief Stops the execution of the Thread
+ void stop() { mStopped = true; }
- /// \brief Stops the execution of the Thread
- void stop() { mStopped = true; }
+ int releaseThread(int id);
- int releaseThread(int id);
+ void setConnectDefaultAudioPorts(bool connectDefaultAudioPorts) { m_connectDefaultAudioPorts = connectDefaultAudioPorts; }
private slots:
- void testReceive()
- { std::cout << "========= TEST RECEIVE SLOT ===========" << std::endl; }
+ void testReceive()
+ { std::cout << "========= TEST RECEIVE SLOT ===========" << std::endl; }
signals:
- void Listening();
- void ClientAddressSet();
- void signalRemoveThread(int id);
+ void Listening();
+ void ClientAddressSet();
+ void signalRemoveThread(int id);
private:
- /** \brief Binds a QUdpSocket. It chooses the available (active) interface.
+ /** \brief Binds a QUdpSocket. It chooses the available (active) interface.
* \param udpsocket a QUdpSocket
* \param port Port number
*/
- static void bindUdpSocket(QUdpSocket& udpsocket, int port) throw(std::runtime_error);
+ static void bindUdpSocket(QUdpSocket& udpsocket, int port) throw(std::runtime_error);
- int readClientUdpPort(QTcpSocket* clientConnection);
- int sendUdpPort(QTcpSocket* clientConnection, int udp_port);
+ int readClientUdpPort(QTcpSocket* clientConnection);
+ int sendUdpPort(QTcpSocket* clientConnection, int udp_port);
- /** \brief Send the JackTripWorker to the thread pool. This will run
+ /** \brief Send the JackTripWorker to the thread pool. This will run
* until it's done. We still have control over the prototype class.
* \param id Identification Number
*/
- //void sendToPoolPrototype(int id);
+ //void sendToPoolPrototype(int id);
- /** \brief Check if address is already handled, if not add to array
- * \param IPv4 address as a number
+ /** \brief Check if address is already handled, if not add to array
+ * \param address as string (IPv4 or IPv6)
* \return -1 if address is busy, id number if not
- */
- int isNewAddress(uint32_t address, uint16_t port);
+ */
+ int isNewAddress(QString address, uint16_t port);
- /** \brief Returns the ID of the client in the pool. If the client
+ /** \brief Returns the ID of the client in the pool. If the client
* is not in the pool yet, returns -1.
*/
- int getPoolID(uint32_t address, uint16_t port);
-
- //QUdpSocket mUdpMasterSocket; ///< The UDP socket
- //QHostAddress mPeerAddress; ///< The Peer Address
-
- //JackTripWorker* mJTWorker; ///< Class that will be used as prototype
- QVector<JackTripWorker*>* mJTWorkers; ///< Vector of JackTripWorker s
- QThreadPool mThreadPool; ///< The Thread Pool
-
- int mServerPort; //< Server known port number
- int mBasePort;
- uint32_t mActiveAddress[gMaxThreads][2]; ///< Active addresses pool numbers (32 bits IPv4 numbers)
- QHash<uint32_t, uint16_t> mActiveAddresPortPair;
-
- /// Boolean stop the execution of the thread
- volatile bool mStopped;
- int mTotalRunningThreads; ///< Number of Threads running in the pool
- QMutex mMutex;
+ int getPoolID(QString address, uint16_t port);
+
+ //QUdpSocket mUdpMasterSocket; ///< The UDP socket
+ //QHostAddress mPeerAddress; ///< The Peer Address
+
+ //JackTripWorker* mJTWorker; ///< Class that will be used as prototype
+ QVector<JackTripWorker*>* mJTWorkers; ///< Vector of JackTripWorker s
+ QThreadPool mThreadPool; ///< The Thread Pool
+
+ int mServerPort; //< Server known port number
+ int mBasePort;
+ addressPortPair mActiveAddress[gMaxThreads]; ///< Active address pool addresses
+ QHash<QString, uint16_t> mActiveAddressPortPair;
+
+ /// Boolean stop the execution of the thread
+ volatile bool mStopped;
+ int mTotalRunningThreads; ///< Number of Threads running in the pool
+ QMutex mMutex;
+ JackTrip::underrunModeT mUnderRunMode;
+ int mBufferQueueLength;
+
+ bool m_connectDefaultAudioPorts;
+
+#ifdef WAIR // wair
+ bool mWAIR;
+ void connectMesh(bool spawn);
+ void enumerateRunningThreadIDs();
+public :
+ void setWAIR(int b) {mWAIR = b;}
+ bool isWAIR() {return mWAIR;}
+#endif // endwhere
+ void connectPatch(bool spawn);
+public :
+ unsigned int mHubPatch;
+ void setHubPatch(unsigned int p) {mHubPatch = p;}
+ unsigned int getHubPatch() {return mHubPatch;}
+
+ void setUnderRunMode(JackTrip::underrunModeT UnderRunMode) { mUnderRunMode = UnderRunMode; }
+ void setBufferQueueLength(int BufferQueueLength) { mBufferQueueLength = BufferQueueLength; }
};
QSPEC=linux-g++
elif [[ $platform == 'macosx' ]]; then
QCMD=qmake
- QSPEC=macx-g++
+ QSPEC=macx-clang
fi
# Build
# Created by Juan-Pablo Caceres
#******************************
+CONFIG += c++11 console
+CONFIG -= app_bundle
+
CONFIG += qt thread debug_and_release build_all
CONFIG(debug, debug|release) {
TARGET = jacktrip_debug
} else {
TARGET = jacktrip
}
+
QT -= gui
QT += network
+
+# rc.1.2 switch enables experimental wair build, merge some of it with WAIRTOMASTER
+# DEFINES += WAIR
+DEFINES += WAIRTOMASTER
+
# http://wiki.qtcentre.org/index.php?title=Undocumented_qmake#Custom_tools
-DEFINES += __RT_AUDIO__
+#cc DEFINES += __RT_AUDIO__
# Configuration without Jack
nojack {
DEFINES += __NO_JACK__
}
+
+# for plugins
+INCLUDEPATH += ../faust-src-lair/stk
+
!win32 {
INCLUDEPATH+=/usr/local/include
+# wair needs stk, can be had from linux this way
+# INCLUDEPATH+=/usr/include/stk
+# LIBS += -L/usr/local/lib -ljack -lstk -lm
LIBS += -L/usr/local/lib -ljack -lm
nojack {
message(Building NONJACK)
}
macx {
- message(MAC OS X)
+ message(Building on MAC OS X)
QMAKE_CXXFLAGS += -D__MACOSX_CORE__ #-D__UNIX_JACK__ #RtAudio Flags
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.9
- QMAKE_MAC_SDK = macosx10.9
+ #QMAKE_MAC_SDK = macosx10.9
CONFIG -= app_bundle
#CONFIG += x86 #ppc #### If you have both libraries installed, you
# can change between 32bits (x86) or 64bits(x86_64) Change this to go back to 32 bits (x86)
LIBS += -framework CoreAudio -framework CoreFoundation
DEFINES += __MAC_OSX__
}
-linux-g++ {
- message(Linux)
- LIBS += -lasound
+
+linux-g++ | linux-g++-64 {
+# LIBS += -lasound -lrtaudio
QMAKE_CXXFLAGS += -D__LINUX_ALSA__ #-D__LINUX_OSS__ #RtAudio Flags
+
+FEDORA = $$system(cat /proc/version | grep -o fc)
+
+contains( FEDORA, fc): {
+ message(building on fedora)
+}
+
+UBUNTU = $$system(cat /proc/version | grep -o Ubuntu)
+
+contains( UBUNTU, Ubuntu): {
+ message(building on Ubuntu)
+
+# workaround for Qt bug under ubuntu 18.04
+# gcc version 7.3.0 (Ubuntu 7.3.0-16ubuntu3)
+# QMake version 3.1
+# Using Qt version 5.9.5 in /usr/lib/x86_64-linux-gnu
+ INCLUDEPATH += /usr/include/x86_64-linux-gnu/c++/7
+
+# sets differences from original fedora version
+ DEFINES += __UBUNTU__
+}
+
QMAKE_CXXFLAGS += -g -O2
DEFINES += __LINUX__
}
+
+linux-g++ {
+ message(Linux)
+ QMAKE_CXXFLAGS += -D__LINUX_ALSA__ #-D__LINUX_OSS__ #RtAudio Flags
+ }
+
linux-g++-64 {
message(Linux 64bit)
- LIBS += -lasound
QMAKE_CXXFLAGS += -fPIC -D__LINUX_ALSA__ #-D__LINUX_OSS__ #RtAudio Flags
- QMAKE_CXXFLAGS += -g -O2
- DEFINES += __LINUX__
}
+
+
win32 {
- message(win32)
- CONFIG += x86 console
- QMAKE_CXXFLAGS += -D__WINDOWS_ASIO__ #-D__UNIX_JACK__ #RtAudio Flags
- LIBS += -lWs2_32 -lOle32 #needed by rtaudio/asio
- LIBS += "../externals/includes/QTWindows/libjack.lib"
+ message(Building on win32)
+#cc CONFIG += x86 console
+ CONFIG += c++11 console
+ INCLUDEPATH += "C:\Program Files (x86)\Jack\includes"
+ LIBS += "C:\Program Files (x86)\Jack\lib\libjack64.lib"
+ LIBS += "C:\Program Files (x86)\Jack\lib\libjackserver64.lib"
+#cc QMAKE_CXXFLAGS += -D__WINDOWS_ASIO__ #-D__UNIX_JACK__ #RtAudio Flags
+ #QMAKE_LFLAGS += -static -static-libgcc -static-libstdc++ -lpthread
+ LIBS += -lWs2_32 #cc -lOle32 #needed by rtaudio/asio
DEFINES += __WIN_32__
- DEFINES -= UNICODE #RtAudio for Qt
+ DEFINES += _WIN32_WINNT=0x0600 #needed for inet_pton
+#cc DEFINES -= UNICODE #RtAudio for Qt
}
-
-
-
DESTDIR = .
QMAKE_CLEAN += -r ./jacktrip ./jacktrip_debug ./release ./debug
target.path = /usr/bin
INSTALLS += target
-#INCLUDEPATH += ../externals/includes/rtaudio-4.0.7
-#DEPENDPATH += ../externals/includes/rtaudio-4.0.7
-win32 {
- INCLUDEPATH += ../externals/includes/rtaudio-4.0.7/include
- INCLUDEPATH += ../externals/includes
- DEPENDPATH += ../externals/includes/rtaudio-4.0.7/include
- DEPENDPATH += ../externals/includes
-}
+# for plugins
+INCLUDEPATH += ../faust-src-lair
# Input
HEADERS += DataProtocol.h \
+ JMess.h \
JackTrip.h \
jacktrip_globals.h \
jacktrip_types.h \
ThreadPoolTest.h \
UdpDataProtocol.h \
UdpMasterListener.h \
- AudioInterface.h \
- RtAudioInterface.h
- #JamTest.h
+ AudioInterface.h
+
!nojack {
-SOURCES += JackAudioInterface.h
+HEADERS += JackAudioInterface.h
}
SOURCES += DataProtocol.cpp \
+ JMess.cpp \
JackTrip.cpp \
jacktrip_globals.cpp \
jacktrip_main.cpp \
ProcessPlugin.cpp \
RingBuffer.cpp \
Settings.cpp \
- #tests.cpp \
UdpDataProtocol.cpp \
UdpMasterListener.cpp \
- AudioInterface.cpp \
- RtAudioInterface.cpp
+ AudioInterface.cpp
+
!nojack {
SOURCES += JackAudioInterface.cpp
}
# RtAduio Input
-HEADERS += ../externals/includes/rtaudio-4.0.7/RtAudio.h \
- ../externals/includes/rtaudio-4.0.7/RtError.h
-SOURCES += ../externals/includes/rtaudio-4.0.7/RtAudio.cpp
win32 {
-HEADERS += asio.h \
- asiodrivers.h \
- asiolist.h \
- asiodrvr.h \
- asiosys.h \
- ginclude.h \
- iasiodrv.h \
- iasiothiscallresolver.h
-SOURCES += asio.cpp \
- asiodrivers.cpp \
- asiolist.cpp \
- iasiothiscallresolver.cpp
+ INCLUDEPATH += ../externals/rtaudio-4.1.1/include
+ DEPENDPATH += ../externals/rtaudio-4.1.1/include
+}
+macx | win32 {
+INCLUDEPATH += ../externals/rtaudio-4.1.1/
+DEPENDPATH += ../externals/rtaudio-4.1.1/
+HEADERS +=
+SOURCES +=
}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*/
#include <iostream>
-#include <cstring>
-#include <cstdio>
-
-#include "jacktrip_globals.h"
-#include "jacktrip_types.h"
#if defined ( __LINUX__ )
-#include <sched.h>
-#include <unistd.h>
-#include <sys/types.h>
+ #include <sched.h>
+ #include <unistd.h>
+ #include <sys/types.h>
#endif //__LINUX__
#if defined ( __MAC_OSX__ )
-#include <mach/mach.h>
-#include <mach/thread_policy.h>
-
-//#include <mach/processor.h>
-
-//#include <mach/clock.h>
-//#include <sys/kernel.h>
-//#include <mach/kern/clock.h>
-
-//#include <Kernel/kern/clock.h>
-//#include <kern/kern_types.h>
-//m#include <kern/kern_types.h>
-//#include <Kernel/kern/clock.h>
-//#include <kern/clock.h>
-
-
-//#include <assert.h>
-//#include <CoreServices/CoreServices.h>
-//#include <mach/mach.h>
-//#include <mach/mach_time.h>
-//#include <unistd.h>
-
+ #include <mach/mach.h>
+ #include <mach/mach_time.h>
+ #include <mach/thread_policy.h>
+#endif //__MAC_OSX__
+#include "jacktrip_globals.h"
-//#include <mach/machine.h>
-//#include <mach/mach_time.h>
-//#include <mach/thread_call.h>
-//#include <mach/processor.h>
-//#include <mach/macro_help.h>
+#if defined ( __MAC_OSX__ )
-#endif //__MAC_OSX__
+// The following function is taken from the chromium source code
+// https://github.com/chromium/chromium/blob/master/base/threading/platform_thread_mac.mm
+// For the following macOS implementation of the function setRealtimeProcessPriority() only: Copyright (c) 2012 The Chromium Authors. All rights reserved.
+
+// Enables time-contraint policy and priority suitable for low-latency,
+// glitch-resistant audio.
+void setRealtimeProcessPriority() {
+ // Increase thread priority to real-time.
+
+ // Please note that the thread_policy_set() calls may fail in
+ // rare cases if the kernel decides the system is under heavy load
+ // and is unable to handle boosting the thread priority.
+ // In these cases we just return early and go on with life.
+
+ mach_port_t mach_thread_id = mach_thread_self();
+
+ // Make thread fixed priority.
+ thread_extended_policy_data_t policy;
+ policy.timeshare = 0; // Set to 1 for a non-fixed thread.
+ kern_return_t result =
+ thread_policy_set(mach_thread_id,
+ THREAD_EXTENDED_POLICY,
+ reinterpret_cast<thread_policy_t>(&policy),
+ THREAD_EXTENDED_POLICY_COUNT);
+ if (result != KERN_SUCCESS) {
+ std::cerr << "Failed to make thread fixed priority. " << result << std::endl;
+ return;
+ }
+ // Set to relatively high priority.
+ thread_precedence_policy_data_t precedence;
+ precedence.importance = 63;
+ result = thread_policy_set(mach_thread_id,
+ THREAD_PRECEDENCE_POLICY,
+ reinterpret_cast<thread_policy_t>(&precedence),
+ THREAD_PRECEDENCE_POLICY_COUNT);
+ if (result != KERN_SUCCESS) {
+ std::cerr << "Failed to set thread priority. " << result << std::endl;
+ return;
+ }
-#if defined ( __MAC_OSX__ )
-//*******************************************************************************
-//http://developer.apple.com/DOCUMENTATION/Darwin/Conceptual/KernelProgramming/scheduler/chapter_8_section_4.html
-//http://lists.apple.com/archives/darwin-dev/2007/Sep/msg00035.html
-int set_realtime(int period, int computation, int constraint)
-{
- //AbsoluteTime time;
- //clock_get_uptime((uint64_t *)&time);
-
- //uint64_t result;
- //clock_get_uptime(&result);
- //clock_get_system_microtime(&result,&result);
-
- struct thread_time_constraint_policy ttcpolicy;
- int ret;
-
- ttcpolicy.period=period; // HZ/160
- ttcpolicy.computation=computation; // HZ/3300;
- ttcpolicy.constraint=constraint; // HZ/2200;
- ttcpolicy.preemptible=1;
-
- if ((ret=thread_policy_set(mach_thread_self(),
- THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&ttcpolicy,
- THREAD_TIME_CONSTRAINT_POLICY_COUNT)) != KERN_SUCCESS) {
- fprintf(stderr, "set_realtime() failed.\n");
- return 0;
- }
- return 1;
+ // Most important, set real-time constraints.
+
+ // Define the guaranteed and max fraction of time for the audio thread.
+ // These "duty cycle" values can range from 0 to 1. A value of 0.5
+ // means the scheduler would give half the time to the thread.
+ // These values have empirically been found to yield good behavior.
+ // Good means that audio performance is high and other threads won't starve.
+ const double kGuaranteedAudioDutyCycle = 0.75;
+ const double kMaxAudioDutyCycle = 0.85;
+
+ // Define constants determining how much time the audio thread can
+ // use in a given time quantum. All times are in milliseconds.
+
+ // About 128 frames @44.1KHz
+ const double kTimeQuantum = 2.9;
+
+ // Time guaranteed each quantum.
+ const double kAudioTimeNeeded = kGuaranteedAudioDutyCycle * kTimeQuantum;
+
+ // Maximum time each quantum.
+ const double kMaxTimeAllowed = kMaxAudioDutyCycle * kTimeQuantum;
+
+ // Get the conversion factor from milliseconds to absolute time
+ // which is what the time-constraints call needs.
+ mach_timebase_info_data_t tb_info;
+ mach_timebase_info(&tb_info);
+ double ms_to_abs_time =
+ (static_cast<double>(tb_info.denom) / tb_info.numer) * 1000000;
+
+ thread_time_constraint_policy_data_t time_constraints;
+ time_constraints.period = kTimeQuantum * ms_to_abs_time;
+ time_constraints.computation = kAudioTimeNeeded * ms_to_abs_time;
+ time_constraints.constraint = kMaxTimeAllowed * ms_to_abs_time;
+ time_constraints.preemptible = 0;
+
+ result = thread_policy_set(mach_thread_id,
+ THREAD_TIME_CONSTRAINT_POLICY,
+ reinterpret_cast<thread_policy_t>(&time_constraints),
+ THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+ if (result != KERN_SUCCESS)
+ std::cerr << "Failed to set thread realtime constraints. " << result << std::endl;
+
+ return;
}
-#endif //__MAC_OSX__
-
-#if defined ( __LINUX__ )
-//*******************************************************************************
-int get_fifo_priority (bool half)
-{
- int min, max, priority;
- min = sched_get_priority_min (SCHED_FIFO);
- max = sched_get_priority_max (SCHED_FIFO);
- if (half) {
- priority = (max - (max - min) / 2); }
- else {
- priority = max; }
-
- //priority=min;
- return priority;
-}
-#endif //__LINUX__
+#endif //__MAC_OSX__
#if defined ( __LINUX__ )
//*******************************************************************************
-int set_fifo_priority (bool half)
+void setRealtimeProcessPriority()
{
- struct sched_param p;
- int priority;
- // scheduling priority
+ int priority = sched_get_priority_max(SCHED_FIFO); // 99 is the highest possible
+#ifdef __UBUNTU__
+ priority = 95; // anything higher is silently ignored by Ubuntu 18.04
+#endif
+ struct sched_param sp = { .sched_priority = priority };
- if (true) // (!getuid () || !geteuid ())
- {
- priority = get_fifo_priority (half);
- p.sched_priority = priority;
-
- if (sched_setscheduler (0, SCHED_FIFO, &p) == -1)
- {
- fprintf (stderr,
- "\ncould not activate scheduling with priority %d\n",
- priority);
- return -1;
- }
- seteuid (getuid ());
- //fprintf (stderr,
- // "\nset scheduling priority to %d (SCHED_FIFO)\n",
- // priority);
- }
- else
- {
- fprintf (stderr,
- "\ninsufficient privileges to set scheduling priority\n");
- priority = 0;
+ if (sched_setscheduler(0, SCHED_FIFO, &sp) == -1) {
+ std::cerr << "Failed to set the scheduler policy and priority." << std::endl;;
}
- return priority;
}
#endif //__LINUX__
-#if defined ( __LINUX__ )
-//*******************************************************************************
-int set_realtime_priority (void)
+#if defined ( __WIN_32__ )
+void setRealtimeProcessPriority()
{
- struct sched_param schp;
-
- memset (&schp, 0, sizeof (schp));
- schp.sched_priority = sched_get_priority_max (SCHED_FIFO);
- if (sched_setscheduler (0, SCHED_FIFO, &schp) != 0)
+ if (SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS) == 0)
{
- perror ("set_scheduler");
- return -1;
+ std::cerr << "Failed to set process priority class." << std::endl;
+ }
+ if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) == 0)
+ {
+ std::cerr << "Failed to set thread priority." << std::endl;
}
- return 0;
-}
-#endif //__LINUX__
-
-
-#if defined ( __WIN_32__ )
-int win_priority()
-{
- if (SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS) == 0)
- {
- printf("set Priority Class failed \n");
- return -1;
- }
- if(SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) == 0)
- {
- printf("set Thread Priority failed \n");
- return -1;
- }
- return GetThreadPriority(GetCurrentThread());
}
#endif //__WIN_32__
-
-
-void set_crossplatform_realtime_priority()
-{
-#if defined ( __LINUX__ )
- set_fifo_priority (false);
-#endif //__LINUX__
-#if defined ( __MAC_OSX__ )
- set_realtime(1250000,60000,90000);
-#endif //__MAC_OSX__
-#if defined __WIN_32__
- win_priority();
-#endif
-
-}
-
-
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
/// \todo Add this namespace
//namespace JackTrip
-const char* const gVersion = "1.1"; ///< JackTrip version
+const char* const gVersion = "1.2beta2"; ///< JackTrip version
//*******************************************************************************
/// \name Default Values
//@{
const int gDefaultNumInChannels = 2;
const int gDefaultNumOutChannels = 2;
+
+#define PROTOCOL_STACK QHostAddress::AnyIPv4 // as opposed to Any
+// #define WAIR_AUDIO_NAME "JackTrip" // for jack connection
+const QString WAIR_AUDIO_NAME = QString("JackTrip"); // keep legacy for WAIR
+const int gMAX_WAIRS = 10; // jmess revision needed for string parse if > 1 digit
+
+// hubpatch = 3 for TUB ensemble patching
+///////////////////////////////
+// test NUC as server
+//const QString gDOMAIN_TRIPLE = QString("130.149.23"); // for TUB multiclient hub
+//const int gMIN_TUB = 245; // lowest client address
+//const int gMAX_TUB = 245; // highest client address
+///////////////////////////////
+// test Riviera as server
+ const QString gDOMAIN_TRIPLE = QString("192.168.0"); // for TUB multiclient hub
+ const int gMIN_TUB = 11; // lowest client address
+ const int gMAX_TUB = 20; // highest client address
+
+#ifdef WAIR // wair
+// uses hub mode
+// hard wire the number of netrev (comb filter) channels
+ #define NUMNETREVCHANSbecauseNOTINRECEIVEDheader 16 // for jacktripworker, jmess
+ const int gDefaultNumNetRevChannels = NUMNETREVCHANSbecauseNOTINRECEIVEDheader;
+ const int gDefaultAddCombFilterLength = 0;
+ const int gDefaultCombFilterFeedback = 0;
+#endif // endwhere
+
//const JackAudioInterface::audioBitResolutionT gDefaultBitResolutionMode =
// JackAudioInterface::BIT16;
const AudioInterface::audioBitResolutionT gDefaultBitResolutionMode =
- AudioInterface::BIT16;
+ AudioInterface::BIT16;
const int gDefaultQueueLength = 4;
const int gDefaultOutputQueueLength = 4;
const uint32_t gDefaultSampleRate = 48000;
+const uint32_t gDefaultDeviceID = 0;
const uint32_t gDefaultBufferSizeInSamples = 128;
const QString gDefaultLocalAddress = QString();
const int gDefaultRedundancy = 1;
//*******************************************************************************
/// \name Global Functions
-void set_crossplatform_realtime_priority();
+void setRealtimeProcessPriority();
-//@{
-// Linux Specific Functions
-#if defined ( __LINUX__ )
-/// \brief Returns fifo priority
-int get_fifo_priority (bool half);
-/// \brief Set fifo priority (if user has sufficient privileges).
-int set_fifo_priority (bool half);
-int set_realtime_priority (void);
-#endif //__LINUX__
-//@}
-
-//@{
-// Mac OS X Specific Functions
-#if defined ( __MAC_OSX__ )
-int set_realtime(int period, int computation, int constraint);
-#endif //__MAC_OSX__
-//@}
-
-//@{
-// Windows Specific Functions
-#if defined ( __WIN_32__ )
-int win_priority();
-#endif //__WIN_32__
-//@}
//*******************************************************************************
/// \name JackTrip Server parameters
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#include <iostream>
#include <QCoreApplication>
+#include <QDebug>
+#include <QLoggingCategory>
#include "JackAudioInterface.h"
#include "UdpDataProtocol.h"
#include "LoopBack.h"
#include "PacketHeader.h"
//#include "JackTripThread.h"
+#ifdef __RT_AUDIO__
#include "RtAudioInterface.h"
+#endif
#include "jacktrip_tests.cpp"
-
#include "jacktrip_globals.h"
-using std::cout; using std::endl;
+void qtMessageHandler(QtMsgType /*type*/, const QMessageLogContext& /*context*/, const QString& msg)
+{
+ std::cerr << msg.toStdString() << std::endl;
+}
+
int main(int argc, char** argv)
{
- QCoreApplication app(argc, argv);
+ QCoreApplication app(argc, argv);
+ QLoggingCategory::setFilterRules(QStringLiteral("*.debug=true"));
+ qInstallMessageHandler(qtMessageHandler);
- bool testing = false;
- if ( argc > 1 ) {
- if ( !strcmp(argv[1], "test") ) {
- testing = true;
+ bool testing = false;
+ if ( argc > 1 ) {
+ if ( !strcmp(argv[1], "test") ) {
+ testing = true;
+ }
}
- }
-
- if ( testing ) {
- cout << "=========TESTING=========" << endl;
- //main_tests(argc, argv); // test functions
- JackTrip jacktrip;
- RtAudioInterface rtaudio(&jacktrip);
- //rtaudio.setup();
- rtaudio.listAllInterfaces();
- //rtaudio.printDeviceInfo(0);
- //while (true) sleep(9999);
- }
- else {
- //---------------------------------------
+ if ( testing ) {
+ std::cout << "=========TESTING=========" << std::endl;
+ //main_tests(argc, argv); // test functions
+ JackTrip jacktrip;
+ //RtAudioInterface rtaudio(&jacktrip);
+ //rtaudio.setup();
+ //rtaudio.listAllInterfaces();
+ //rtaudio.printDeviceInfo(0);
- // Get Settings from user
- // ----------------------
- try
- {
- // Get Settings from user
- // ----------------------
- Settings* settings = new Settings;
- settings->parseInput(argc, argv);
- settings->startJackTrip();
+ //while (true) sleep(9999);
}
- catch ( const std::exception & e )
- {
- std::cerr << "ERROR:" << endl;
- std::cerr << e.what() << endl;
- std::cerr << "Exiting JackTrip..." << endl;
- std::cerr << gPrintSeparator << endl;
- return -1;
+ else {
+ // catch all potential exeptions
+ try
+ {
+ // Get Settings from user
+ // ----------------------
+ Settings* settings = new Settings;
+ settings->parseInput(argc, argv);
+ settings->startJackTrip();
+ }
+ catch ( const std::exception & e )
+ {
+ std::cerr << "ERROR:" << std::endl;
+ std::cerr << e.what() << std::endl;
+ std::cerr << "Exiting JackTrip..." << std::endl;
+ std::cerr << gPrintSeparator << std::endl;
+ return -1;
+ }
}
- }
+ if (gVerboseFlag) std::cout << "step 6" << std::endl;
+ if (gVerboseFlag) std::cout << "jacktrip_main before app.exec()" << std::endl;
- return app.exec();
+ return app.exec();
}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
void main_tests(int /*argc*/, char** argv)
{
- if (argv[1][0] == 's' )
+ if (argv[1][0] == 's' )
{
- test_threads_server();
+ test_threads_server();
}
- else if (argv[1][0] == 'c' )
- {
- test_threads_client("171.64.197.209");
+ else if (argv[1][0] == 'c' )
+ {
+ test_threads_client("171.64.197.209");
}
}
// Test many servers running at the same time
void test_threads_server()
{
- QVector<JackTripThread*> jacktrips;
- jacktrips.resize(num_jacktrips);
- int port_num;
- for (int i = 0; i < num_jacktrips; i++)
+ QVector<JackTripThread*> jacktrips;
+ jacktrips.resize(num_jacktrips);
+ int port_num;
+ for (int i = 0; i < num_jacktrips; i++)
{
- port_num = base_port + i*10;
- cout << "Port Number: " << port_num << endl;
- jacktrips[i] = new JackTripThread(JackTrip::SERVER);
- jacktrips[i]->setPort(port_num);
- jacktrips[i]->start(QThread::NormalPriority);
- //sleep(1);
+ port_num = base_port + i*10;
+ cout << "Port Number: " << port_num << endl;
+ jacktrips[i] = new JackTripThread(JackTrip::SERVER);
+ jacktrips[i]->setPort(port_num);
+ jacktrips[i]->start(QThread::NormalPriority);
+ //sleep(1);
}
}
// Test many servers running at the same time
void test_threads_client(const char* peer_address)
{
- QVector<JackTripThread*> jacktrips;
- jacktrips.resize(num_jacktrips);
- int port_num;
- for (int i = 0; i < num_jacktrips; i++)
+ QVector<JackTripThread*> jacktrips;
+ jacktrips.resize(num_jacktrips);
+ int port_num;
+ for (int i = 0; i < num_jacktrips; i++)
{
- port_num = base_port + i*10;
- cout << "Port Number: " << port_num << endl;
- jacktrips[i] = new JackTripThread(JackTrip::CLIENT);
- jacktrips[i]->setPort(port_num);
- jacktrips[i]->setPeerAddress(peer_address);
- //sleep(1);
- jacktrips[i]->start(QThread::NormalPriority);
- //sleep(1);
+ port_num = base_port + i*10;
+ cout << "Port Number: " << port_num << endl;
+ jacktrips[i] = new JackTripThread(JackTrip::CLIENT);
+ jacktrips[i]->setPort(port_num);
+ jacktrips[i]->setPeerAddress(peer_address);
+ //sleep(1);
+ jacktrips[i]->start(QThread::NormalPriority);
+ //sleep(1);
}
}
Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
SoundWIRE group at CCRMA, Stanford University.
-
+
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
-
+
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND