[SCM] jacktrip/master: Imported Upstream version 1.1~repack
umlaeute at users.alioth.debian.org
umlaeute at users.alioth.debian.org
Sun Jun 28 20:58:41 UTC 2015
The following commit has been merged in the master branch:
commit c666435c5848ef17cabca8bd7f7ad5642171aef8
Author: IOhannes m zmölnig <zmoelnig at umlautQ.umlaeute.mur.at>
Date: Sun Jun 28 21:44:36 2015 +0200
Imported Upstream version 1.1~repack
diff --git a/CHANGESLOG.txt b/CHANGESLOG.txt
index 1849861..446e7e5 100644
--- a/CHANGESLOG.txt
+++ b/CHANGESLOG.txt
@@ -1,4 +1,11 @@
---
+1.1
+- (added) Support for RtAudio. Jacktrip can now be used without Jack
+- (added) DNS Look-up support, now one machine can have a private IP (but still needs to have UDP ports open)
+- (added) New port to Windows XP and Windows Vista (experimental and not tested for a long time, only when using jacktrip as a library)
+- (added) Multiclient Server (experimental and not exposed in the executable)
+
+---
1.0.5
- (added) Compatibility with JamLink boxes (restricted at the moment to 48KHz, 64 buffer size and 1 channel)
- (added) New port structure that allows the communication between a public server and a local client
diff --git a/INSTALL.txt b/INSTALL.txt
index cc95c0f..81f3d67 100644
--- a/INSTALL.txt
+++ b/INSTALL.txt
@@ -1,69 +1,116 @@
-Jacktrip : Build Instructions for Linux and MacOS X
-
-JackTrip: A System for High-Quality Audio Network Performance over the Internet.
-
----
-MacOS X (10.3.9 or higher) Installation:
-
-If you are installing on MacOS X, a universal binary is provided. You just need to have JackOSX installed on your machine
-http://www.jackosx.com/
-
-To install (using Terminal): go to bin/ directory and type:
-
- sudo cp jacktrip /usr/bin/
- (enter your password when prompted)
-
- sudo chmod 755 /usr/bin/jacktrip
- (now you can run jacktrip from any directory using Terminal)
-
-
----
-Dependencies:
-
-You need to have installed the libraries in your system:
-qt4-devel
-jack-audio-connection-kit-devel
-
-If you are using yum (in Fedora 8 or later) you can just install them (as root) with:
- yum install qt4-devel jack-audio-connection-kit-devel
-
-If you want to build on MacOS X, you need JackOSX
-http://www.jackosx.com/
-and Qt 4.5 or higher.
-http://trolltech.com/products/qt/
-
-
----
-Build:
-
-If you're on Mac OS X or Fedora Linux and have all the dependencies installed,
-you can build by simply going to the /src directory and typing the following:
- ./build
-
-
-If the previous script doesn't work on a different Linux flavor, try building
-the Makfiles yourself. You'd need qmake (e.g., on Fedora, this command is called
-qmake-qt4). Then you can build by:
- qmake jacktrip.pro
- make release
-
-
-If you want to install install (using Terminal): on the /src directory type:
-
- sudo cp jacktrip /usr/bin/
- (enter your password when prompted)
-
- sudo chmod 755 /usr/bin/jacktrip
- (now you can run jacktrip from any directory using Terminal)
-
-
----
-Post Configuration
-Detailed instructions at
-http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/
-
-
----
-Using JackTrip
-Detailed instructions at
-http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/
+Jacktrip : Build Instructions for Linux and MacOS X
+
+JackTrip: A System for High-Quality Audio Network Performance over the Internet.
+
+---
+MacOS X (10.9 or higher) Installation:
+
+If you are installing on MacOS X, a binary is provided. You just need to have JackOSX installed on your machine
+http://www.jackosx.com/
+
+To install (using Terminal): go to bin/ directory and type:
+
+ sudo cp jacktrip /usr/bin/
+ (enter your password when prompted)
+
+ sudo chmod 755 /usr/bin/jacktrip
+ (now you can run jacktrip from any directory using Terminal)
+
+
+---
+Dependencies:
+
+You need to have installed the libraries in your system:
+Qt 5.3 or higher
+jack-audio-connection-kit-devel
+
+If you are using yum (in Fedora 8 or later) you can just install them (as root) with:
+ yum install jack-audio-connection-kit-devel
+and install qt from the qt site.
+
+If you want to build on MacOS X, you need JackOSX
+http://www.jackosx.com/
+and Qt 5.3 or higher.
+
+It is also possible to build without jack, see below.
+
+---
+Build:
+
+If you're on Mac OS X or Fedora Linux and have all the dependencies installed,
+you can build by simply going to the /src directory and typing the following:
+ ./build
+
+If you want to build without Jack support (meaning that you won't need jack installed
+to use the app) type the following:
+ ./build nojack
+
+If the previous script doesn't work on a different Linux flavor, try building
+the Makfiles yourself. You'd need qmake (e.g., on Fedora, this command is called
+qmake-qt4). Then you can build by:
+ qmake jacktrip.pro
+ make release
+
+Or without Jack support:
+ qmake -config nojack jacktrip.pro
+ make release
+
+
+If you want to install install (using Terminal): on the /src directory type:
+
+ sudo cp jacktrip /usr/bin/
+ (enter your password when prompted)
+
+ sudo chmod 755 /usr/bin/jacktrip
+ (now you can run jacktrip from any directory using Terminal)
+
+-----------------------------
+WINDOWS (XP and later)
+
+Dependencies:
+
+- ASIO4all audio driver is required even with Audio interfaces that support ASIO: www.asio4all.com
+
+Installation:
+
+Simply Run the setup file Jacktrip-1.1.exe, which will unpack Jacktrip in the directory of your choice,
+the default is Program Files/Jacktrip.
+
+The installer also adds the executable Jacktrip.exe in the System32 directory, so that it can be executed
+from a command prompt from any working directory.
+
+This executable (jacktrip.exe) can be found in the bin directory, along with the Dynamic
+Link Libraries (DLLs) it links to.
+
+
+Building:
+
+The easiest way to build is to download the free Qt Creator IDE from http://qt.nokia.com/products/
+
+Make a copy of the src and externals directories into a new directory of your choice, open the jacktrip.pro
+file in src, and build the project.
+
+You can alternatively download the MinGW (Minimalist GNU for Windows), a Windows port of the GNU
+compiler from http://www.mingw.org/ and use mingw32-make from a command terminal to build the makefile.
+
+Building is not supported with Microsoft Visual Studio Compilers.
+
+Note: compiling with modifications in the .pro file (like adding a new source or header file) requires
+qmake which is only available in the Qt Creator package.
+
+---
+
+BUILD WARNING
+
+Always keep the /src and /externals directories under the same directory.
+
+---
+Post Configuration
+Detailed instructions at
+http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/
+
+
+---
+Using JackTrip
+Detailed instructions at
+http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/
diff --git a/documentation/documentation.cpp b/documentation/documentation.cpp
index 54908c2..4783844 100644
--- a/documentation/documentation.cpp
+++ b/documentation/documentation.cpp
@@ -61,7 +61,7 @@ It is currently being developed and actively tested at CCRMA by the SoundWIRE gr
\section install_sec Installation
Download the latest release:
-<a href="https://sourceforge.net/project/showfiles.php?group_id=236811">Download</a>
+<a href="http://code.google.com/p/jacktrip/">Download</a>
Please read the documentation inside the packet to install.
diff --git a/jacktrip_doxygen b/jacktrip_doxygen
index 61e6740..8682067 100644
--- a/jacktrip_doxygen
+++ b/jacktrip_doxygen
@@ -282,7 +282,7 @@ EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
-EXTRACT_PRIVATE = YES
+EXTRACT_PRIVATE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
diff --git a/src/AudioInterface.cpp b/src/AudioInterface.cpp
new file mode 100644
index 0000000..dfea25f
--- /dev/null
+++ b/src/AudioInterface.cpp
@@ -0,0 +1,397 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ 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
+ 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.
+*/
+//*****************************************************************
+
+/**
+ * \file AudioInterface.cpp
+ * \author Juan-Pablo Caceres
+ * \date July 2009
+ */
+
+#include "AudioInterface.h"
+#include "JackTrip.h"
+#include <iostream>
+#include <cmath>
+
+using std::cout; using std::endl;
+
+//*******************************************************************************
+AudioInterface::AudioInterface(JackTrip* jacktrip,
+ int NumInChans, int NumOutChans,
+ audioBitResolutionT AudioBitResolution) :
+mJackTrip(jacktrip),
+mNumInChans(NumInChans), mNumOutChans(NumOutChans),
+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;
+ }
+}
+
+
+//*******************************************************************************
+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];
+ }
+}
+
+
+//*******************************************************************************
+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);
+ }
+}
+
+
+//*******************************************************************************
+size_t AudioInterface::getSizeInBytesPerChannel() const
+{
+ return (getBufferSizeInSamples() * getAudioBitResolution()/8);
+}
+
+
+//*******************************************************************************
+void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
+ 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**************************
+ ///********************************************************
+ /*
+ 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, );
+
+ ///********************************************************
+ ///********************************************************
+
+}
+
+
+//*******************************************************************************
+// Before sending and reading to Jack, we have to round to the sample resolution
+// that the program is using. Jack uses 32 bits (gJackBitResolution in globals.h)
+// by default
+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 );
+ }
+ }
+}
+
+
+//*******************************************************************************
+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 );
+}
+
+
+//*******************************************************************************
+// 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)
+{
+ 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;
+ 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;
+ 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;
+ case BIT32 :
+ std::memcpy(output, input, 4); // 32bit = 4 bytes
+ break;
+ }
+}
+
+
+//*******************************************************************************
+void AudioInterface::fromBitToSampleConversion
+ (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)
+ {
+ case BIT8 :
+ 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;
+ 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;
+ case BIT32 :
+ 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);
+}
+
+
+//*******************************************************************************
+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;
+}
+
+//*******************************************************************************
+int AudioInterface::getSampleRateFromType(samplingRateT rate_type)
+{
+ int sample_rate = 0;
+ switch (rate_type)
+ {
+ case SR22 :
+ sample_rate = 22050;
+ return sample_rate;
+ break;
+ case SR32 :
+ sample_rate = 32000;
+ return sample_rate;
+ break;
+ case SR44 :
+ sample_rate = 44100;
+ return sample_rate;
+ break;
+ case SR48 :
+ sample_rate = 48000;
+ return sample_rate;
+ break;
+ case SR88 :
+ sample_rate = 88200;
+ return sample_rate;
+ break;
+ case SR96 :
+ sample_rate = 96000;
+ return sample_rate;
+ break;
+ case SR192 :
+ sample_rate = 192000;
+ return sample_rate;
+ break;
+ default:
+ return sample_rate;
+ break;
+ }
+
+ return sample_rate;
+}
+
+
diff --git a/src/AudioInterface.h b/src/AudioInterface.h
new file mode 100644
index 0000000..b35b5cd
--- /dev/null
+++ b/src/AudioInterface.h
@@ -0,0 +1,212 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ 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
+ 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.
+*/
+//*****************************************************************
+
+/**
+ * \file AudioInterface.h
+ * \author Juan-Pablo Caceres
+ * \date July 2009
+ */
+
+#ifndef __AUDIOINTERFACE_H__
+#define __AUDIOINTERFACE_H__
+
+#include "ProcessPlugin.h"
+#include "jacktrip_types.h"
+
+#include <QVarLengthArray>
+#include <QVector>
+//#include "jacktrip_globals.h"
+
+// Forward declarations
+class JackTrip;
+
+//using namespace JackTripNamespace;
+
+
+/** \brief Base Class that provides an interface with audio
+ */
+class AudioInterface
+{
+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
+ * \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
+ *
+ * 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
+ 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
+ * 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
+ * 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
+ * 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
+ *
+ * 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
+ * JackAudioInterface::samplingRateT
+ * \param rate_type JackAudioInterface::samplingRateT enum type
+ * \return Sample Rate in Hz
+ */
+ static int getSampleRateFromType(samplingRateT rate_type);
+ //------------------------------------------------------------------
+
+
+private:
+
+ /// \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);
+
+ 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
+};
+
+#endif // __AUDIOINTERFACE_H__
diff --git a/src/DataProtocol.h b/src/DataProtocol.h
index 9f9d2bc..53f2790 100644
--- a/src/DataProtocol.h
+++ b/src/DataProtocol.h
@@ -38,14 +38,23 @@
#ifndef __DATAPROTOCOL_H__
#define __DATAPROTOCOL_H__
-//#include <sys/socket.h> //basic socket definitions
+#ifdef __WIN_32__
+#include <winsock.h>
+#endif
+
+#ifndef __WIN_32__
#include <netinet/in.h> //sockaddr_in{} and other Internet defns
#include <arpa/inet.h> //inet(3) functions
#include <netdb.h>
-#include <tr1/memory> //for shared_ptr
+//#include <tr1/memory> //for shared_ptr
+#endif
+
+#include <iostream>
#include <QThread>
#include <QHostAddress>
+#include <QMutex>
+#include <QMutexLocker>
class JackTrip; // forward declaration
@@ -82,6 +91,8 @@ class JackTrip; // forward declaration
*/
class DataProtocol : public QThread
{
+ Q_OBJECT;
+
public:
//----------ENUMS------------------------------------------
@@ -123,17 +134,20 @@ public:
virtual void run() = 0;
/// \brief Stops the execution of the Thread
- virtual void stop() { mStopped = true; };
+ virtual void stop() {
+ QMutexLocker lock(&mMutex);
+ mStopped = true;
+ }
/** \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
* \return size_bytes Size in bytes
*/
- size_t getAudioPacketSizeInBites() { return(mAudioPacketSize); };
+ size_t getAudioPacketSizeInBites() { return(mAudioPacketSize); }
/** \brief Set the peer address
* \param peerHostOrIP IPv4 number or host name
@@ -150,12 +164,19 @@ public:
//virtual void getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
// uint16_t& port) = 0;
+
+signals:
+
+ void signalError(const char* error_message);
+ void signalReceivedConnectionFromPeer();
+
+
protected:
/** \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;
@@ -163,6 +184,7 @@ protected:
volatile bool mHasPeerAddress;
/// Boolean that indicates if a packet was received
volatile bool mHasPacketsToReceive;
+ QMutex mMutex;
private:
diff --git a/src/JackAudioInterface.cpp b/src/JackAudioInterface.cpp
index 5ca3ba3..3c8c0ca 100644
--- a/src/JackAudioInterface.cpp
+++ b/src/JackAudioInterface.cpp
@@ -62,47 +62,38 @@ QMutex JackAudioInterface::sJackMutex;
//*******************************************************************************
JackAudioInterface::JackAudioInterface(JackTrip* jacktrip,
- int NumInChans, int NumOutChans,
- audioBitResolutionT AudioBitResolution,
- const char* ClienName) :
- mNumInChans(NumInChans), mNumOutChans(NumOutChans),
- mAudioBitResolution(AudioBitResolution*8), mBitResolutionMode(AudioBitResolution),
- mClient(NULL),
- mClientName(ClienName),
- mJackTrip(jacktrip)
-{
- //setupClient();
- //setProcessCallback();
-}
+ int NumInChans, int NumOutChans,
+ 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)
+{}
//*******************************************************************************
JackAudioInterface::~JackAudioInterface()
-{
- delete[] mInputPacket;
- delete[] mOutputPacket;
-
- for (int i = 0; i < mNumInChans; i++) {
- delete[] mInProcessBuffer[i];
- }
-
- for (int i = 0; i < mNumOutChans; i++) {
- delete[] mOutProcessBuffer[i];
- }
-}
+{}
//*******************************************************************************
void JackAudioInterface::setup()
{
setupClient();
+ AudioInterface::setup();
setProcessCallback();
}
//*******************************************************************************
void JackAudioInterface::setupClient()
-{
+{
const char* client_name = mClientName;
const char* server_name = NULL;
jack_options_t options = JackNoStartServer;
@@ -141,35 +132,12 @@ void JackAudioInterface::setupClient()
// Create input and output channels
createChannels();
- // 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];
-
// Buffer size member
mNumFrames = getBufferSizeInSamples();
// Initialize Buffer array to read and write audio
mInBuffer.resize(mNumInChans);
mOutBuffer.resize(mNumOutChans);
-
- // 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);
- }
}
@@ -208,72 +176,6 @@ uint32_t JackAudioInterface::getSampleRate() const
//*******************************************************************************
-JackAudioInterface::samplingRateT JackAudioInterface::getSampleRateType() const
-{
- uint32_t rate = jack_get_sample_rate(mClient);
-
- if ( rate == 22050 ) {
- return JackAudioInterface::SR22; }
- else if ( rate == 32000 ) {
- return JackAudioInterface::SR32; }
- else if ( rate == 44100 ) {
- return JackAudioInterface::SR44; }
- else if ( rate == 48000 ) {
- return JackAudioInterface::SR48; }
- else if ( rate == 88200 ) {
- return JackAudioInterface::SR88; }
- else if ( rate == 96000 ) {
- return JackAudioInterface::SR96; }
- else if ( rate == 19200 ) {
- return JackAudioInterface::SR192; }
-
- return JackAudioInterface::UNDEF;
-}
-
-
-//*******************************************************************************
-int JackAudioInterface::getSampleRateFromType(samplingRateT rate_type)
-{
- int sample_rate = 0;
- switch (rate_type)
- {
- case SR22 :
- sample_rate = 22050;
- return sample_rate;
- break;
- case SR32 :
- sample_rate = 32000;
- return sample_rate;
- break;
- case SR44 :
- sample_rate = 44100;
- return sample_rate;
- break;
- case SR48 :
- sample_rate = 48000;
- return sample_rate;
- break;
- case SR88 :
- sample_rate = 88200;
- return sample_rate;
- break;
- case SR96 :
- sample_rate = 96000;
- return sample_rate;
- break;
- case SR192 :
- sample_rate = 192000;
- return sample_rate;
- break;
- default:
- return sample_rate;
- break;
- }
-
- return sample_rate;
-}
-
-//*******************************************************************************
uint32_t JackAudioInterface::getBufferSizeInSamples() const
{
return jack_get_buffer_size(mClient);
@@ -281,27 +183,6 @@ uint32_t JackAudioInterface::getBufferSizeInSamples() const
//*******************************************************************************
-int JackAudioInterface::getAudioBitResolution() const
-{
- return mAudioBitResolution;
-}
-
-
-//*******************************************************************************
-int JackAudioInterface::getNumInputChannels() const
-{
- return mNumInChans;
-}
-
-
-//*******************************************************************************
-int JackAudioInterface::getNumOutputChannels() const
-{
- return mNumOutChans;
-}
-
-
-//*******************************************************************************
size_t JackAudioInterface::getSizeInBytesPerChannel() const
{
return (getBufferSizeInSamples() * getAudioBitResolution()/8);
@@ -345,7 +226,8 @@ int JackAudioInterface::startProcess() const
int JackAudioInterface::stopProcess() const
{
QMutexLocker locker(&sJackMutex);
- if ( int code = (jack_client_close(mClient)) )
+ int code = (jack_client_close(mClient));
+ if ( code != 0 )
{
std::cerr << "Cannot disconnect client" << std::endl;
return(code);
@@ -364,87 +246,109 @@ void JackAudioInterface::jackShutdown (void*)
}
+
//*******************************************************************************
-/*
-void JackAudioInterface::setRingBuffers
-(const std::tr1::shared_ptr<RingBuffer> InRingBuffer,
- const std::tr1::shared_ptr<RingBuffer> OutRingBuffer)
+int JackAudioInterface::processCallback(jack_nframes_t nframes)
{
- mInRingBuffer = InRingBuffer;
- mOutRingBuffer = OutRingBuffer;
+ // 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;
}
-*/
//*******************************************************************************
-// Before sending and reading to Jack, we have to round to the sample resolution
-// that the program is using. Jack uses 32 bits (gJackBitResolution in globals.h)
-// by default
-void JackAudioInterface::computeNetworkProcessFromNetwork()
+int JackAudioInterface::wrapperProcessCallback(jack_nframes_t nframes, void *arg)
{
- /// \todo cast *mInBuffer[i] to the bit resolution
- //cout << mNumFrames << endl;
- // Output Process (from NETWORK to JACK)
- // ----------------------------------------------------------------
- // Read Audio buffer from RingBuffer (read from incoming packets)
- //mOutRingBuffer->readSlotNonBlocking( mOutputPacket );
- 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 = mOutBuffer[i]; //sample buffer for channel i
- for (int j = 0; j < mNumFrames; j++) {
- //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
- // Change the bit resolution on each sample
- //cout << tmp_sample[j] << endl;
- fromBitToSampleConversion(&mOutputPacket[(i*mSizeInBytesPerChannel)
- + (j*mBitResolutionMode)],
- &tmp_sample[j],
- mBitResolutionMode);
- }
- }
+ return static_cast<JackAudioInterface*>(arg)->processCallback(nframes);
}
//*******************************************************************************
-void JackAudioInterface::computeNetworkProcessToNetwork()
+void JackAudioInterface::connectDefaultPorts()
{
- // 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 = mInBuffer[i]; //sample buffer for channel i
- sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
- sample_t tmp_result;
- for (int j = 0; j < mNumFrames; j++) {
- //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
- // Change the bit resolution on each sample
+ const char** ports;
- // 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);
+ // 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++)
+ {
+ // 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 << "WARING: 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);
}
- // Send Audio buffer to RingBuffer (these goes out as outgoing packets)
- //mInRingBuffer->insertSlotNonBlocking( mInputPacket );
- mJackTrip->sendNetworkPacket( mInputPacket );
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// OLD CODE
+// ==============================================================================
+
//*******************************************************************************
+/*
int JackAudioInterface::processCallback(jack_nframes_t nframes)
{
// Get input and output buffers from JACK
@@ -495,8 +399,7 @@ int JackAudioInterface::processCallback(jack_nframes_t nframes)
// 3) Finally, send packets to peer
// --------------------------------
computeNetworkProcessToNetwork();
-
-
+*/
///************PROTORYPE FOR CELT**************************
///********************************************************
/*
@@ -508,116 +411,99 @@ int JackAudioInterface::processCallback(jack_nframes_t nframes)
//unsigned char* compressed;
//CELTEncoder* celtEncoder;
//celt_encode_float(celtEncoder, mInBuffer, NULL, compressed, );
-
+
///********************************************************
///********************************************************
+// return 0;
+//}
- return 0;
-}
-
-
//*******************************************************************************
-int JackAudioInterface::wrapperProcessCallback(jack_nframes_t nframes, void *arg)
+/*
+void JackAudioInterface::setRingBuffers
+(const std::tr1::shared_ptr<RingBuffer> InRingBuffer,
+ const std::tr1::shared_ptr<RingBuffer> OutRingBuffer)
{
- return static_cast<JackAudioInterface*>(arg)->processCallback(nframes);
+ mInRingBuffer = InRingBuffer;
+ mOutRingBuffer = OutRingBuffer;
}
+*/
//*******************************************************************************
-// This function quantize from 32 bit to a lower bit resolution
-// 24 bit is not working yet
-void JackAudioInterface::fromSampleToBitConversion(const sample_t* const input,
- int8_t* output,
- const audioBitResolutionT targetBitResolution)
+// Before sending and reading to Jack, we have to round to the sample resolution
+// that the program is using. Jack uses 32 bits (gJackBitResolution in globals.h)
+// by default
+/*
+void JackAudioInterface::computeNetworkProcessFromNetwork()
{
- 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;
- 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;
- 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;
- case BIT32 :
- std::memcpy(output, input, 4); // 32bit = 4 bytes
- break;
+ /// \todo cast *mInBuffer[i] to the bit resolution
+ //cout << mNumFrames << endl;
+ // Output Process (from NETWORK to JACK)
+ // ----------------------------------------------------------------
+ // Read Audio buffer from RingBuffer (read from incoming packets)
+ //mOutRingBuffer->readSlotNonBlocking( mOutputPacket );
+ 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 = mOutBuffer[i]; //sample buffer for channel i
+ for (int j = 0; j < mNumFrames; j++) {
+ //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
+ // Change the bit resolution on each sample
+ //cout << tmp_sample[j] << endl;
+ fromBitToSampleConversion(&mOutputPacket[(i*mSizeInBytesPerChannel)
+ + (j*mBitResolutionMode)],
+ &tmp_sample[j],
+ mBitResolutionMode);
}
+ }
}
-
+*/
//*******************************************************************************
-void JackAudioInterface::fromBitToSampleConversion(const int8_t* const input,
- sample_t* output,
- const audioBitResolutionT sourceBitResolution)
+/*
+void JackAudioInterface::computeNetworkProcessToNetwork()
{
- 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;
- 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;
- 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;
- case BIT32 :
- std::memcpy(output, input, 4); // 4 bytes
- break;
+ // 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 = mInBuffer[i]; //sample buffer for channel i
+ sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
+ sample_t tmp_result;
+ for (int j = 0; j < mNumFrames; j++) {
+ //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
+ // 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 RingBuffer (these goes out as outgoing packets)
+ //mInRingBuffer->insertSlotNonBlocking( mInputPacket );
+ mJackTrip->sendNetworkPacket( mInputPacket );
}
+*/
//*******************************************************************************
+/*
//void JackAudioInterface::appendProcessPlugin(const std::tr1::shared_ptr<ProcessPlugin> plugin)
void JackAudioInterface::appendProcessPlugin(ProcessPlugin* plugin)
{
@@ -625,51 +511,4 @@ void JackAudioInterface::appendProcessPlugin(ProcessPlugin* plugin)
if ( plugin->getNumInputs() ) {}
mProcessPlugins.append(plugin);
}
-
-
-
-//*******************************************************************************
-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++)
- {
- // 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 << "WARING: 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);
- }
-}
+*/
diff --git a/src/JackAudioInterface.h b/src/JackAudioInterface.h
index 2b01ff2..39ddd0c 100644
--- a/src/JackAudioInterface.h
+++ b/src/JackAudioInterface.h
@@ -40,7 +40,7 @@
#define __JACKAUDIOINTERFACE_H__
#include <iostream>
-#include <tr1/memory> //for shared_ptr
+//#include <tr1/memory> //for shared_ptr
#include <functional> //for mem_fun_ref
#include <jack/jack.h>
@@ -51,8 +51,9 @@
#include "jacktrip_types.h"
#include "ProcessPlugin.h"
+#include "AudioInterface.h"
-class JackTrip; //forward declaration
+//class JackTrip; //forward declaration
/** \brief Class that provides an interface with the Jack Audio Server
@@ -60,31 +61,10 @@ class JackTrip; //forward declaration
* \todo implement srate_callback
* \todo automatically starts jack with buffer and sample rate settings specified by the user
*/
-class JackAudioInterface
+class JackAudioInterface : public AudioInterface
{
public:
- /// \brief Enum for Audio Resolution in bits
- /// \todo implement this into the class, now it's using jack default of 32 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
@@ -93,123 +73,47 @@ public:
* \param ClientName Client name in Jack
*/
JackAudioInterface(JackTrip* jacktrip,
- int NumInChans, int NumOutChans,
- audioBitResolutionT AudioBitResolution = BIT16,
- const char* ClientName = "JackTrip");
-
- /** \brief The class destructor
- */
+ int NumInChans, int NumOutChans,
+ AudioInterface::audioBitResolutionT AudioBitResolution = AudioInterface::BIT16,
+ const char* ClientName = "JackTrip");
+ /// \brief The class destructor
virtual ~JackAudioInterface();
- /** \brief Setup the client
- */
- void setup();
-
- /** \brief Get the Jack Server Sampling Rate, in samples/second
- */
- uint32_t getSampleRate() const;
-
- /** \brief Get the Jack Server Sampling Rate Enum Type samplingRateT
- * \return JackAudioInterface::samplingRateT enum type
- */
- samplingRateT getSampleRateType() const;
-
- /** \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);
-
- /** \brief Get the Jack Server Buffer Size, in samples
- */
- uint32_t getBufferSizeInSamples() const;
-
- /** \brief Get the Jack Server Buffer Size, in bytes
- */
- uint32_t getBufferSizeInBytes() const
- {
- return (getBufferSizeInSamples() * getAudioBitResolution()/8);
- }
-
- /** \brief Get the Audio Bit Resolution, in bits
- *
- * This is one of the audioBitResolutionT set in construction
- */
- int getAudioBitResolution() const;
-
- /// \brief Get Number of Input Channels
- int getNumInputChannels() const;
-
- /// \brief Get Number of Output Channels
- int getNumOutputChannels() const;
-
- /// \brief Get size of each audio per channel, in bytes
- size_t getSizeInBytesPerChannel() const;
-
+ /// \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
*/
- int startProcess() const;
-
+ virtual int startProcess() const;
/** \brief Stops the process-callback thread
* \return 0 on success, otherwise a non-zero error code
*/
- int stopProcess() const;
-
- /** \brief Set the pointer to the Input and Output RingBuffer
- * that'll be use to read and write audio
- *
- * These RingBuffer<EM>s</EM> are used to read and write audio samples on
- * each JACK callback.
- * \todo If the RingBuffer is blocked, the callback should stay
- * on the last buffer, as in JackTrip (wavetable synth)
- * \param InRingBuffer RingBuffer to read samples <B>from</B>
- * \param OutRingBuffer RingBuffer to write samples <B>to</B>
- */
- /*
- void setRingBuffers(const std::tr1::shared_ptr<RingBuffer> InRingBuffer,
- const std::tr1::shared_ptr<RingBuffer> OutRingBuffer);
- */
-
- /** \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>
- */
- //void appendProcessPlugin(const std::tr1::shared_ptr<ProcessPlugin> plugin);
- void appendProcessPlugin(ProcessPlugin* plugin);
-
- /** \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 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 audioBitResolutionT sourceBitResolution);
-
+ 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)
- void setClientName(const char* ClientName)
+ 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;
+ //------------------------------------------------------------------
private:
@@ -222,30 +126,16 @@ private:
* - Creates the appropriate number of input and output channels
*/
void setupClient();
-
- /** \brief Creates input and output channels in the Jack client
- */
+ /// \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 Sets the part of the process callback that sends and receive packets
- //void computeNetworkProcess();
-
- /// \brief Compute the process to receive packets to JACK
- void computeNetworkProcessFromNetwork();
-
- /// \brief Compute the process from JACK to send packets
- void computeNetworkProcessToNetwork();
-
/** \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
@@ -257,7 +147,6 @@ private:
* for more details
*/
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>
*
@@ -272,32 +161,21 @@ private:
// 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
- audioBitResolutionT mBitResolutionMode; ///< Bit resolution (audioBitResolutionT) mode
+ //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)
- //jack_port_t** mInPorts; ///< Vector of Input Ports (Channels)
- //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
-
- 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
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
};
diff --git a/src/JackTrip.cpp b/src/JackTrip.cpp
index 6384504..0ae9f39 100644
--- a/src/JackTrip.cpp
+++ b/src/JackTrip.cpp
@@ -39,6 +39,10 @@
#include "UdpDataProtocol.h"
#include "RingBufferWavetable.h"
#include "jacktrip_globals.h"
+#include "JackAudioInterface.h"
+#ifdef __RT_AUDIO__
+#include "RtAudioInterface.h"
+#endif
#include <iostream>
//#include <unistd.h> // for usleep, sleep
@@ -47,10 +51,18 @@
#include <QHostAddress>
#include <QThread>
+#include <QTcpSocket>
using std::cout; using std::endl;
-
+//the following function has to remain outside the Jacktrip class definition
+//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);
+ }
+#endif
//*******************************************************************************
JackTrip::JackTrip(jacktripModeT JacktripMode,
@@ -58,7 +70,7 @@ JackTrip::JackTrip(jacktripModeT JacktripMode,
int NumChans,
int BufferQueueLength,
unsigned int redundancy,
- JackAudioInterface::audioBitResolutionT AudioBitResolution,
+ AudioInterface::audioBitResolutionT AudioBitResolution,
DataProtocol::packetHeaderTypeT PacketHeaderType,
underrunModeT UnderRunMode,
int receiver_bind_port, int sender_bind_port,
@@ -66,14 +78,15 @@ JackTrip::JackTrip(jacktripModeT JacktripMode,
mJackTripMode(JacktripMode),
mDataProtocol(DataProtocolType),
mPacketHeaderType(PacketHeaderType),
+ mAudiointerfaceMode(JackTrip::JACK),
mNumChans(NumChans),
mBufferQueueLength(BufferQueueLength),
- mSampleRate(0),
- mAudioBufferSize(0),
+ mSampleRate(gDefaultSampleRate),
+ mAudioBufferSize(gDefaultBufferSizeInSamples),
mAudioBitResolution(AudioBitResolution),
mDataProtocolSender(NULL),
mDataProtocolReceiver(NULL),
- mJackAudio(NULL),
+ mAudioInterface(NULL),
mPacketHeader(NULL),
mUnderRunMode(UnderRunMode),
mSendRingBuffer(NULL),
@@ -82,17 +95,25 @@ JackTrip::JackTrip(jacktripModeT JacktripMode,
mSenderPeerPort(sender_peer_port),
mSenderBindPort(sender_bind_port),
mReceiverPeerPort(receiver_peer_port),
+ mTcpServerPort(4464),
mRedundancy(redundancy),
- mJackClientName("JackTrip")
-{}
+ mJackClientName("JackTrip"),
+ mConnectionMode(JackTrip::NORMAL),
+ mReceivedConnection(false),
+ mTcpConnectionError(false),
+ mStopped(false)
+{
+ createHeader(mPacketHeaderType);
+}
//*******************************************************************************
JackTrip::~JackTrip()
{
+ wait();
delete mDataProtocolSender;
delete mDataProtocolReceiver;
- delete mJackAudio;
+ delete mAudioInterface;
delete mPacketHeader;
delete mSendRingBuffer;
delete mReceiveRingBuffer;
@@ -100,28 +121,70 @@ JackTrip::~JackTrip()
//*******************************************************************************
-void JackTrip::setupJackAudio()
+void JackTrip::setupAudio()
{
- // Create JackAudioInterface Client Object
- mJackAudio = new JackAudioInterface(this, mNumChans, mNumChans, mAudioBitResolution);
- mJackAudio->setClientName(mJackClientName);
- mJackAudio->setup();
- mSampleRate = mJackAudio->getSampleRate();
+ // 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 ) {
+#ifndef __NO_JACK__
+ mAudioInterface = new JackAudioInterface(this, mNumChans, mNumChans, mAudioBitResolution);
+ mAudioInterface->setClientName(mJackClientName);
+ mAudioInterface->setup();
+ mSampleRate = mAudioInterface->getSampleRate();
+ 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();
+#endif
+#endif
+ }
+ else if ( mAudiointerfaceMode == JackTrip::RTAUDIO ) {
+#ifdef __RT_AUDIO__
+ mAudioInterface = new RtAudioInterface(this, mNumChans, mNumChans, mAudioBitResolution);
+ mAudioInterface->setSampleRate(mSampleRate);
+ mAudioInterface->setBufferSizeInSamples(mAudioBufferSize);
+ mAudioInterface->setup();
+#endif
+ }
+
std::cout << "The Sampling Rate is: " << mSampleRate << std::endl;
std::cout << gPrintSeparator << std::endl;
- mAudioBufferSize = mJackAudio->getBufferSizeInSamples();
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 << " or: " << AudioBufferSizeInBytes
+ << " bytes" << std::endl;
std::cout << gPrintSeparator << std::endl;
- cout << "The Number of Channels is: " << mJackAudio->getNumInputChannels() << endl;
+ cout << "The Number of Channels is: " << mAudioInterface->getNumInputChannels() << endl;
std::cout << gPrintSeparator << std::endl;
QThread::usleep(100);
}
//*******************************************************************************
+void JackTrip::closeAudio()
+{
+ //mAudioInterface->close();
+ if ( mAudioInterface != NULL ) {
+ mAudioInterface->stopProcess();
+ delete mAudioInterface;
+ mAudioInterface = NULL;
+ }
+}
+
+
+//*******************************************************************************
void JackTrip::setupDataProtocol()
{
// Create DataProtocol Objects
@@ -150,10 +213,12 @@ void JackTrip::setupDataProtocol()
}
// Set Audio Packet Size
- mDataProtocolSender->setAudioPacketSize
- (mJackAudio->getSizeInBytesPerChannel() * mNumChans);
- mDataProtocolReceiver->setAudioPacketSize
- (mJackAudio->getSizeInBytesPerChannel() * mNumChans);
+ //mDataProtocolSender->setAudioPacketSize
+ // (mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
+ //mDataProtocolReceiver->setAudioPacketSize
+ // (mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
+ mDataProtocolSender->setAudioPacketSize(getTotalAudioPacketSizeInBytes());
+ mDataProtocolReceiver->setAudioPacketSize(getTotalAudioPacketSizeInBytes());
}
@@ -162,19 +227,34 @@ 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(mJackAudio->getSizeInBytesPerChannel() * mNumChans,
- gDefaultOutputQueueLength);
- mReceiveRingBuffer = new RingBufferWavetable(mJackAudio->getSizeInBytesPerChannel() * mNumChans,
- mBufferQueueLength);
+ 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(mJackAudio->getSizeInBytesPerChannel() * mNumChans,
- gDefaultOutputQueueLength);
- mReceiveRingBuffer = new RingBuffer(mJackAudio->getSizeInBytesPerChannel() * mNumChans,
- mBufferQueueLength);
+ 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");
@@ -194,48 +274,82 @@ void JackTrip::setPeerAddress(const char* PeerHostOrIP)
void JackTrip::appendProcessPlugin(ProcessPlugin* plugin)
{
mProcessPlugins.append(plugin);
- //mJackAudio->appendProcessPlugin(plugin);
+ //mAudioInterface->appendProcessPlugin(plugin);
}
//*******************************************************************************
-void JackTrip::start()
-{
+void JackTrip::startProcess() 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
- setupJackAudio();
+ // ------------------------------
+ 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 :
- clientPingToServerStart();
- break;
- default:
- throw std::invalid_argument("Jacktrip Mode undefined");
- break;
+ {
+ 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;
+ }
+ break;
+ default:
+ throw std::invalid_argument("Jacktrip Mode undefined");
+ break;
+ }
+
// Start Threads
- mJackAudio->startProcess();
+ mAudioInterface->startProcess();
+
for (int i = 0; i < mProcessPlugins.size(); ++i) {
- mJackAudio->appendProcessPlugin(mProcessPlugins[i]);
+ mAudioInterface->appendProcessPlugin(mProcessPlugins[i]);
}
- mJackAudio->connectDefaultPorts();
- mDataProtocolSender->start();
+ mAudioInterface->connectDefaultPorts();
mDataProtocolReceiver->start();
+ QThread::msleep(1);
+ mDataProtocolSender->start();
}
@@ -250,8 +364,9 @@ void JackTrip::stop()
mDataProtocolReceiver->stop();
mDataProtocolReceiver->wait();
- // Stop the jack process callback
- mJackAudio->stopProcess();
+ // Stop the audio processes
+ //mAudioInterface->stopProcess();
+ closeAudio();
cout << "JackTrip Processes STOPPED!" << endl;
cout << gPrintSeparator << endl;
@@ -260,8 +375,9 @@ void JackTrip::stop()
emit signalProcessesStopped();
}
+
//*******************************************************************************
-void JackTrip::wait()
+void JackTrip::waitThreads()
{
mDataProtocolSender->wait();
mDataProtocolReceiver->wait();
@@ -269,14 +385,13 @@ void JackTrip::wait()
//*******************************************************************************
-void JackTrip::clientStart()
+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 {
- // Set the peer address
mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().data() );
cout << "Peer Address set to: " << mPeerAddress.toStdString() << std::endl;
@@ -286,12 +401,15 @@ void JackTrip::clientStart()
//*******************************************************************************
-void JackTrip::serverStart()
+int JackTrip::serverStart(bool timeout, int udpTimeout)
+ 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;
}
// Get the client address when it connects
@@ -304,10 +422,29 @@ void JackTrip::serverStart()
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
- while ( !UdpSockTemp.hasPendingDatagrams() ) { QThread::usleep(100000); }
+ 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 {
+ while ( !UdpSockTemp.hasPendingDatagrams() ) {
+ if (mStopped == true) { emit signalUdpTimeOut(); return -1; }
+ QThread::msleep(sleepTime);
+ }
+ }
char buf[1];
// set client address
UdpSockTemp.readDatagram(buf, 1, &peerHostAddress, &peer_port);
@@ -321,7 +458,7 @@ void JackTrip::serverStart()
// 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
+ // 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.:
@@ -330,40 +467,122 @@ void JackTrip::serverStart()
mDataProtocolSender->setPeerPort(peer_port);
mDataProtocolReceiver->setPeerPort(peer_port);
setPeerPorts(peer_port);
+ return 0;
}
+
//*******************************************************************************
-void JackTrip::clientPingToServerStart()
+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;
+ }
+
+ // 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();
+
+ // 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 << "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;
+ }
+ }
+ 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;
+
+ /*
else {
// Set the peer address
mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
}
- // Start Threads
- mJackAudio->startProcess();
- //mJackAudio->connectDefaultPorts();
+ // Start the Sender Threads
+ // ------------------------
+ mAudioInterface->startProcess();
mDataProtocolSender->start();
- //cout << "STARTED DATA PROTOCOL SENDER-----------------------------" << endl;
- //mDataProtocolReceiver->start();
+ // block until mDataProtocolSender thread starts
+ while ( !mDataProtocolSender->isRunning() ) { QThread::msleep(100); }
+ // Create a Socket to listen to Server's answer
+ // --------------------------------------------
QHostAddress serverHostAddress;
QUdpSocket UdpSockTemp;// Create socket to wait for server answer
uint16_t server_port;
// Bind the socket
+ //bindReceiveSocket(UdpSockTemp, mReceiverBindPort,
+ // mPeerAddress, peer_port);
if ( !UdpSockTemp.bind(QHostAddress::Any,
- mReceiverBindPort,
- QUdpSocket::DefaultForPlatform) ) {
- throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
+ mReceiverBindPort,
+ QUdpSocket::ShareAddress) ) {
+ //throw std::runtime_error("Could not bind PingToServer UDP socket. It may be already binded.");
}
+
// Listen to server response
cout << "Waiting for server response..." << endl;
- while ( !UdpSockTemp.hasPendingDatagrams() ) { QThread::usleep(100000); }
+ while ( !UdpSockTemp.hasPendingDatagrams() ) { QThread::msleep(100); }
cout << "Received response from server!" << endl;
char buf[1];
// set client address
@@ -373,27 +592,80 @@ void JackTrip::clientPingToServerStart()
// Stop the sender thread to change server port
mDataProtocolSender->stop();
mDataProtocolSender->wait(); // Wait for the thread to terminate
- /*
- while ( mDataProtocolSender->isRunning() )
- {
- cout << "IS RUNNING!" << endl;
- QThread::usleep(100000);
- }
- */
- cout << "Server port now set to: " << server_port-1 << endl;
+
+ cout << "Server port now set to: " << server_port << endl;
cout << gPrintSeparator << endl;
- mDataProtocolSender->setPeerPort(server_port-1);
+ mDataProtocolSender->setPeerPort(server_port);
// Start Threads
- //mJackAudio->connectDefaultPorts();
+ //mAudioInterface->connectDefaultPorts();
mDataProtocolSender->start();
mDataProtocolReceiver->start();
+ */
}
//*******************************************************************************
+/*
+void JackTrip::bindReceiveSocket(QUdpSocket& UdpSocket, int bind_port,
+ QHostAddress PeerHostAddress, int peer_port)
+throw(std::runtime_error)
+{
+ // Creat socket descriptor
+ int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ // Set local IPv4 Address
+ struct sockaddr_in local_addr;
+ ::bzero(&local_addr, sizeof(local_addr));
+ 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(bind_port); //set bind port
+
+ // 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));
+#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));
+#endif
+
+ // Bind the Socket
+ 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.
+ // 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(peer_port); //set local port
+ // Connect the socket and issue a Write shutdown (to make it a
+ // reader socket only)
+ if ( (::inet_pton(AF_INET, PeerHostAddress.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"); }
+
+ UdpSocket.setSocketDescriptor(sock_fd, QUdpSocket::ConnectedState,
+ QUdpSocket::ReadOnly);
+ cout << "UDP Socket Receiving in Port: " << bind_port << endl;
+ cout << gPrintSeparator << endl;
+}
+*/
+
+
+//*******************************************************************************
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);
@@ -419,17 +691,20 @@ void JackTrip::putHeaderInPacket(int8_t* full_packet, int8_t* audio_packet)
int8_t* audio_part;
audio_part = full_packet + mPacketHeader->getHeaderSizeInBytes();
- //std::memcpy(audio_part, audio_packet, mJackAudio->getBufferSizeInBytes());
- std::memcpy(audio_part, audio_packet, mJackAudio->getSizeInBytesPerChannel() * mNumChans);
+ //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() const
+int JackTrip::getPacketSizeInBytes()
{
- //return (mJackAudio->getBufferSizeInBytes() + mPacketHeader->getHeaderSizeInBytes());
- return (mJackAudio->getSizeInBytesPerChannel() * mNumChans +
- mPacketHeader->getHeaderSizeInBytes());
+ //return (mAudioInterface->getBufferSizeInBytes() + mPacketHeader->getHeaderSizeInBytes());
+ //return (mAudioInterface->getSizeInBytesPerChannel() * mNumChans +
+ //mPacketHeader->getHeaderSizeInBytes());
+ return (getTotalAudioPacketSizeInBytes() +
+ mPacketHeader->getHeaderSizeInBytes());
}
@@ -438,8 +713,9 @@ 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, mJackAudio->getBufferSizeInBytes());
- std::memcpy(audio_packet, audio_part, mJackAudio->getSizeInBytesPerChannel() * mNumChans);
+ //std::memcpy(audio_packet, audio_part, mAudioInterface->getBufferSizeInBytes());
+ //std::memcpy(audio_packet, audio_part, mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
+ std::memcpy(audio_packet, audio_part, getTotalAudioPacketSizeInBytes());
}
diff --git a/src/JackTrip.h b/src/JackTrip.h
index 69576f2..9084290 100644
--- a/src/JackTrip.h
+++ b/src/JackTrip.h
@@ -38,17 +38,24 @@
#ifndef __JACKTRIP_H__
#define __JACKTRIP_H__
-#include <tr1/memory> //for shared_ptr
+//#include <tr1/memory> //for shared_ptr
+#include <stdexcept>
#include <QObject>
#include <QString>
+#include <QUdpSocket>
#include "DataProtocol.h"
+#include "AudioInterface.h"
+
+#ifndef __NO_JACK__
#include "JackAudioInterface.h"
+#endif //__NO_JACK__
+
#include "PacketHeader.h"
#include "RingBuffer.h"
-
+#include <signal.h>
/** \brief Main class to creates a SERVER (to listen) or a CLIENT (to connect
* to a listening server) to send audio streams in the network.
*
@@ -56,6 +63,7 @@
* This class also acts as a Mediator between all the other class.
* Classes that uses JackTrip methods need to register with it.
*/
+
class JackTrip : public QThread
{
Q_OBJECT;
@@ -74,7 +82,8 @@ public:
enum jacktripModeT {
SERVER, ///< Run in Server Mode
CLIENT, ///< Run in Client Mode
- CLIENTTOPINGSERVER ///< Client of the Ping Server Mode
+ CLIENTTOPINGSERVER, ///< Client of the Ping Server Mode
+ SERVERPINGSERVER ///< Server of the MultiThreaded JackTrip
};
/// \brief Enum for the JackTrip Underrun Mode, when packets
@@ -82,6 +91,19 @@ public:
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
+ };
//---------------------------------------------------------
@@ -95,11 +117,11 @@ public:
*/
JackTrip(jacktripModeT JacktripMode = CLIENT,
dataProtocolT DataProtocolType = UDP,
- int NumChans = 2,
- int BufferQueueLength = 8,
- unsigned int redundancy = 1,
- JackAudioInterface::audioBitResolutionT AudioBitResolution =
- JackAudioInterface::BIT16,
+ int NumChans = gDefaultNumInChannels,
+ int BufferQueueLength = gDefaultQueueLength,
+ unsigned int redundancy = gDefaultRedundancy,
+ AudioInterface::audioBitResolutionT AudioBitResolution =
+ AudioInterface::BIT16,
DataProtocol::packetHeaderTypeT PacketHeaderType =
DataProtocol::DEFAULT,
underrunModeT UnderRunMode = WAVETABLE,
@@ -111,63 +133,62 @@ public:
/// \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
- void setPeerAddress(const char* PeerHostOrIP);
+ 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);
- void appendProcessPlugin(ProcessPlugin* plugin);
+ virtual void appendProcessPlugin(ProcessPlugin* plugin);
/// \brief Start the processing threads
- void start();
+ virtual void startProcess() throw(std::invalid_argument);
/// \brief Stop the processing threads
- void stop();
+ virtual void stop();
/// \brief Wait for all the threads to finish. This functions is used when JackTrip is
/// run as a thread
- void wait();
+ virtual void waitThreads();
/// \brief Check if UDP port is already binded
/// \param port Port number
- void checkIfPortIsBinded(int port);
+ virtual void checkIfPortIsBinded(int port);
//------------------------------------------------------------------------------------
- /// \name Methods to change parameters after construction
+ /// \name Getters and Setters Methods to change parameters after construction
//@{
//
/// \brief Sets (override) JackTrip Mode after construction
- void setJackTripMode(jacktripModeT JacktripMode)
+ virtual void setJackTripMode(jacktripModeT JacktripMode)
{ mJackTripMode = JacktripMode; }
/// \brief Sets (override) DataProtocol Type after construction
- void setDataProtocoType(dataProtocolT DataProtocolType)
+ virtual void setDataProtocoType(dataProtocolT DataProtocolType)
{ mDataProtocol = DataProtocolType; }
/// \brief Sets the Packet header type
- void setPacketHeaderType(DataProtocol::packetHeaderTypeT PacketHeaderType)
+ virtual void setPacketHeaderType(DataProtocol::packetHeaderTypeT PacketHeaderType)
{
mPacketHeaderType = PacketHeaderType;
delete mPacketHeader;
mPacketHeader = NULL;
createHeader(mPacketHeaderType);
}
- /// \brief Sets (override) Number of Channels after construction
- /// \todo implement this, not working right now because channels cannot be changed after construction
- //void setNumChannels(int NumChans)
- //{ mNumChans=NumChans; }
/// \brief Sets (override) Buffer Queue Length Mode after construction
- void setBufferQueueLength(int BufferQueueLength)
+ virtual void setBufferQueueLength(int BufferQueueLength)
{ mBufferQueueLength = BufferQueueLength; }
/// \brief Sets (override) Audio Bit Resolution after construction
- void setAudioBitResolution(JackAudioInterface::audioBitResolutionT AudioBitResolution)
+ virtual void setAudioBitResolution(AudioInterface::audioBitResolutionT AudioBitResolution)
{ mAudioBitResolution = AudioBitResolution; }
/// \brief Sets (override) Underrun Mode
- void setUnderRunMode(underrunModeT UnderRunMode)
+ virtual void setUnderRunMode(underrunModeT UnderRunMode)
{ mUnderRunMode = UnderRunMode; }
/// \brief Sets port numbers for the local and peer machine.
/// Receive port is <tt>port</tt>
- void setAllPorts(int port)
+ virtual void setAllPorts(int port)
{
mReceiverBindPort = port;
mSenderPeerPort = port;
@@ -175,20 +196,84 @@ public:
mReceiverPeerPort = port;
}
/// \brief Sets port numbers to bind in RECEIVER and SENDER sockets.
- void setBindPorts(int port)
+ virtual void setBindPorts(int port)
{
mReceiverBindPort = port;
mSenderBindPort = port;
}
/// \brief Sets port numbers for the peer (remote) machine.
- void setPeerPorts(int port)
+ virtual void setPeerPorts(int port)
{
mSenderPeerPort = port;
mReceiverPeerPort = port;
}
/// \brief Set Client Name to something different that the default (JackTrip)
- void setClientName(char* ClientName)
+ 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; }
//@}
//------------------------------------------------------------------------------------
@@ -197,49 +282,88 @@ public:
/// \name Mediator Functions
//@{
/// \todo Document all these functions
- void createHeader(const DataProtocol::packetHeaderTypeT headertype);
+ virtual void createHeader(const DataProtocol::packetHeaderTypeT headertype);
void putHeaderInPacket(int8_t* full_packet, int8_t* audio_packet);
- int getPacketSizeInBytes() const;
+ virtual int getPacketSizeInBytes();
void parseAudioPacket(int8_t* full_packet, int8_t* audio_packet);
- void sendNetworkPacket(const int8_t* ptrToSlot)
+ virtual void sendNetworkPacket(const int8_t* ptrToSlot)
{ mSendRingBuffer->insertSlotNonBlocking(ptrToSlot); }
- void receiveNetworkPacket(int8_t* ptrToReadSlot)
+ virtual void receiveNetworkPacket(int8_t* ptrToReadSlot)
{ mReceiveRingBuffer->readSlotNonBlocking(ptrToReadSlot); }
- void readAudioBuffer(int8_t* ptrToReadSlot)
+ virtual void readAudioBuffer(int8_t* ptrToReadSlot)
{ mSendRingBuffer->readSlotBlocking(ptrToReadSlot); }
- void writeAudioBuffer(const int8_t* ptrToSlot)
+ virtual void writeAudioBuffer(const int8_t* ptrToSlot)
{ mReceiveRingBuffer->insertSlotNonBlocking(ptrToSlot); }
uint32_t getBufferSizeInSamples() const
- { return mJackAudio->getBufferSizeInSamples(); }
- JackAudioInterface::samplingRateT getSampleRateType() const
- { return mJackAudio->getSampleRateType(); }
+ { 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 mJackAudio->getAudioBitResolution(); }
- int getNumInputChannels() const
- { return mJackAudio->getNumInputChannels(); }
- int getNumOutputChannels() const
- {return mJackAudio->getNumOutputChannels(); }
- void checkPeerSettings(int8_t* full_packet);
+ { 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(); }
- int getPeerSequenceNumber(int8_t* full_packet) const
+
+ 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;}
public slots:
/// \brief Slot to stop all the processes and threads
- void slotStopProcesses()
+ virtual void slotStopProcesses()
{
std::cout << "Stopping JackTrip..." << std::endl;
- stop();
- };
+ mStopped = true;
+ this->stop();
+ }
/** \brief This slot emits in turn the signal signalNoUdpPacketsForSeconds
- * when UDP is waited for more than 30 seconds.
+ * when UDP has waited for more than 30 seconds.
*
* It is used to remove the thread from the server.
*/
@@ -251,46 +375,67 @@ public slots:
emit signalNoUdpPacketsForSeconds();
}
}
-
+ void slotPrintTest()
+ { std::cout << "=== TESTING ===" << std::endl; }
+ void slotReceivedConnectionFromPeer()
+ { mReceivedConnection = true; }
+
signals:
- /// \brieg Signal emitted when all the processes and threads are stopped
+
+ void signalUdpTimeOut();
+ /// \brief Signal emitted when all the processes and threads are stopped
void signalProcessesStopped();
- /// \brieg Signal emitted when no UDP Packets have been received for a while
+ /// \brief Signal emitted when no UDP Packets have been received for a while
void signalNoUdpPacketsForSeconds();
+ void signalTcpClientConnected();
-private:
+public:
- /// \brief Set the JackAudioInteface object
- void setupJackAudio();
+ /// \brief Set the AudioInteface object
+ virtual void setupAudio();
+ /// \brief Close the JackAudioInteface and disconnects it from JACK
+ void closeAudio();
/// \brief Set the DataProtocol objects
- void setupDataProtocol();
+ virtual void setupDataProtocol();
/// \brief Set the RingBuffer objects
void setupRingBuffers();
/// \brief Starts for the CLIENT mode
- void clientStart();
+ void clientStart() throw(std::invalid_argument);
/// \brief Starts for the SERVER mode
- void serverStart();
+ /// \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
- void clientPingToServerStart();
+ /// \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
- JackAudioInterface::audioBitResolutionT mAudioBitResolution; ///< Audio Bit Resolutions
+ 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
+ /// Pointer to Abstract Type DataProtocol that receives packets
DataProtocol* mDataProtocolReceiver;
- JackAudioInterface* mJackAudio; ///< Interface to Jack Client
+ AudioInterface* mAudioInterface; ///< Interface to Jack Client
PacketHeader* mPacketHeader; ///< Pointer to Packet Header
underrunModeT mUnderRunMode; ///< underrunModeT Mode
@@ -303,11 +448,20 @@ private:
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;
};
#endif
+
+
diff --git a/src/JackTripThread.h b/src/JackTripThread.h
index 6825386..06a85c7 100644
--- a/src/JackTripThread.h
+++ b/src/JackTripThread.h
@@ -47,11 +47,11 @@
class JackTripThread : public QThread
{
public:
- JackTripThread(JackTrip::jacktripModeT JacktripMode) : mJackTripMode(JacktripMode) {};
- virtual ~JackTripThread(){};
+ JackTripThread(JackTrip::jacktripModeT JacktripMode) : mJackTripMode(JacktripMode) {}
+ virtual ~JackTripThread(){}
void run();
- void setPort(int port_num) { mPortNum = port_num; } ;
+ void setPort(int port_num) { mPortNum = port_num; }
void setPeerAddress(const char* PeerHostOrIP) { mPeerAddress = PeerHostOrIP; }
private:
diff --git a/src/JackTripWorker.cpp b/src/JackTripWorker.cpp
index e20c4ba..b83b5c7 100644
--- a/src/JackTripWorker.cpp
+++ b/src/JackTripWorker.cpp
@@ -40,12 +40,16 @@
#include <QTimer>
#include <QMutexLocker>
+#include <QWaitCondition>
#include "JackTripWorker.h"
#include "JackTrip.h"
#include "UdpMasterListener.h"
#include "NetKS.h"
#include "LoopBack.h"
+#ifdef __JAMTEST__
+#include "JamTest.h"
+#endif
using std::cout; using std::endl;
@@ -73,8 +77,7 @@ JackTripWorker::JackTripWorker(UdpMasterListener* udpmasterlistener) :
//*******************************************************************************
JackTripWorker::~JackTripWorker()
{
- delete mUdpMasterListener;
-
+ //delete mUdpMasterListener;
}
@@ -89,7 +92,8 @@ void JackTripWorker::setJackTrip(int id, uint32_t client_address,
}
mID = id;
// Set the jacktrip address and ports
- mClientAddress.setAddress(client_address);
+ //mClientAddress.setAddress(client_address);
+ mClientAddress = client_address;
mServerPort = server_port;
mClientPort = client_port;
mNumChans = num_channels;
@@ -99,74 +103,160 @@ void JackTripWorker::setJackTrip(int id, uint32_t client_address,
//*******************************************************************************
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.'
- */
-
+ caught before control returns to Qt Concurrent.'*/
+
+ { QMutexLocker locker(&mMutex); mSpawning = true; }
+
+ 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::CLIENT, JackTrip::UDP, mNumChans, 2);
- jacktrip.setPeerAddress( mClientAddress.toString().toLatin1().data() );
- jacktrip.setBindPorts(mServerPort);
- jacktrip.setPeerPorts(mClientPort-1);
-
- // Connect signals and slots
- // -------------------------
- 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);
-
- // Karplus Strong String
- NetKS netks;
- jacktrip.appendProcessPlugin(&netks);
- // Play the String
- QTimer timer;
- QObject::connect(&timer, SIGNAL(timeout()), &netks, SLOT(exciteString()),
- Qt::QueuedConnection);
- timer.start(300);
-
- // Start Threads and event loop
- jacktrip.start();
-
- { // Thread is already spawning, so release the lock
- QMutexLocker locker(&mMutex);
- mSpawning = false;
- }
-
- event_loop.exec(); // Excecution will block here until exit() the QEventLoop
- //--------------------------------------------------------------------------
-
- // wait for jacktrip to be done before exiting the Worker Thread
- jacktrip.wait();
-
+ {
+ // 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);
+ cout << "---> JackTripWorker: Creating jacktip objects..." << endl;
+#ifndef __JAMTEST__
+ JackTrip jacktrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, mNumChans, 2);
+#endif
+#ifdef __JAMTEST__
+ 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
+ //--------------------------------------------------------------------------
+
+ { QMutexLocker locker(&mMutex); mSpawning = true; }
+
+ // 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;
- }
+ {
+ 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;
+ }
- mUdpMasterListener->releasePort(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;
+
+//*******************************************************************************
+// 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;
+ }
+ }
+ // 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;
}
@@ -176,3 +266,11 @@ bool JackTripWorker::isSpawning()
QMutexLocker locker(&mMutex);
return mSpawning;
}
+
+
+//*******************************************************************************
+void JackTripWorker::stopThread()
+{
+ QMutexLocker locker(&mMutex);
+ emit signalRemoveThread();
+}
diff --git a/src/JackTripWorker.h b/src/JackTripWorker.h
index 8df371e..adf1602 100644
--- a/src/JackTripWorker.h
+++ b/src/JackTripWorker.h
@@ -46,9 +46,9 @@
#include <QHostAddress>
#include <QMutex>
-#include "jacktrip_types.h"
+#include "JackTrip.h"
-class JackTrip; // forward declaration
+//class JackTrip; // forward declaration
class UdpMasterListener; // forward declaration
@@ -70,40 +70,45 @@ class JackTripWorker : public QObject, public QRunnable
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() ).
- */
+ /// \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
- */
+ /// \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
- */
+ /// \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;
+ }
private slots:
void slotTest()
- {
- std::cout << "--- JackTripWorker TEST SLOT ---" << std::endl;
- }
+ { std::cout << "--- JackTripWorker TEST SLOT ---" << std::endl; }
+
+
+signals:
+ void signalRemoveThread();
private:
+ int setJackTripFromClientHeader(JackTrip& jacktrip);
+ JackTrip::connectionModeT getConnectionModeFromHeader();
UdpMasterListener* mUdpMasterListener; ///< Master Listener Socket
- QHostAddress mClientAddress; ///< Client Address
+ //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>
diff --git a/src/LoopBack.cpp b/src/LoopBack.cpp
index f22197b..b8a698e 100644
--- a/src/LoopBack.cpp
+++ b/src/LoopBack.cpp
@@ -40,6 +40,10 @@
#include "jacktrip_types.h"
#include <cstring> // for memcpy
+#include <iostream>
+
+using std::cout; using std::endl;
+//using namespace JackTripNamespace;
//*******************************************************************************
diff --git a/src/NetKS.h b/src/NetKS.h
index 2d09c4b..864be52 100644
--- a/src/NetKS.h
+++ b/src/NetKS.h
@@ -39,7 +39,7 @@
#define __NETKS_H__
#include <iostream>
-#include <unistd.h>
+//#include <unistd.h>
#include <QTimer>
@@ -73,7 +73,7 @@ private slots:
std::cout << "========= EXTICING STRING ===========" << std::endl;
fbutton0 = 1.0;
//std::cout << fbutton0 << std::endl;
- usleep(280000); /// \todo Define this number based on the sampling rate and buffer size
+ QThread::usleep(280000); /// \todo Define this number based on the sampling rate and buffer size
fbutton0 = 0.0;
//std::cout << fbutton0 << std::endl;
}
diff --git a/src/PacketHeader.cpp b/src/PacketHeader.cpp
index 1a37556..41e41dc 100644
--- a/src/PacketHeader.cpp
+++ b/src/PacketHeader.cpp
@@ -46,6 +46,29 @@
using std::cout; using std::endl;
+// below is the gettimeofday definition for windows: this function is not defined in sys/time.h as it is in unix
+// for more info check: http://www.halcode.com/archives/2008/08/26/retrieving-system-time-gettimeofday/
+#if defined __WIN_32__
+#ifdef __cplusplus
+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;
+}
+#else
+/* Must be defined somewhere else */
+int gettimeofday(struct timeval* p, void* tz /* IGNORED */);
+#endif
+#endif
+
+
//#######################################################################
//####################### PacketHeader ##################################
//#######################################################################
@@ -79,23 +102,22 @@ DefaultHeader::DefaultHeader(JackTrip* jacktrip) :
mHeader.BufferSize = 0;
mHeader.SamplingRate = 0;
mHeader.BitResolution = 0;
- mHeader.NumInChannels = 0;
- mHeader.NumOutChannels = 0;
- //mHeader.Dummy = 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.NumInChannels = mJackTrip->getNumInputChannels();
mHeader.BitResolution = mJackTrip->getAudioBitResolution();
- mHeader.NumOutChannels = mJackTrip->getNumOutputChannels();
- //mHeader.SeqNumber = 0;
- mHeader.TimeStamp = PacketHeader::usecTime();
- //cout << mHeader.TimeStamp << endl;
+ mHeader.NumChannels = mJackTrip->getNumChannels();
+ mHeader.ConnectionMode = static_cast<int>(mJackTrip->getConnectionMode());
//printHeader();
}
@@ -120,17 +142,17 @@ void DefaultHeader::checkPeerSettings(int8_t* full_packet)
// Check Sampling Rate
if ( peer_header->SamplingRate != mHeader.SamplingRate )
- {
- std::cerr << "ERROR: Peer Sampling Rate is : " <<
- JackAudioInterface::getSampleRateFromType
- ( static_cast<JackAudioInterface::samplingRateT>(peer_header->SamplingRate) ) << endl;
- std::cerr << " Local Sampling Rate is : " <<
- JackAudioInterface::getSampleRateFromType
- ( static_cast<JackAudioInterface::samplingRateT>(mHeader.SamplingRate) ) << endl;
- std::cerr << "Make sure both machines use the same Sampling Rate" << 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 Audio Bit Resolution
if ( peer_header->BitResolution != mHeader.BitResolution )
@@ -149,7 +171,8 @@ void DefaultHeader::checkPeerSettings(int8_t* full_packet)
{
//std::cerr << "Exiting program..." << endl;
//std::exit(1);
- throw std::logic_error("Local and Peer Settings don't match");
+ //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
}
@@ -160,18 +183,30 @@ 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 JackAudioInterface::samplingRateT
+ // Get the sample rate in Hz form the AudioInterface::samplingRateT
int sample_rate =
- JackAudioInterface::getSampleRateFromType
- ( static_cast<JackAudioInterface::samplingRateT>(mHeader.SamplingRate) );
+ 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 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 << 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;
}
@@ -184,6 +219,49 @@ uint16_t DefaultHeader::getPeerSequenceNumber(int8_t* full_packet) const
}
+//***********************************************************************
+uint16_t DefaultHeader::getPeerBufferSize(int8_t* full_packet) const
+{
+ 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;
+}
+
+
+//***********************************************************************
+uint8_t DefaultHeader::getPeerBitResolution(int8_t* full_packet) const
+{
+ 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;
+}
+
+
+//***********************************************************************
+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);
+}
@@ -212,41 +290,48 @@ void JamLinkHeader::fillHeaderCommonFromAudio()
//std::cerr << "ERROR: JamLink only support ONE channel. Run JackTrip using only one channel"
// << endl;
//std::exit(1);
- throw std::logic_error("JamLink only support ONE channel. Run JackTrip using only one channel");
+ //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 != JackAudioInterface::SR48 ) {
- throw std::logic_error("ERROR: JamLink only support 48kHz for communication with JackTrip at the moment.");
+ 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 )
- {
- throw std::logic_error("ERROR: JamLink only support 64 buffer size for communication with JackTrip at the moment.");
- }
+ 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 JackAudioInterface::SR48 :
+ case AudioInterface::SR48 :
mHeader.Common = (mHeader.Common | ETX_48KHZ);
break;
- case JackAudioInterface::SR44 :
+ case AudioInterface::SR44 :
mHeader.Common = (mHeader.Common | ETX_44KHZ);
break;
- case JackAudioInterface::SR32 :
+ case AudioInterface::SR32 :
mHeader.Common = (mHeader.Common | ETX_32KHZ);
break;
- case JackAudioInterface::SR22 :
+ case AudioInterface::SR22 :
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");
+ //throw std::out_of_range("Sample rate not supported by JamLink");
+ emit signalError("Sample rate not supported by JamLink.");
break;
}
}
diff --git a/src/PacketHeader.h b/src/PacketHeader.h
index 73cf979..3988039 100644
--- a/src/PacketHeader.h
+++ b/src/PacketHeader.h
@@ -39,9 +39,12 @@
#define __PACKETHEADER_H__
#include <iostream>
-#include <tr1/memory> // for shared_ptr
+//#include <tr1/memory> // for shared_ptr
#include <cstring>
+#include <QObject>
+#include <QString>
+
#include "jacktrip_types.h"
#include "jacktrip_globals.h"
class JackTrip; // Forward Declaration
@@ -60,9 +63,10 @@ public:
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 Dummy; ///< Dummy value to byte padding alignment
+ //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;
};
//---------------------------------------------------------
@@ -103,70 +107,67 @@ struct JamLinkHeaderStuct : public HeaderStruct
};
+
//#######################################################################
//####################### PacketHeader ##################################
//#######################################################################
/** \brief Base class for header type. Subclass this struct to
* create a new header.
*/
-class PacketHeader
+class PacketHeader : public QObject
{
+ Q_OBJECT;
+
public:
/// \brief The class Constructor
PacketHeader(JackTrip* jacktrip);
/// \brief The class Destructor
- virtual ~PacketHeader() {};
+ virtual ~PacketHeader() {}
- /** \brief Return a time stamp in microseconds
- * \return Time stamp: microseconds since midnight (0 hour), January 1, 1970
- */
+ /// \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)
- */
+ /// \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
- */
+ /// \brief Increase sequence number for counter, a 16bit number
virtual void increaseSequenceNumber()
- {
- mSeqNumber++;
- };
-
- /* \brief Returns the current sequence number
- * \return 16bit Sequence number
- */
+ { 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
- */
+ { 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)
- */
+ }
+ /// \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);
+
+
private:
uint16_t mSeqNumber;
JackTrip* mJackTrip; ///< JackTrip mediator class
@@ -183,48 +184,37 @@ private:
class DefaultHeader : public PacketHeader
{
public:
- /*
- //----------STRUCT-----------------------------------------
- /// \brief Default Header Struct
- struct DefaultHeaderStruct
- {
- // 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 NumInChannels; ///< Number of Input Channels
- uint8_t NumOutChannels; ///< Number of Output Channels
- // uint8_t BitResolution; ///< \todo implement this part
- };
- //---------------------------------------------------------
- */
+
DefaultHeader(JackTrip* jacktrip);
- virtual ~DefaultHeader() {};
+ virtual ~DefaultHeader() {}
+
virtual void fillHeaderCommonFromAudio();
- virtual void parseHeader() {};
+ virtual void parseHeader() {}
virtual void checkPeerSettings(int8_t* full_packet);
virtual void increaseSequenceNumber()
- {
- mHeader.SeqNumber++;
- //std::cout << "Sequence Number = " << static_cast<int>(mHeader.SeqNumber) << std::endl;
- };
+ { mHeader.SeqNumber++; }
virtual uint16_t getSequenceNumber() const
- {
- return mHeader.SeqNumber;
- }
- virtual uint16_t getPeerSequenceNumber(int8_t* full_packet) const;
- virtual int getHeaderSizeInBytes() const { return sizeof(mHeader); };
+ { return mHeader.SeqNumber; }
+ virtual int getHeaderSizeInBytes() const { return sizeof(mHeader); }
virtual void putHeaderInPacket(int8_t* full_packet)
- {
- putHeaderInPacketBaseClass(full_packet, mHeader);
- //std::memcpy(full_packet, reinterpret_cast<const void*>(&mHeader),
- // getHeaderSizeInBytes() );
- };
+ { 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; ///< Header Struct
DefaultHeaderStruct mHeader;///< Default Header Struct
JackTrip* mJackTrip; ///< JackTrip mediator class
};
@@ -243,18 +233,24 @@ class JamLinkHeader : public PacketHeader
public:
JamLinkHeader(JackTrip* jacktrip);
- virtual ~JamLinkHeader() {};
+ virtual ~JamLinkHeader() {}
virtual void fillHeaderCommonFromAudio();
- virtual void parseHeader() {};
+ virtual void parseHeader() {}
virtual void checkPeerSettings(int8_t* /*full_packet*/) {}
- virtual uint16_t getPeerSequenceNumber(int8_t* /*full_packet*/) const { /*\todo IMPLEMENT*/ return 0; }
- virtual void increaseSequenceNumber() {};
- virtual int getHeaderSizeInBytes() const { return sizeof(mHeader); };
+
+ 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);
- };
+ { putHeaderInPacketBaseClass(full_packet, mHeader); }
private:
JamLinkHeaderStuct mHeader; ///< JamLink Header Struct
@@ -274,15 +270,23 @@ class EmptyHeader : public PacketHeader
public:
EmptyHeader(JackTrip* jacktrip);
- virtual ~EmptyHeader() {};
+ virtual ~EmptyHeader() {}
- virtual void fillHeaderCommonFromAudio() {};
- virtual void parseHeader() {};
+ virtual void fillHeaderCommonFromAudio() {}
+ virtual void parseHeader() {}
virtual void checkPeerSettings(int8_t* /*full_packet*/) {}
- virtual uint16_t getPeerSequenceNumber(int8_t* /*full_packet*/) const { return 0; /*\todo IMPLEMENT*/}
- virtual void increaseSequenceNumber() {};
- virtual int getHeaderSizeInBytes() const { return 0; };
- virtual void putHeaderInPacket(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
diff --git a/src/ProcessPlugin.h b/src/ProcessPlugin.h
index 70533c8..4c0cae8 100644
--- a/src/ProcessPlugin.h
+++ b/src/ProcessPlugin.h
@@ -39,7 +39,7 @@
#define __PROCESSPLUGIN_H__
#include <jack/jack.h>
-#include <QObject>
+#include <QThread>
/** \brief Interface for the process plugins to add to the JACK callback process in
* JackAudioInterface
@@ -49,7 +49,7 @@
* except init, which is optional for processing that are sampling rate dependent or
* that need specific initialization.
*/
-class ProcessPlugin : public QObject
+class ProcessPlugin : public QThread
{
public:
diff --git a/src/RingBuffer.h b/src/RingBuffer.h
index e3cf986..9a5cab6 100644
--- a/src/RingBuffer.h
+++ b/src/RingBuffer.h
@@ -44,6 +44,8 @@
#include "jacktrip_types.h"
+//using namespace JackTripNamespace;
+
/** \brief Provides a ring-buffer (or circular-buffer) that can be written to and read from
* asynchronously (blocking) or synchronously (non-blocking).
diff --git a/src/RtAudioInterface.cpp b/src/RtAudioInterface.cpp
new file mode 100644
index 0000000..3add762
--- /dev/null
+++ b/src/RtAudioInterface.cpp
@@ -0,0 +1,452 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ 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
+ 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.
+*/
+//*****************************************************************
+
+/**
+ * \file RtAudioInterface.cpp
+ * \author Juan-Pablo Caceres
+ * \date July 2009
+ */
+
+#include "RtAudioInterface.h"
+#include "JackTrip.h"
+#include "jacktrip_globals.h"
+
+#include <cstdlib>
+
+
+using std::cout; using std::endl;
+
+
+//*******************************************************************************
+RtAudioInterface::RtAudioInterface(JackTrip* jacktrip,
+ int NumInChans, int NumOutChans,
+ audioBitResolutionT AudioBitResolution) :
+AudioInterface(jacktrip,
+ NumInChans, NumOutChans,
+ AudioBitResolution),
+mJackTrip(jacktrip),
+mRtAudio(NULL)
+{}
+
+
+//*******************************************************************************
+RtAudioInterface::~RtAudioInterface()
+{
+ 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);
+ }
+
+ // 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;
+#ifdef __WIN_32__
+ 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 );
+ }
+
+ // 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;
+ }
+ }
+}
+
+
+//*******************************************************************************
+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; }
+}
+
+
+//*******************************************************************************
+int RtAudioInterface::RtAudioCallback(void *outputBuffer, void *inputBuffer,
+ 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);
+ }
+
+ AudioInterface::callback(mInBuffer, mOutBuffer, nFrames);
+ return 0;
+}
+
+
+//*******************************************************************************
+int RtAudioInterface::wrapperRtAudioCallback(void *outputBuffer, void *inputBuffer,
+ unsigned int nFrames, double streamTime,
+ RtAudioStreamStatus status, void *userData)
+{
+ 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);
+}
+
+
+//*******************************************************************************
+int RtAudioInterface::stopProcess() const
+{
+ try { mRtAudio->closeStream(); }
+ catch ( RtError& e ) {
+ std::cout << '\n' << e.getMessage() << '\n' << std::endl;
+ return(-1);
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// OLD CODE
+// =============================================================================
+
+/*
+int RtAudioInterface::processCallback(jack_nframes_t nframes)
+{
+ mJackTrip->printTextTest();
+ return JackAudioInterface::processCallback(nframes);
+}
+*/
+
+
+//*******************************************************************************
+//int RtAudioInterface::RtAudioCallback(void *outputBuffer, void *inputBuffer,
+// unsigned int nFrames,
+// double /*streamTime*/, RtAudioStreamStatus /*status*/)
+//{
+/*
+ mInBuffer[0] = (sample_t*) inputBuffer;
+ mOutBuffer[0] = (sample_t*) outputBuffer;
+ //AudioInterface::callback(mInBuffer, mOutBuffer, mInputPacket, mOutputPacket,
+ // nFrames, mInProcessBuffer, mOutProcessBuffer);
+
+
+ // Output Process (from NETWORK to JACK)
+ // ----------------------------------------------------------------
+ // Read Audio buffer from RingBuffer (read from incoming packets)
+ //mOutRingBuffer->readSlotNonBlocking( mOutputPacket );
+ mJackTrip->receiveNetworkPacket( mOutputPacket );
+
+
+ // Extract separate channels to send to Jack
+ for (int i = 0; i < getNumOutputChannels(); i++) {
+ //--------
+ // This should be faster for 32 bits
+ //std::memcpy(mOutBuffer[i], &mOutputPacket[i*mSizeInBytesPerChannel],
+ // mSizeInBytesPerChannel);
+ //--------
+ sample_t* tmp_sample = mOutBuffer[i]; //sample buffer for channel i
+ for (unsigned int j = 0; j < nFrames; j++) {
+ //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
+ // Change the bit resolution on each sample
+ //cout << tmp_sample[j] << endl;
+ AudioInterface::fromBitToSampleConversion(&mOutputPacket[(i*getSizeInBytesPerChannel())
+ + (j*BIT16)],
+ &tmp_sample[j],
+ BIT16);
+ }
+ }
+
+
+
+ // Input Process (from JACK to NETWORK)
+ // ----------------------------------------------------------------
+ // Concatenate all the channels from jack to form packet
+ for (int i = 0; i < getNumInputChannels(); i++) {
+ //--------
+ // This should be faster for 32 bits
+ //std::memcpy(&mInputPacket[i*getSizeInBytesPerChannel()], mInBuffer[i],
+ // mSizeInBytesPerChannel);
+ //--------
+ sample_t* tmp_sample = mInBuffer[i]; //sample buffer for channel i
+ sample_t tmp_result;
+ for (unsigned int j = 0; j < nFrames; j++) {
+ // Add the input jack buffer to the buffer resulting from the output process
+ tmp_result = tmp_sample[j];
+ AudioInterface::fromSampleToBitConversion(&tmp_result,
+ &mInputPacket[(i*getSizeInBytesPerChannel())
+ + (j*BIT16)],
+ BIT16);
+ }
+ }
+ // Send Audio buffer to RingBuffer (these goes out as outgoing packets)
+ //mInRingBuffer->insertSlotNonBlocking( mInputPacket );
+ mJackTrip->sendNetworkPacket( mInputPacket );
+
+*/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ //mTestJackTrip->printTextTest();
+
+ //if (mJackTrip != NULL)
+ // cout << "(mJackTrip != NULL)" << endl;
+
+
+ //if (mJackTrip == NULL) { cout << " === JACKTRIPNULL === " << endl; }
+
+ //const int8_t* caca;
+ //mJackTrip->sendNetworkPacket( mInputPacket );
+
+ //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);
+
+
+ //cout << "nFrames = ==================== = = = = = = = ======== " << this->getBufferSizeInSamples() << endl;
+ //int8_t* input_packet = new int8_t[nFrames*2];
+
+ //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;
+
+
+ //mOutputPacket = static_cast<int8_t*>(inputBuffer);
+ //mInputPacket = static_cast<int8_t*>(outputBuffer);
+
+ // 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++) {
+ sample_t* tmp_sample = mOutBuffer[i]; //sample buffer for channel i
+ for (int j = 0; j < mBufferSize; j++) {
+ fromBitToSampleConversion(&mOutputPacket[(i*getSizeInBytesPerChannel()) + (j*BIT16)],
+ &tmp_sample[j],
+ BIT16);
+ }
+ }
+ */
+
+
+ // 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
+ //std::memcpy(&mInputPacket[i*mSizeInBytesPerChannel], mInBuffer[i],
+ // mSizeInBytesPerChannel);
+ //--------
+ float* tmp_sample = in_buffer; //sample buffer for channel i
+ //sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
+ sample_t tmp_result;
+ for (int j = 0; j < mBufferSize; j++) {
+ //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
+ // 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_sample,
+ &mInputPacket[(i*getSizeInBytesPerChannel())
+ + (j*BIT16)],
+ BIT16);
+
+
+
+ }
+ }
+ // Send Audio buffer to RingBuffer (these goes out as outgoing packets)
+ //mInRingBuffer->insertSlotNonBlocking( mInputPacket );
+ mJackTrip->sendNetworkPacket( mInputPacket );
+ */
+ //return 0;
+//}
+
diff --git a/src/RtAudioInterface.h b/src/RtAudioInterface.h
new file mode 100644
index 0000000..a176e78
--- /dev/null
+++ b/src/RtAudioInterface.h
@@ -0,0 +1,97 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ 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
+ 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.
+*/
+//*****************************************************************
+
+/**
+ * \file RtAudioInterface.h
+ * \author Juan-Pablo Caceres
+ * \date July 2009
+ */
+
+#ifndef __RTAUDIOINTERFACE_H__
+#define __RTAUDIOINTERFACE_H__
+
+#include "RtAudio.h"
+
+#include "AudioInterface.h"
+#include "jacktrip_globals.h"
+class JackTrip; // Forward declaration
+
+/// \brief Base Class that provides an interface with RtAudio
+class RtAudioInterface : public AudioInterface
+{
+public:
+
+ /** \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---------------------------------------------
+ //------------------------------------------------------------------
+
+
+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
+};
+
+#endif // __RTAUDIOINTERFACE_H__
diff --git a/src/Settings.cpp b/src/Settings.cpp
index 5b764da..21d9601 100644
--- a/src/Settings.cpp
+++ b/src/Settings.cpp
@@ -55,220 +55,275 @@ int gVerboseFlag = 0;
//*******************************************************************************
Settings::Settings() :
- mJackTrip(NULL),
- mJackTripMode(JackTrip::SERVER),
- mDataProtocol(JackTrip::UDP),
- mNumChans(2),
- mBufferQueueLength(gDefaultQueueLength),
- mAudioBitResolution(JackAudioInterface::BIT16),
- mPortNum(gDefaultPort),
- mClientName(NULL),
- mUnderrrunZero(false),
- mLoopBack(false),
- mJamLink(false),
- mEmptyHeader(false),
- mJackTripServer(false),
- mRedundancy(1)
+ mJackTrip(NULL),
+ mJackTripMode(JackTrip::SERVER),
+ mDataProtocol(JackTrip::UDP),
+ mNumChans(2),
+ mBufferQueueLength(gDefaultQueueLength),
+ mAudioBitResolution(AudioInterface::BIT16),
+ mBindPortNum(gDefaultPort), mPeerPortNum(gDefaultPort),
+ mClientName(NULL),
+ mUnderrrunZero(false),
+ mLoopBack(false),
+ mJamLink(false),
+ mEmptyHeader(false),
+ mJackTripServer(false),
+ mLocalAddress(gDefaultLocalAddress),
+ mRedundancy(1),
+ mUseJack(true),
+ mChanfeDefaultSR(false),
+ mChanfeDefaultBS(false)
{}
//*******************************************************************************
Settings::~Settings()
{
- stopJackTrip();
- delete mJackTrip;
+ stopJackTrip();
+ delete mJackTrip;
}
//*******************************************************************************
void Settings::parseInput(int argc, char** argv)
{
- // If no command arguments are given, print instructions
- if(argc == 1) {
- printUsage();
- std::exit(0);
- }
-
- // Usage example at:
- // http://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Option-Example.html#Getopt-Long-Option-Example
- // 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
- { "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
- { "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
- { "version", no_argument, NULL, 'v' }, // Version Number
- { "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:q:r:b:zljeJ:vh", longopts, NULL)) != -1 )
- switch (ch) {
-
- case 'n': // Number of input and output channels
- //-------------------------------------------------------
- mNumChans = atoi(optarg);
- break;
- case 's': // Run in server mode
- //-------------------------------------------------------
- mJackTripMode = JackTrip::SERVER;
- break;
- case 'S': // Run in jacktripserver mode
- //-------------------------------------------------------
- mJackTripServer = true;
- break;
- case 'c': // Client mode
- //-------------------------------------------------------
- mJackTripMode = JackTrip::CLIENT;
- mPeerAddress = optarg;
- break;
- case 'C': // Ping to server
- //-------------------------------------------------------
- mJackTripMode = JackTrip::CLIENTTOPINGSERVER;
- mPeerAddress = optarg;
- break;
- case 'o': // Port Offset
- //-------------------------------------------------------
- mPortNum += atoi(optarg);
- break;
- case 'b':
- //-------------------------------------------------------
- if ( atoi(optarg) == 8 ) {
- mAudioBitResolution = JackAudioInterface::BIT8; }
- else if ( atoi(optarg) == 16 ) {
- mAudioBitResolution = JackAudioInterface::BIT16; }
- else if ( atoi(optarg) == 24 ) {
- mAudioBitResolution = JackAudioInterface::BIT24; }
- else if ( atoi(optarg) == 32 ) {
- mAudioBitResolution = JackAudioInterface::BIT32; }
- else {
- std::cerr << "--bitres ERROR: Wrong bit resolutions: "
- << atoi(optarg) << " is not supported." << endl;
- printUsage();
- std::exit(1); }
- break;
- case 'q':
- //-------------------------------------------------------
- if ( atoi(optarg) <= 0 ) {
- std::cerr << "--queue ERROR: The queue has to be a positive integer" << endl;
- printUsage();
- std::exit(1); }
- else {
- mBufferQueueLength = atoi(optarg);
- }
- break;
- case 'r':
- //-------------------------------------------------------
- if ( atoi(optarg) <= 0 ) {
- std::cerr << "--queue ERROR: The queue has to be a positive integer" << endl;
- printUsage();
- std::exit(1); }
- else {
- mRedundancy = atoi(optarg);
- }
- break;
- case 'z': // underrun to zero
- //-------------------------------------------------------
- mUnderrrunZero = true;
- break;
- case 'l': // loopback
- //-------------------------------------------------------
- mLoopBack = true;
- break;
- case 'e': // jamlink
- //-------------------------------------------------------
- mEmptyHeader = true;
- break;
- case 'j': // jamlink
- //-------------------------------------------------------
- mJamLink = true;
- break;
- case 'J':
- //-------------------------------------------------------
- mClientName = optarg;
- break;
- case 'v':
- //-------------------------------------------------------
- cout << "JackTrip VERSION: " << gVersion << endl;
- cout << "Copyright (c) 2008-2009 Juan-Pablo Caceres, Chris Chafe." << endl;
- cout << "SoundWIRE group at CCRMA, Stanford University" << endl;
- cout << "" << endl;
- std::exit(0);
- break;
- case 'h':
- //-------------------------------------------------------
- printUsage();
- std::exit(0);
- break;
- default:
- //-------------------------------------------------------
- printUsage();
- std::exit(0);
- break;
+ // If no command arguments are given, print instructions
+ if(argc == 1) {
+ printUsage();
+ std::exit(0);
}
- // Warn user if undefined options where entered
- //----------------------------------------------------------------------------
- if (optind < argc) {
- cout << gPrintSeparator << endl;
- cout << "WARINING: The following entered options have no effect" << endl;
- cout << " They will be ignored!" << endl;
- cout << " Type jacktrip to see options." << endl;
- for( ; optind < argc; optind++) {
- printf("argument: %s\n", argv[optind]);
+ // Usage example at:
+ // http://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Option-Example.html#Getopt-Long-Option-Example
+ // 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 }
+ };
+
+ // 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 )
+ switch (ch) {
+
+ case 'n': // Number of input and output channels
+ //-------------------------------------------------------
+ mNumChans = atoi(optarg);
+ break;
+ case 's': // Run in server mode
+ //-------------------------------------------------------
+ mJackTripMode = JackTrip::SERVER;
+ break;
+ case 'S': // Run in jacktripserver mode
+ //-------------------------------------------------------
+ mJackTripServer = true;
+ break;
+ case 'c': // Client mode
+ //-------------------------------------------------------
+ mJackTripMode = JackTrip::CLIENT;
+ mPeerAddress = optarg;
+ break;
+ case 'L': // set optional local host address
+ //-------------------------------------------------------
+ mLocalAddress = optarg;
+ break;
+ case 'C': // Ping to server
+ //-------------------------------------------------------
+ mJackTripMode = JackTrip::CLIENTTOPINGSERVER;
+ mPeerAddress = optarg;
+ break;
+ case 'o': // Port Offset
+ //-------------------------------------------------------
+ mBindPortNum += atoi(optarg);
+ mPeerPortNum += atoi(optarg);
+ break;
+ case 'B': // Bind Port
+ //-------------------------------------------------------
+ mBindPortNum = atoi(optarg);
+ break;
+ case 'P': // Peer Port
+ //-------------------------------------------------------
+ mPeerPortNum = atoi(optarg);
+ break;
+ case 'b':
+ //-------------------------------------------------------
+ if ( atoi(optarg) == 8 ) {
+ mAudioBitResolution = AudioInterface::BIT8; }
+ else if ( atoi(optarg) == 16 ) {
+ mAudioBitResolution = AudioInterface::BIT16; }
+ else if ( atoi(optarg) == 24 ) {
+ mAudioBitResolution = AudioInterface::BIT24; }
+ else if ( atoi(optarg) == 32 ) {
+ mAudioBitResolution = AudioInterface::BIT32; }
+ else {
+ std::cerr << "--bitres ERROR: Wrong bit resolutions: "
+ << atoi(optarg) << " is not supported." << endl;
+ printUsage();
+ std::exit(1); }
+ break;
+ case 'q':
+ //-------------------------------------------------------
+ if ( atoi(optarg) <= 0 ) {
+ std::cerr << "--queue ERROR: The queue has to be equal or greater that 2" << endl;
+ printUsage();
+ std::exit(1); }
+ else {
+ mBufferQueueLength = atoi(optarg);
+ }
+ break;
+ case 'r':
+ //-------------------------------------------------------
+ if ( atoi(optarg) <= 0 ) {
+ std::cerr << "--redundancy ERROR: The reduncancy has to be a positive integer" << endl;
+ printUsage();
+ std::exit(1); }
+ else {
+ mRedundancy = atoi(optarg);
+ }
+ break;
+ case 'z': // underrun to zero
+ //-------------------------------------------------------
+ mUnderrrunZero = true;
+ break;
+ case 'l': // loopback
+ //-------------------------------------------------------
+ mLoopBack = true;
+ break;
+ case 'e': // jamlink
+ //-------------------------------------------------------
+ mEmptyHeader = true;
+ break;
+ case 'j': // jamlink
+ //-------------------------------------------------------
+ mJamLink = true;
+ break;
+ case 'J': // Set client Name
+ //-------------------------------------------------------
+ mClientName = optarg;
+ break;
+ case 'R': // RtAudio
+ //-------------------------------------------------------
+ mUseJack = false;
+ break;
+ case 'T': // Sampling Rate
+ //-------------------------------------------------------
+ mChanfeDefaultSR = true;
+ mSampleRate = atoi(optarg);
+ break;
+ case 'F': // Buffer Size
+ //-------------------------------------------------------
+ mChanfeDefaultBS = true;
+ mAudioBufferSize = atoi(optarg);
+ break;
+ case 'v':
+ //-------------------------------------------------------
+ cout << "JackTrip VERSION: " << gVersion << endl;
+ cout << "Copyright (c) 2008-2009 Juan-Pablo Caceres, Chris Chafe." << endl;
+ cout << "SoundWIRE group at CCRMA, Stanford University" << endl;
+ cout << "" << endl;
+ std::exit(0);
+ break;
+ case 'h':
+ //-------------------------------------------------------
+ printUsage();
+ std::exit(0);
+ break;
+ default:
+ //-------------------------------------------------------
+ printUsage();
+ std::exit(0);
+ break;
+ }
+
+ // Warn user if undefined options where entered
+ //----------------------------------------------------------------------------
+ if (optind < argc) {
+ cout << gPrintSeparator << endl;
+ cout << "WARINING: The following entered options have no effect" << endl;
+ cout << " They will be ignored!" << endl;
+ cout << " Type jacktrip to see options." << endl;
+ for( ; optind < argc; optind++) {
+ printf("argument: %s\n", argv[optind]);
+ }
+ cout << gPrintSeparator << endl;
}
- cout << gPrintSeparator << endl;
- }
}
//*******************************************************************************
void Settings::printUsage()
{
- cout << "" << endl;
- cout << "JackTrip: A System for High-Quality Audio Network Performance" << endl;
- cout << "over the Internet" << endl;
- cout << "Copyright (c) 2008-2009 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 << " -s, --server Run in Server Mode" << endl;
- cout << " -c, --client <peer_host_IP_number> Run in Client Mode" << endl;
- cout << " -n, --numchannels # Number of Input and Output Channels (default "
- << 2 << ")" << endl;
- cout << " -q, --queue # (1 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)"
- << endl;
- cout << " -o, --portoffset # Receiving port offset from base port " << gDefaultPort << 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 << " -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 << " -v, --version Prints Version Number" << endl;
- cout << " -h, --help Prints this Help" << endl;
- cout << "" << 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 << "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 << endl;
+ cout << "OPTIONAL ARGUMENTS: " << endl;
+ cout << "===================" << endl;
+ 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 "
+ << gDefaultQueueLength << ")" << endl;
+ cout << " -r, --redundancy # (1 or more) Packet Redundancy to avoid glitches with packet losses (defaul 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 << " -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 << 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 << endl;
+ cout << "HELP ARGUMENTS: " << endl;
+ cout << "===============" << endl;
+ cout << " -v, --version Prints Version Number" << endl;
+ cout << " -h, --help Prints this Help" << endl;
+ cout << "" << endl;
}
@@ -276,13 +331,13 @@ void Settings::printUsage()
void Settings::startJackTrip()
{
- ///\todo Change this, just here to test
- if ( mJackTripServer ) {
- UdpMasterListener* udpmaster = new UdpMasterListener;
- udpmaster->start();
-
- //---Thread Pool Test--------------------------------------------
- /*
+ /// \todo Change this, just here to test
+ if ( mJackTripServer ) {
+ UdpMasterListener* udpmaster = new UdpMasterListener;
+ udpmaster->start();
+
+ //---Thread Pool Test--------------------------------------------
+ /*
cout << "BEFORE START" << endl;
ThreadPoolTest* thtest = new ThreadPoolTest();
// QThreadPool takes ownership and deletes 'hello' automatically
@@ -293,84 +348,112 @@ void Settings::startJackTrip()
thtest->stop();
QThreadPool::globalInstance()->waitForDone();
*/
- //---------------------------------------------------------------
- }
-
- else {
-
- //JackTrip jacktrip(mJackTripMode, mDataProtocol, mNumChans,
- // mBufferQueueLength, mAudioBitResolution);
- mJackTrip = new JackTrip(mJackTripMode, mDataProtocol, mNumChans,
- mBufferQueueLength, mRedundancy, mAudioBitResolution);
-
- // Change client name if different from default
- if (mClientName != NULL) {
- mJackTrip->setClientName(mClientName);
+ //---------------------------------------------------------------
}
- // Set buffers to zero when underrun
- if ( mUnderrrunZero ) {
- cout << "Setting buffers to zero when underrun..." << endl;
- cout << gPrintSeparator << std::endl;
- mJackTrip->setUnderRunMode(JackTrip::ZEROS);
- }
-
- // Set peer address in server mode
- if ( mJackTripMode == JackTrip::CLIENT || mJackTripMode == JackTrip::CLIENTTOPINGSERVER ) {
- mJackTrip->setPeerAddress(mPeerAddress.toLatin1().data()); }
-
- // Set Ports
- cout << "SETTING ALL PORTS" << endl;
- mJackTrip->setAllPorts(mPortNum);
-
- // Set in JamLink Mode
- if ( mJamLink ) {
- cout << "Running in JamLink Mode..." << endl;
- cout << gPrintSeparator << std::endl;
- mJackTrip->setPacketHeaderType(DataProtocol::JAMLINK);
- }
+ else {
- // Set in EmptyHeader Mode
- if ( mEmptyHeader ) {
- cout << "Running in EmptyHeader Mode..." << endl;
- cout << gPrintSeparator << std::endl;
- mJackTrip->setPacketHeaderType(DataProtocol::EMPTY);
- }
+ //JackTrip jacktrip(mJackTripMode, mDataProtocol, mNumChans,
+ // mBufferQueueLength, mAudioBitResolution);
+ mJackTrip = new JackTrip(mJackTripMode, mDataProtocol, mNumChans,
+ mBufferQueueLength, mRedundancy, mAudioBitResolution);
- // Add Plugins
- if ( mLoopBack ) {
- cout << "Running in Loop-Back Mode..." << endl;
- cout << gPrintSeparator << std::endl;
- //std::tr1::shared_ptr<LoopBack> loopback(new LoopBack(mNumChans));
- //mJackTrip->appendProcessPlugin(loopback.get());
-
- LoopBack* loopback = new LoopBack(mNumChans);
- mJackTrip->appendProcessPlugin(loopback);
-
- // ----- Test Karplus Strong -----------------------------------
- //std::tr1::shared_ptr<NetKS> loopback(new NetKS());
- //mJackTrip->appendProcessPlugin(loopback);
- //loopback->play();
- //NetKS* netks = new NetKS;
- //mJackTrip->appendProcessPlugin(netks);
- //netks->play();
- // -------------------------------------------------------------
- }
-
- // Start JackTrip
- mJackTrip->start();
-
- /*
+ // Connect Signals and Slots
+ QObject::connect(mJackTrip, SIGNAL( signalProcessesStopped() ),
+ this, SLOT( slotExitProgram() ));
+
+ // Change client name if different from default
+ if (mClientName != NULL) {
+ mJackTrip->setClientName(mClientName);
+ }
+
+ // Set buffers to zero when underrun
+ if ( mUnderrrunZero ) {
+ cout << "Setting buffers to zero when underrun..." << endl;
+ cout << gPrintSeparator << std::endl;
+ mJackTrip->setUnderRunMode(JackTrip::ZEROS);
+ }
+
+ // Set peer address in server mode
+ 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);
+
+ // Set Ports
+ //cout << "SETTING ALL PORTS" << endl;
+ mJackTrip->setBindPorts(mBindPortNum);
+ mJackTrip->setPeerPorts(mPeerPortNum);
+
+ // Set in JamLink Mode
+ if ( mJamLink ) {
+ cout << "Running in JamLink Mode..." << endl;
+ cout << gPrintSeparator << std::endl;
+ mJackTrip->setPacketHeaderType(DataProtocol::JAMLINK);
+ }
+
+ // Set in EmptyHeader Mode
+ if ( mEmptyHeader ) {
+ cout << "Running in EmptyHeader Mode..." << endl;
+ cout << gPrintSeparator << std::endl;
+ mJackTrip->setPacketHeaderType(DataProtocol::EMPTY);
+ }
+
+ // Set RtAudio
+#ifdef __RT_AUDIO__
+ if (!mUseJack) {
+ mJackTrip->setAudiointerfaceMode(JackTrip::RTAUDIO);
+ }
+#endif
+
+ // Chanfe default Sampling Rate
+ if (mChanfeDefaultSR) {
+ mJackTrip->setSampleRate(mSampleRate);
+ }
+
+ // Chanfe default Buffer Size
+ if (mChanfeDefaultBS) {
+ mJackTrip->setAudioBufferSizeInSamples(mAudioBufferSize);
+ }
+
+ // Add Plugins
+ if ( mLoopBack ) {
+ cout << "Running in Loop-Back Mode..." << endl;
+ cout << gPrintSeparator << std::endl;
+ //std::tr1::shared_ptr<LoopBack> loopback(new LoopBack(mNumChans));
+ //mJackTrip->appendProcessPlugin(loopback.get());
+
+ LoopBack* loopback = new LoopBack(mNumChans);
+ mJackTrip->appendProcessPlugin(loopback);
+
+ // ----- Test Karplus Strong -----------------------------------
+ //std::tr1::shared_ptr<NetKS> loopback(new NetKS());
+ //mJackTrip->appendProcessPlugin(loopback);
+ //loopback->play();
+ //NetKS* netks = new NetKS;
+ //mJackTrip->appendProcessPlugin(netks);
+ //netks->play();
+ // -------------------------------------------------------------
+ }
+
+ // Start JackTrip
+ mJackTrip->startProcess();
+ mJackTrip->start();
+
+ /*
sleep(10);
cout << "Stoping JackTrip..." << endl;
mJackTrip->stop();
*/
- }
+ }
}
//*******************************************************************************
void Settings::stopJackTrip()
{
- mJackTrip->stop();
+ mJackTrip->stop();
}
diff --git a/src/Settings.h b/src/Settings.h
index 5c08808..90eea26 100644
--- a/src/Settings.h
+++ b/src/Settings.h
@@ -39,14 +39,22 @@
#ifndef __SETTINGS_H__
#define __SETTINGS_H__
+#include <cstdlib>
+
#include "DataProtocol.h"
+
+#ifndef __NO_JACK__
#include "JackAudioInterface.h"
+#endif //__NO_JACK__
+
#include "JackTrip.h"
/** \brief Class to set usage options and parse settings from input
*/
-class Settings
+class Settings : public QThread
{
+ Q_OBJECT;
+
public:
Settings();
virtual ~Settings();
@@ -60,7 +68,15 @@ public:
/// \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);
+ }
private:
JackTrip* mJackTrip; ///< JackTrip class
@@ -68,17 +84,24 @@ private:
JackTrip::dataProtocolT mDataProtocol; ///< Data Protocol
int mNumChans; ///< Number of Channels (inputs = outputs)
int mBufferQueueLength; ///< Audio Buffer from network queue length
- JackAudioInterface::audioBitResolutionT mAudioBitResolution;
+ AudioInterface::audioBitResolutionT mAudioBitResolution;
QString mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
- int mPortNum; ///< Port Number
- char* mClientName;
+ 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;
};
#endif
diff --git a/src/UdpDataProtocol.cpp b/src/UdpDataProtocol.cpp
index 9e2275f..0cd1369 100644
--- a/src/UdpDataProtocol.cpp
+++ b/src/UdpDataProtocol.cpp
@@ -39,12 +39,19 @@
#include "jacktrip_globals.h"
#include "JackTrip.h"
+#include <QHostInfo>
+
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <cerrno>
#include <stdexcept>
+#ifdef __WIN_32__
+#include <winsock.h>
+#endif
+#if defined (__LINUX__) || (__MAC__OSX__)
#include <sys/socket.h> // for POSIX Sockets
+#endif
using std::cout; using std::endl;
@@ -65,6 +72,7 @@ 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);
@@ -82,14 +90,26 @@ UdpDataProtocol::~UdpDataProtocol()
//*******************************************************************************
-void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP)
+void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP) throw(std::invalid_argument)
{
- mPeerAddress.setAddress(peerHostOrIP);
+ // 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;
+ }
+
// check if the ip address is valid
if ( mPeerAddress.isNull() ) {
- 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("");
+ 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 {
@@ -103,16 +123,51 @@ void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP)
//*******************************************************************************
-void UdpDataProtocol::bindSocket(QUdpSocket& UdpSocket)
+void UdpDataProtocol::bindSocket(QUdpSocket& UdpSocket) throw(std::runtime_error)
{
QMutexLocker locker(&sUdpMutex);
+#if defined __WIN_32__
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD( 1, 1 );
+
+ err = WSAStartup( wVersionRequested, &wsaData );
+ if ( err != 0 ) {
+ // Tell the user that we couldn't find a useable
+ // winsock.dll.
+
+ return;
+ }
+
+ // 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;
+ }
+
// Creat socket descriptor
- int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ SOCKET sock_fd;
+ SOCKADDR_IN local_addr;
+#endif
- // Set local IPv4 Address
+#if defined ( __LINUX__ ) || (__MAC_OSX__)
+ int sock_fd;
+ //Set local IPv4 Address
struct sockaddr_in local_addr;
- ::bzero(&local_addr, sizeof(local_addr));
+#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
@@ -127,10 +182,22 @@ void UdpDataProtocol::bindSocket(QUdpSocket& UdpSocket)
// 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));
+#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
// To be able to use the two UDP sockets bound to the same port number,
// we connect the receiver and issue a SHUT_WR.
@@ -140,6 +207,7 @@ void UdpDataProtocol::bindSocket(QUdpSocket& UdpSocket)
QUdpSocket::WriteOnly);
}
else if (mRunMode == RECEIVER) {
+#if defined (__LINUX__) || (__MAC_OSX__)
// Set peer IPv4 Address
struct sockaddr_in peer_addr;
bzero(&peer_addr, sizeof(peer_addr));
@@ -155,6 +223,31 @@ void UdpDataProtocol::bindSocket(QUdpSocket& UdpSocket)
{ 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"); }
+#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");
+ }
+#endif
UdpSocket.setSocketDescriptor(sock_fd, QUdpSocket::ConnectedState,
QUdpSocket::ReadOnly);
@@ -221,11 +314,20 @@ void UdpDataProtocol::getPeerAddressFromFirstPacket(QUdpSocket& UdpSocket,
//*******************************************************************************
void UdpDataProtocol::run()
{
- mStopped = false;
-
+ //QObject::connect(this, SIGNAL(signalError(const char*)),
+ // mJackTrip, SLOT(slotStopProcesses()),
+ // Qt::QueuedConnection);
+
// Creat and bind sockets
QUdpSocket UdpSocket;
- bindSocket(UdpSocket); // Bind Socket
+ try {
+ bindSocket(UdpSocket); // Bind Socket
+ } catch ( const std::exception & e ) {
+ emit signalError( e.what() );
+ return;
+ }
+
+
QHostAddress PeerAddress;
PeerAddress = mPeerAddress;
@@ -257,30 +359,34 @@ void UdpDataProtocol::run()
// Set realtime priority (function in jacktrip_globals.h)
set_crossplatform_realtime_priority();
- // Connect signals and slots for packets arriving too late notifications
- QObject::connect(this, SIGNAL(signalWatingTooLong(int)),
- this, SLOT(printUdpWaitedTooLong(int)),
- Qt::QueuedConnection);
-
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() ) { QThread::msleep(100); }
+ 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];
+ 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.get()), first_packet_size);
+ //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.get());
+ mJackTrip->checkPeerSettings(first_packet);
mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
std::cout << "Received Connection for Peer!" << std::endl;
+ emit signalReceivedConnectionFromPeer();
// Redundancy Variables
// --------------------
@@ -357,7 +463,7 @@ bool UdpDataProtocol::waitForReady(QUdpSocket& UdpSocket, int timeout_msec)
while ( ( !(UdpSocket.hasPendingDatagrams()) && (ellaped_time_usec <= timeout_usec) )
&& !mStopped ){
- //cout << mStopped << endl;
+ if (mStopped) { return false; }
QThread::usleep(loop_resolution_usec);
ellaped_time_usec += loop_resolution_usec;
@@ -380,7 +486,7 @@ void UdpDataProtocol::printUdpWaitedTooLong(int wait_msec)
{
int wait_time = 30; // msec
if ( !(wait_msec%wait_time) ) {
- std::cerr << "UDP is waited too long (more than " << wait_time << "ms)..." << endl;
+ std::cerr << "UDP waiting too long (more than " << wait_time << "ms)..." << endl;
}
}
@@ -409,7 +515,7 @@ void UdpDataProtocol::receivePacketRedundancy(QUdpSocket& UdpSocket,
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 ( 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
diff --git a/src/UdpDataProtocol.h b/src/UdpDataProtocol.h
index fbce562..4015023 100644
--- a/src/UdpDataProtocol.h
+++ b/src/UdpDataProtocol.h
@@ -38,9 +38,12 @@
#ifndef __UDPDATAPROTOCOL_H__
#define __UDPDATAPROTOCOL_H__
+#include <stdexcept>
+
#include <QThread>
#include <QUdpSocket>
#include <QHostAddress>
+#include <QMutex>
#include "DataProtocol.h"
#include "jacktrip_types.h"
@@ -84,7 +87,7 @@ public:
/** \brief Set the Peer address to connect to
* \param peerHostOrIP IPv4 number or host name
*/
- void setPeerAddress(const char* peerHostOrIP);
+ void setPeerAddress(const char* peerHostOrIP) throw(std::invalid_argument);
/** \brief Receives a packet. It blocks until a packet is received
*
@@ -146,11 +149,12 @@ signals:
void signalWatingTooLong(int wait_msec);
-private:
+//private:
+protected:
/** \brief Binds the UDP socket to the available address and specified port
*/
- void bindSocket(QUdpSocket& UdpSocket);
+ void bindSocket(QUdpSocket& UdpSocket) throw(std::runtime_error);
/** \brief This function blocks until data is available for reading in the
* QUdpSocket. The function will timeout after timeout_msec microseconds.
@@ -165,21 +169,24 @@ private:
/** \brief Redundancy algorythm at the receiving end
*/
- 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 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
*/
- void sendPacketRedundancy(QUdpSocket& UdpSocket,
- QHostAddress& PeerAddress,
- int8_t* full_redundant_packet,
- int full_redundant_packet_size,
- int full_packet_size);
+ virtual void sendPacketRedundancy(QUdpSocket& UdpSocket,
+ QHostAddress& PeerAddress,
+ 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
diff --git a/src/UdpMasterListener.cpp b/src/UdpMasterListener.cpp
index 874eda4..6650eaa 100644
--- a/src/UdpMasterListener.cpp
+++ b/src/UdpMasterListener.cpp
@@ -38,6 +38,12 @@
#include <iostream>
#include <cstdlib>
#include <stdexcept>
+#include <cstring>
+
+#include <QTcpServer>
+#include <QTcpSocket>
+#include <QStringList>
+#include <QMutexLocker>
#include "UdpMasterListener.h"
#include "JackTripWorker.h"
@@ -48,13 +54,20 @@ using std::cout; using std::endl;
//*******************************************************************************
UdpMasterListener::UdpMasterListener(int server_port) :
- mJTWorker(NULL),
+ //mJTWorker(NULL),
mServerPort(server_port),
mStopped(false),
mTotalRunningThreads(0)
{
// Register JackTripWorker with the master listener
- mJTWorker = new JackTripWorker(this);
+ //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++) {
@@ -63,23 +76,138 @@ UdpMasterListener::UdpMasterListener(int server_port) :
}
// Set the base dynamic port
// The Dynamic and/or Private Ports are those from 49152 through 65535
- mBasePort = ( random() % ( (65535 - gMaxThreads) - 49152 ) ) + 49152;
+ // mBasePort = ( rand() % ( (65535 - gMaxThreads) - 49152 ) ) + 49152;
+
+ // SoundWIRE ports open are UDP 61000-62000
+ mBasePort = 61000;
}
//*******************************************************************************
UdpMasterListener::~UdpMasterListener()
{
- mThreadPool.waitForDone ();
- delete mJTWorker;
+ QMutexLocker lock(&mMutex);
+ mThreadPool.waitForDone();
+ //delete mJTWorker;
+ for (int i = 0; i<gMaxThreads; i++) {
+ delete mJTWorkers->at(i);
+ }
+ delete mJTWorkers;
}
//*******************************************************************************
+// Now that the first handshake is with TCP server, if the addreess/peer port of
+// the client is already on the thread pool, it means that a new connection is
+// requested (the old was desconnected). So we have to remove that thread from
+// 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);
+ }
+
+ 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);
+ }
+ // 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;
@@ -93,59 +221,110 @@ void UdpMasterListener::run()
cout << "Waiting for client..." << endl;
cout << "=======================================================" << endl;
while ( !mStopped )
+ {
+ //cout << "WAITING........................." << endl;
+ while ( MasterUdpSocket.hasPendingDatagrams() )
{
- //cout << "WAITING........................." << endl;
- while ( MasterUdpSocket.hasPendingDatagrams() )
- {
- //cout << "Received request from Client!" << endl;
- // Get Client IP Address and outgoing port from packet
- int rv = MasterUdpSocket.readDatagram(buf, 1, &PeerAddress, &peer_port);
- //cout << "Peer Port in Server ==== " << peer_port << endl;
- if (rv < 0) { std::cerr << "ERROR: Bad UDP packet read..." << endl; }
-
- /// \todo Get number of channels in the client from header
-
- // check by comparing 32-bit addresses
- /// \todo Add the port number in the comparison
- int id = isNewAddress(PeerAddress.toIPv4Address(), peer_port);
-
- //cout << "IDIDIDIDIDDID === " << id << endl;
-
- // If the address is new, create a new thread in the pool
- if (id >= 0) // old address is -1
- {
- // redirect port and spawn listener
- sendToPoolPrototype(id);
- // wait until one is complete before another spawns
- while (mJTWorker->isSpawning()) { QThread::msleep(1); }
- mTotalRunningThreads++;
- cout << "Total Running Threads: " << mTotalRunningThreads << endl;
- cout << "=======================================================" << endl;
- }
- //cout << "ENDDDDDDDDDDDDDDDDDd === " << id << endl;
- }
- QThread::msleep(100);
+ cout << "Received request from Client!" << endl;
+ // Get Client IP Address and outgoing port from packet
+ int rv = MasterUdpSocket.readDatagram(buf, 1, &PeerAddress, &peer_port);
+ cout << "Peer Port in Server ==== " << peer_port << endl;
+ if (rv < 0) { std::cerr << "ERROR: Bad UDP packet read..." << endl; }
+
+ /// \todo Get number of channels in the client from header
+
+ // check by comparing 32-bit addresses
+ /// \todo Add the port number in the comparison
+ cout << "peer_portpeer_portpeer_port === " << peer_port << endl;
+ int id = isNewAddress(PeerAddress.toIPv4Address(), peer_port);
+
+ //cout << "IDIDIDIDIDDID === " << id << endl;
+
+ // If the address is new, create a new thread in the pool
+ if (id >= 0) // old address is -1
+ {
+ // redirect port and spawn listener
+ sendToPoolPrototype(id);
+ // wait until one is complete before another spawns
+ while (mJTWorker->isSpawning()) { QThread::msleep(10); }
+ mTotalRunningThreads++;
+ cout << "Total Running Threads: " << mTotalRunningThreads << endl;
+ cout << "=======================================================" << endl;
+ }
+ //cout << "ENDDDDDDDDDDDDDDDDDd === " << id << endl;
+ }
+ QThread::msleep(100);
+ }
+ */
+}
+
+
+//*******************************************************************************
+// 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;
+ }
+ }
+
+ 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;
+}
+
+
+//*******************************************************************************
+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;
+ }
+ }
+ return 1;
+ cout << "Port sent to Client" << endl;
}
//*******************************************************************************
+/*
void UdpMasterListener::sendToPoolPrototype(int id)
{
- cout << "id ID **********@@@@@@@@@@@@@@@@@@@@@************** " << id << endl;
mJTWorker->setJackTrip(id, mActiveAddress[id][0],
- mBasePort+(2*id), mActiveAddress[id][1],
- 1); /// \todo temp default to 1 channel
+ mBasePort+(2*id), mActiveAddress[id][1],
+ 1); /// \todo temp default to 1 channel
mThreadPool.start(mJTWorker, QThread::TimeCriticalPriority); //send one thread to the pool
}
+*/
//*******************************************************************************
-void UdpMasterListener::bindUdpSocket(QUdpSocket& udpsocket, int port)
+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) ) {
+ 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.");
@@ -160,27 +339,73 @@ void UdpMasterListener::bindUdpSocket(QUdpSocket& udpsocket, int port)
// check by comparing 32-bit addresses
int UdpMasterListener::isNewAddress(uint32_t address, uint16_t port)
{
- /// \todo Add the port number in the comparison, i.e., compart IP/port pair
-
+ 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++;
- }
- if ( !busyAddress ) {
+ {
+ 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;
+ }
+ }
+ 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++;
+ }
+ }
+ }
+ if (!busyAddress) {
+ mTotalRunningThreads++;
}
return ((busyAddress) ? -1 : id);
}
//*******************************************************************************
-int UdpMasterListener::releasePort(int id)
+int UdpMasterListener::getPoolID(uint32_t 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;
+}
+
+
+//*******************************************************************************
+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
}
+
+
+// TODO:
+// USE bool QAbstractSocket::isValid () const to check if socket is connect. if not, exit loop
+
diff --git a/src/UdpMasterListener.h b/src/UdpMasterListener.h
index 338229e..184176d 100644
--- a/src/UdpMasterListener.h
+++ b/src/UdpMasterListener.h
@@ -39,11 +39,15 @@
#define __UDPMASTERLISTENER_H__
#include <iostream>
+#include <stdexcept>
#include <QThread>
#include <QThreadPool>
#include <QUdpSocket>
#include <QHostAddress>
+#include <QTcpSocket>
+#include <QTcpServer>
+#include <QMutex>
#include "jacktrip_types.h"
#include "jacktrip_globals.h"
@@ -63,25 +67,23 @@ public:
UdpMasterListener(int server_port = gServerUdpPort);
virtual ~UdpMasterListener();
- /** \brief Implements the Thread Loop. To start the thread, call start()
- * ( DO NOT CALL run() )
- */
+ /// \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; };
+ void stop() { mStopped = true; }
- int releasePort(int id);
+ int releaseThread(int id);
private slots:
- void testRecieve()
- {
- 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);
private:
@@ -89,13 +91,17 @@ private:
* \param udpsocket a QUdpSocket
* \param port Port number
*/
- static void bindUdpSocket(QUdpSocket& udpsocket, int port);
+ static void bindUdpSocket(QUdpSocket& udpsocket, int port) throw(std::runtime_error);
+
+ 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
@@ -103,10 +109,16 @@ private:
*/
int isNewAddress(uint32_t address, uint16_t port);
- QUdpSocket mUdpMasterSocket; ///< The UDP socket
- QHostAddress mPeerAddress; ///< The Peer Address
+ /** \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
+ //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
@@ -117,6 +129,7 @@ private:
/// Boolean stop the execution of the thread
volatile bool mStopped;
int mTotalRunningThreads; ///< Number of Threads running in the pool
+ QMutex mMutex;
};
diff --git a/src/build b/src/build
index 546567d..18f47fa 100755
--- a/src/build
+++ b/src/build
@@ -14,12 +14,32 @@ fi
# Set qmake command name
if [[ $platform == 'linux' ]]; then
- QCMD=qmake-qt4
+ if hash qmake-qt5 2>/dev/null; then
+ echo "Using qmake-qt5"
+ QCMD=qmake-qt5
+ elif hash qmake-qt4 2>/dev/null; then
+ echo "Using qmake-qt4"
+ QCMD=qmake-qt4
+ elif hash qmake 2>/dev/null; then #in case qt was compiled by user
+ echo "Using qmake"
+ QCMD=qmake
+ fi
+ QSPEC=linux-g++
elif [[ $platform == 'macosx' ]]; then
QCMD=qmake
+ QSPEC=macx-g++
fi
# Build
-$QCMD jacktrip.pro
-make clean
-make release
+if [[ $1 == 'nojack' ]]; then
+ echo "Building without Jack"
+ $QCMD -spec $QSPEC -config nojack jacktrip.pro
+ make clean
+ $QCMD -spec $QSPEC -config nojack jacktrip.pro
+ make release
+else
+ $QCMD -spec $QSPEC jacktrip.pro
+ make clean
+ $QCMD -spec $QSPEC jacktrip.pro
+ make release
+fi
diff --git a/src/jacktrip-1.0.5.diff b/src/jacktrip-1.0.5.diff
deleted file mode 100644
index 30292b9..0000000
--- a/src/jacktrip-1.0.5.diff
+++ /dev/null
@@ -1,26 +0,0 @@
-Index: src/JackTripWorker.h
-===================================================================
---- src/JackTripWorker.h (revision 495)
-+++ src/JackTripWorker.h (working copy)
-@@ -46,6 +46,8 @@
- #include <QHostAddress>
- #include <QMutex>
-
-+#include "jacktrip_types.h"
-+
- class JackTrip; // forward declaration
- class UdpMasterListener; // forward declaration
-
-Index: src/jacktrip_globals.cpp
-===================================================================
---- src/jacktrip_globals.cpp (revision 495)
-+++ src/jacktrip_globals.cpp (working copy)
-@@ -38,6 +38,8 @@
- #include "jacktrip_globals.h"
- #include "jacktrip_types.h"
-
-+#include <stdio.h>
-+
- #if defined ( __LINUX__ )
- #include <sched.h>
- #endif //__LINUX__
diff --git a/src/jacktrip.pro b/src/jacktrip.pro
index b92e69d..bd95a2b 100644
--- a/src/jacktrip.pro
+++ b/src/jacktrip.pro
@@ -10,28 +10,75 @@ CONFIG(debug, debug|release) {
}
QT -= gui
QT += network
-INCLUDEPATH+=/usr/local/include
-LIBS += -ljack -lm
+# http://wiki.qtcentre.org/index.php?title=Undocumented_qmake#Custom_tools
+DEFINES += __RT_AUDIO__
+# Configuration without Jack
+nojack {
+ DEFINES += __NO_JACK__
+}
+!win32 {
+ INCLUDEPATH+=/usr/local/include
+ LIBS += -L/usr/local/lib -ljack -lm
+ nojack {
+ message(Building NONJACK)
+ LIBS -= -ljack
+ }
+}
+
macx {
message(MAC OS X)
+ QMAKE_CXXFLAGS += -D__MACOSX_CORE__ #-D__UNIX_JACK__ #RtAudio Flags
+ QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.9
+ QMAKE_MAC_SDK = macosx10.9
CONFIG -= app_bundle
- CONFIG += x86 #ppc
- LIBS += -framework CoreAudio
+ #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
+ QMAKE_CXXFLAGS += -D__LINUX_ALSA__ #-D__LINUX_OSS__ #RtAudio Flags
+ QMAKE_CXXFLAGS += -g -O2
+ DEFINES += __LINUX__
+ }
+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"
+ DEFINES += __WIN_32__
+ DEFINES -= UNICODE #RtAudio for Qt
+}
+
+
+
+
DESTDIR = .
-QMAKE_CLEAN += ./jacktrip ./jacktrip_debug
+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
+}
+
# Input
HEADERS += DataProtocol.h \
- JackAudioInterface.h \
JackTrip.h \
jacktrip_globals.h \
jacktrip_types.h \
@@ -49,9 +96,13 @@ HEADERS += DataProtocol.h \
ThreadPoolTest.h \
UdpDataProtocol.h \
UdpMasterListener.h \
- jacktrip_tests.cpp
+ AudioInterface.h \
+ RtAudioInterface.h
+ #JamTest.h
+!nojack {
+SOURCES += JackAudioInterface.h
+}
SOURCES += DataProtocol.cpp \
- JackAudioInterface.cpp \
JackTrip.cpp \
jacktrip_globals.cpp \
jacktrip_main.cpp \
@@ -63,6 +114,30 @@ SOURCES += DataProtocol.cpp \
ProcessPlugin.cpp \
RingBuffer.cpp \
Settings.cpp \
- tests.cpp \
+ #tests.cpp \
UdpDataProtocol.cpp \
- UdpMasterListener.cpp
+ UdpMasterListener.cpp \
+ AudioInterface.cpp \
+ RtAudioInterface.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
+}
diff --git a/src/jacktrip_globals.cpp b/src/jacktrip_globals.cpp
index df5c24d..feb5191 100644
--- a/src/jacktrip_globals.cpp
+++ b/src/jacktrip_globals.cpp
@@ -35,13 +35,17 @@
* \date August 2008
*/
+#include <iostream>
+#include <cstring>
+#include <cstdio>
+
#include "jacktrip_globals.h"
#include "jacktrip_types.h"
-#include <stdio.h>
-
#if defined ( __LINUX__ )
#include <sched.h>
+#include <unistd.h>
+#include <sys/types.h>
#endif //__LINUX__
#if defined ( __MAC_OSX__ )
@@ -183,6 +187,25 @@ int set_realtime_priority (void)
}
#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__ )
@@ -191,6 +214,10 @@ void set_crossplatform_realtime_priority()
#if defined ( __MAC_OSX__ )
set_realtime(1250000,60000,90000);
#endif //__MAC_OSX__
+#if defined __WIN_32__
+ win_priority();
+#endif
+
}
diff --git a/src/jacktrip_globals.h b/src/jacktrip_globals.h
index f9d2d76..3f87dac 100644
--- a/src/jacktrip_globals.h
+++ b/src/jacktrip_globals.h
@@ -38,22 +38,31 @@
#ifndef __JACKTRIP_GLOBALS_H__
#define __JACKTRIP_GLOBALS_H__
-#include "JackAudioInterface.h"
+#include "AudioInterface.h"
+//#include "JackAudioInterface.h"
+/// \todo Add this namespace
+//namespace JackTrip
-//namespace JackTrip/// \todo Add this namespace
-
-const char* const gVersion = "1.0.5"; ///< JackTrip version
+const char* const gVersion = "1.1"; ///< JackTrip version
//*******************************************************************************
/// \name Default Values
//@{
const int gDefaultNumInChannels = 2;
const int gDefaultNumOutChannels = 2;
-const JackAudioInterface::audioBitResolutionT gDefaultBitResolutionMode =
- JackAudioInterface::BIT16;
+//const JackAudioInterface::audioBitResolutionT gDefaultBitResolutionMode =
+// JackAudioInterface::BIT16;
+const AudioInterface::audioBitResolutionT gDefaultBitResolutionMode =
+ AudioInterface::BIT16;
const int gDefaultQueueLength = 4;
const int gDefaultOutputQueueLength = 4;
+const uint32_t gDefaultSampleRate = 48000;
+const uint32_t gDefaultBufferSizeInSamples = 128;
+const QString gDefaultLocalAddress = QString();
+const int gDefaultRedundancy = 1;
+const int gTimeOutMultiThreadedServer = 5000; // seconds
+const int gWaitCounter = 60;
//@}
@@ -110,7 +119,13 @@ int set_realtime_priority (void);
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
diff --git a/src/jacktrip_main.cpp b/src/jacktrip_main.cpp
index e0d4203..96159d2 100644
--- a/src/jacktrip_main.cpp
+++ b/src/jacktrip_main.cpp
@@ -47,11 +47,11 @@
//#include "TestRingBuffer.h"
#include "LoopBack.h"
#include "PacketHeader.h"
-#include "JackTripThread.h"
+//#include "JackTripThread.h"
+#include "RtAudioInterface.h"
#include "jacktrip_tests.cpp"
#include "jacktrip_globals.h"
-
using std::cout; using std::endl;
@@ -59,14 +59,30 @@ int main(int argc, char** argv)
{
QCoreApplication app(argc, argv);
- //--------TESTS--------------------------
- //main_tests(argc, argv); // test functions
- //while (true) sleep(9999);
- //---------------------------------------
+ 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);
- // Get Settings from user
- // ----------------------
- try
+ //while (true) sleep(9999);
+ }
+ else {
+ //---------------------------------------
+
+ // Get Settings from user
+ // ----------------------
+ try
{
// Get Settings from user
// ----------------------
@@ -74,7 +90,7 @@ int main(int argc, char** argv)
settings->parseInput(argc, argv);
settings->startJackTrip();
}
- catch ( const std::exception & e )
+ catch ( const std::exception & e )
{
std::cerr << "ERROR:" << endl;
std::cerr << e.what() << endl;
@@ -82,5 +98,7 @@ int main(int argc, char** argv)
std::cerr << gPrintSeparator << endl;
return -1;
}
+ }
+
return app.exec();
}
diff --git a/src/jacktrip_types.h b/src/jacktrip_types.h
index 08bfe87..f9f10f0 100644
--- a/src/jacktrip_types.h
+++ b/src/jacktrip_types.h
@@ -39,47 +39,51 @@
#ifndef __JACKTRIP_TYPES_H__
#define __JACKTRIP_TYPES_H__
-#include <jack/types.h>
+//#include <jack/types.h>
#include <QtGlobal> //For QT4 types
-//-------------------------------------------------------------------------------
-/** \name Audio typedefs
+//namespace JackTripNamespace
+//{
+
+ //-------------------------------------------------------------------------------
+ /** \name Audio typedefs
*
*/
-//-------------------------------------------------------------------------------
-//@{
-/// Audio sample type
-typedef jack_default_audio_sample_t sample_t;
-//@}
+ //-------------------------------------------------------------------------------
+ //@{
+ /// Audio sample type
+ //typedef jack_default_audio_sample_t sample_t;
+ typedef float sample_t;
+ //@}
-//-------------------------------------------------------------------------------
-/** \name Typedefs that guaranty some specific bit length
+ //-------------------------------------------------------------------------------
+ /** \name Typedefs that guaranty some specific bit length
*
* It uses the QT4 types. This can be changed in the future, keeping
* compatibility for the rest of the code.
*/
-//-------------------------------------------------------------------------------
-//@{
-/// Typedef for <tt>unsigned char</tt>. This type is guaranteed to be 8-bit.
-typedef quint8 uint8_t;
-/// Typedef for <tt>unsigned short</tt>. This type is guaranteed to be 16-bit.
-typedef quint16 uint16_t;
-/// Typedef for <tt>unsigned int</tt>. This type is guaranteed to be 32-bit.
-typedef quint32 uint32_t;
-/// \brief Typedef for <tt>unsigned long long int</tt>. This type is guaranteed to
-/// be 64-bit.
-//typedef quint64 uint64_t;
-/// Typedef for <tt>signed char</tt>. This type is guaranteed to be 8-bit.
-typedef qint8 int8_t;
-/// Typedef for <tt>signed short</tt>. This type is guaranteed to be 16-bit.
-typedef qint16 int16_t;
-/// Typedef for <tt>signed int</tt>. This type is guaranteed to be 32-bit.
-typedef qint32 int32_t;
-/// \brief Typedef for <tt>long long int</tt>. This type is guaranteed to
-/// be 64-bit.
-//typedef qint64 int64_t;
-//@}
-
+ //-------------------------------------------------------------------------------
+ //@{
+ /// Typedef for <tt>unsigned char</tt>. This type is guaranteed to be 8-bit.
+ typedef quint8 uint8_t;
+ /// Typedef for <tt>unsigned short</tt>. This type is guaranteed to be 16-bit.
+ typedef quint16 uint16_t;
+ /// Typedef for <tt>unsigned int</tt>. This type is guaranteed to be 32-bit.
+ typedef quint32 uint32_t;
+ /// \brief Typedef for <tt>unsigned long long int</tt>. This type is guaranteed to
+ /// be 64-bit.
+ //typedef quint64 uint64_t;
+ /// Typedef for <tt>signed char</tt>. This type is guaranteed to be 8-bit.
+ typedef qint8 int8_t;
+ /// Typedef for <tt>signed short</tt>. This type is guaranteed to be 16-bit.
+ typedef qint16 int16_t;
+ /// Typedef for <tt>signed int</tt>. This type is guaranteed to be 32-bit.
+ typedef qint32 int32_t;
+ /// \brief Typedef for <tt>long long int</tt>. This type is guaranteed to
+ /// be 64-bit.
+ //typedef qint64 int64_t;
+ //@}
+//} // end of namespace JackTripNamespace
#endif
diff --git a/src/tests.cpp b/src/tests.cpp
deleted file mode 100644
index 6582563..0000000
--- a/src/tests.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-//*****************************************************************
-/*
- JackTrip: A System for High-Quality Audio Network Performance
- over the Internet
-
- 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
- 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.
-*/
-//*****************************************************************
-
-/**
- * \file tests.cpp
- * \author Juan-Pablo Caceres
- * \date June 2008
- */
-#include <iostream>
-#include <unistd.h>
-#include <getopt.h>
-
-
-#include "JackAudioInterface.h"
-#include "UdpDataProtocol.h"
-#include "RingBuffer.h"
-#include "JackTrip.h"
-#include "Settings.h"
-#include "TestRingBuffer.h"
-#include "jacktrip_globals.h"
-
-using namespace std;
-
-void tests()
-{
- // Test JackTrip
- //================================================================
- //JackTrip jacktrip1;
- //jacktrip1.startThreads();
-
- //JackTrip jacktrip2;
- //jacktrip2.startThreads();
-
- /*
- // TestRingBuffer
- //================================================================
- TestRingBufferWrite tw;
- TestRingBufferRead tr;
- tr.start();
- tw.start();
- */
-
- /*
- // Test RingBuffer
- //================================================================
- RingBuffer rb(2,2);
-
- int8_t* writeSlot;
- writeSlot = new int8_t[2];
- writeSlot[0] = *"a";
- writeSlot[1] = *"b";
- std::cout << *writeSlot << std::endl;
- std::cout << writeSlot[0] << std::endl;
- std::cout << writeSlot[1] << std::endl;
- std::cout << *(writeSlot+1) << std::endl;
- rb.writeSlot(writeSlot);
-
- int8_t* readSlot;
- readSlot = new int8_t[2];
- rb.readSlot(readSlot);
- std::cout << *(readSlot) << std::endl;
- std::cout << *(readSlot+1) << std::endl;
- */
-
-
- /*
- // Test UDP Socket
- //================================================================
- UdpDataProtocol udp_rec(RECEIVER, "192.168.1.4");
- UdpDataProtocol udp_send(SENDER, "192.168.1.4");
- udp_rec.start();
- udp_send.start();
- */
-
- /*
- // Test JackAudioInterface
- //================================================================
- JackAudioInterface jack_test(4);
- cout << "SR: " << jack_test.getSampleRate() << endl;
- cout << "Buffer Size: " << jack_test.getBufferSize() << endl;
- jack_test.setProcessCallback(process);
- jack_test.startProcess();
- */
-
-
- while (true)
- {
- //cout << "SR: " << test.getSampleRate() << endl;
- //cout << "Buffer Size: " << test.getBufferSize() << endl;
- usleep(1000000);
- //usleep(1);
- }
-
-}
--
jacktrip packaging
More information about the pkg-multimedia-commits
mailing list