--- /dev/null
+---
+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
+- (added) Option for packets without header
+- (added) Option to change default client name
+- (fixed) General optimizations and code cleanup
+- (added) Improved, now cross-platform build script
+
+---
+1.0.4
+- (fixed) Buss error caused when no physical inputs or outputs ports are available
+
+---
+1.0.3
+- (added) Redundancy Algorithm for UDP Packets to to avoid glitches with packet losses
+- (fixed) Now compiles on 64bits machines
+- (fixed) Improved exceptions handling
+- (added) Basic Karplus-Strong model added as Plug-in
+- (added) Some functionality reimplemented using signals and slots for
+ more flexibility
+- (added) Multiple-Client-Server in alpha testing, expect it working in the next release
+
+---
+1.0.2 Alpha
+- (added) Port offset mode, to use a different UDP port than the default one.
+- (fixed) Improved thread behavior
+
+---
+1.0.1 Alpha
+- (added) jamlink mode to connect with jamlink boxes
+- (fixed) thread priority in both Linux and Mac OS X (still need some work on the Mac OS X version)
+- (fixed) Bug that was causing plug-ins not to behave correctly
+- (added) Loopback mode
+- (added) Underrun Modes: Wavetable (default) and set to zeros
+- (added) Check for peer audio settings, program exists if they don't match
+- (added) Automatically connect ports to available physical audio interface.
+
+---
+1.0 Alpha - initial release
--- /dev/null
+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/
--- /dev/null
+High Priority TODOS:
+--------------------
+
+- Add redundancy to UDP (DONE)
+- Finish header implementation, add run-time check
+
+
+Plug-ins:
+---------
+- Extend Plugin structure to include more than 1 plug-in and add the mode for local effect (not loopback)
+- add the offset option to process starting from a different channel
+- Set the faust compiler to automatically generate plugins
+- Add low latency compression www.celt-codec.org
+
+Protocol:
+---------
+- Add TCP clacc
+- Add SCTP class
+- Maybe add a layer of OSC communication for control messages
--- /dev/null
+//*****************************************************************
+/*
+ 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 documentation.cpp
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+
+// Main Page Documentation
+//-----------------------------------------------------------------
+/**
+\mainpage JackTrip Documentation
+
+\section intro_sec About JackTrip
+
+JackTrip: A System for High-Quality Audio Network Performance
+over the Internet.
+
+JackTrip is a Linux and Mac OS X-based system used for multi-machine network
+performance over the Internet. It supports any number of channels
+(as many as the computer/network can handle) of bidirectional, high quality,
+uncompressed audio signal steaming.
+
+You can use it between any combination of Linux and Mac OS X
+(i.e., one end using Linux can connect to the other using Mac OS X).
+
+It is currently being developed and actively tested at CCRMA by the SoundWIRE group.
+
+
+
+\section install_sec Installation
+
+Download the latest release:
+<a href="https://sourceforge.net/project/showfiles.php?group_id=236811">Download</a>
+
+Please read the documentation inside the packet to install.
+
+\subsection install_subsec_osx Mac OS X Requirements
+
+You'll need: <a href="http://www.jackosx.com/">Jack OS X</a>.
+The documentation explains how to install it and set it up, and it's highly recommended.
+
+Jack OS X comes with JackPilot to do the audio routing.
+An alternative is <a href="http://qjackctl.sourceforge.net/">qjackctl</a>,
+which I find easier to use. You can find the binary here:
+<a href="http://www.ardour.org/osx_system_requirements">qjackctl mac binary</a>
+
+If you use Leopard, you won't need to configure the UDP ports manually.
+
+\subsubsection install_linux Linux Requirements
+
+Please read the documentation inside the packet to compile and install in linux.\n
+The older version of JackTrip is documented
+<a href="http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/">here</a>.
+Please follow those instructions to configure the firewall under
+
+
+
+\section using Using JackTrip
+
+Type jacktrip in a terminal window to display a help list with all the options.
+JackTrip uses Jack as its audio server. You have to make sure that the settings in
+Jack are the same in the local and remote machine.
+
+There are two parameters that you want to tweak: Frames/Period and Sample Rate.
+The Lower the Frames/Period, the lower the latency.
+The higher the Sampling Rate, the higher the bandwidth requirements.
+You have to make sure these settings match in both machines.
+
+\image html jack_main_settings.jpg
+
+You also may want to look at the internal buffering
+<tt>-q, --queue</tt> parameter in JackTrip. If your connection is very unstable, with a lot of jitter,
+you should increase this number at the expense of a higher latency.
+
+The audio bit resolution parameter, <tt>-b, --bitres</tt>, can be use to decrease (or increase)
+the bandwidth requirements, at the expense of a lower audio quality.
+
+A basic connection will have one of the nodes as a server:
+
+<tt>jacktrip -s</tt>
+
+And the other as a client
+
+<tt>jacktrip -c [SERVER-IP-NUMBER]</tt>
+
+You'll see a JackTrip client in Jack. Everything you connect into the send ports
+will be transmitted to your peer. You'll receive what your peer sends you on the receive ports.
+
+\image html jack_routing.png
+
+*/
+
+
--- /dev/null
+</BODY>
+</HTML>
+<center>
+<footer>
+<p> </p>
+<font size="1">
+<p>Documentation generated by Doxygen $doxygenversion on $datetime</p>
+<p>
+© 2008 by Juan-Pablo Caceres (jcaceres <em>at</em> ccrma <em>dot</em> stanford <em>dot</em> edu) and
+Chris Chafe<br />
+<a href="http://ccrma.stanford.edu/groups/soundwire/" title="SoundWIRE Group">SoundWIRE Group</a> at
+<a href="http://ccrma.stanford.edu/" title="CCRMA home">CCRMA</a> -
+<a href="http://www.stanford.edu/" title="Stanford home">Stanford University</a>
+</font>
+<p>
+<a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=236811&type=1" width="88" height="31" border="0" alt="SourceForge.net Logo" /></a>
+</p>
+</center>
+</footer>
--- /dev/null
+all : jackgtk
+
+test: jackgtk alsagtk jackqt alsaqt ladspa ossgtk bench plot sndfile jackconsole
+
+svg:
+ $(MAKE) -f Makefile.svg
+
+puredata :
+ install -d puredatadir
+ $(MAKE) DEST='puredatadir/' ARCH='puredata.cpp' LIB='' -f Makefile.pdcompile
+
+alsagtk :
+ install -d alsagtkdir
+ $(MAKE) DEST='alsagtkdir/' ARCH='alsa-gtk.cpp' LIB='-lpthread -lasound `pkg-config --cflags --libs gtk+-2.0`' -f Makefile.compile
+
+jackgtk :
+ install -d jackgtkdir
+ $(MAKE) DEST='jackgtkdir/' ARCH='jack-gtk.cpp' LIB='`pkg-config --cflags --libs jack gtk+-2.0`' -f Makefile.compile
+
+jackqt :
+ install -d jackqtdir
+ $(MAKE) DEST='jackqtdir/' ARCH='jack-qt.cpp' LIB='-ljack' -f Makefile.qtcompile
+
+alsaqt :
+ install -d alsaqtdir
+ $(MAKE) DEST='alsaqtdir/' ARCH='alsa-qt.cpp' LIB='-lpthread -lasound' -f Makefile.qtcompile
+
+ladspa :
+ install -d ladspadir
+ $(MAKE) DEST='ladspadir/' ARCH='ladspa.cpp' LIB='-fPIC -shared' EXT='.so' -f Makefile.ladspacompile
+
+jackwx :
+ install -d jackwxdir
+ $(MAKE) DEST='jackwxdir/' ARCH='jack-wx.cpp' LIB='`pkg-config jack --cflags --libs` `wx-config --cflags --libs`' -f Makefile.compile
+
+ossgtk :
+ install -d ossgtkdir
+ $(MAKE) DEST='ossgtkdir/' ARCH='oss-gtk.cpp' LIB='-lpthread `pkg-config gtk+-2.0 --cflags --libs`' -f Makefile.compile
+
+osswx :
+ install -d osswxdir
+ $(MAKE) DEST='osswxdir/' ARCH='oss-wx.cpp' LIB='-lpthread `wx-config --cflags --libs`' -f Makefile.compile
+
+pagtk :
+ install -d pagtkdir
+ $(MAKE) DEST='pagtkdir/' ARCH='pa-gtk.cpp' LIB='-lpthread -lportaudio `pkg-config gtk+-2.0 --cflags --libs`' -f Makefile.compile
+
+pawx :
+ install -d pawxdir
+ $(MAKE) DEST='pawxdir/' ARCH='pa-wx.cpp' LIB='-lpthread -lportaudio `wx-config --cflags --libs`' -f Makefile.compile
+
+module :
+ install -d moduledir
+ $(MAKE) DEST='moduledir/' ARCH='module.cpp' LIB='-fPIC -shared' EXT='.so' -f Makefile.compile
+
+bundle :
+ install -d bundledir
+ $(MAKE) DEST='bundledir/' ARCH='module.cpp' LIB='-fPIC -bundle' EXT='.so' -f Makefile.compile
+
+msp :
+ install -d mspdir
+ $(MAKE) DEST='mspdir/' ARCH='max-msp.cpp' LIB='' -f Makefile.mspcompile
+
+vst :
+ install -d vstdir
+ $(MAKE) DEST='vstdir/' ARCH='vst.cpp' LIB='' -f Makefile.vstcompile
+
+bench :
+ install -d benchdir
+ $(MAKE) DEST='benchdir/' ARCH='bench.cpp' LIB='' -f Makefile.compile
+
+sndfile :
+ install -d sndfiledir
+ $(MAKE) DEST='sndfiledir/' ARCH='sndfile.cpp' LIB='-lsndfile' -f Makefile.compile
+
+plot :
+ install -d plotdir
+ $(MAKE) DEST='plotdir/' ARCH='plot.cpp' LIB='' -f Makefile.compile
+
+matlabplot :
+ install -d matlabplotdir
+ $(MAKE) DEST='matlabplotdir/' ARCH='matlabplot.cpp' LIB='' -f Makefile.compile
+
+q :
+ install -d qdir
+ $(MAKE) DEST='qdir/' ARCH='q.cpp' LIB='' -f Makefile.qcompile
+
+supercollider :
+ install -d supercolliderdir
+ $(MAKE) DEST='supercolliderdir/' ARCH='../architecture/supercollider.cpp' CXXFLAGS='`pkg-config --cflags libscsynth`' LIB='-fPIC -shared' EXT='.so' -f Makefile.sccompile
+
+jackconsole :
+ install -d jackconsoledir
+ $(MAKE) DEST='jackconsoledir/' ARCH='jack-console.cpp' LIB='`pkg-config --cflags --libs jack `' -f Makefile.compile
+
+clean :
+ rm -rf alsagtkdir jackgtkdir alsaqtdir jackqtdir vecalsagtkdir vecjackgtkdir ladspadir jackwxdir ossgtkdir osswxdir pagtkdir pawxdir moduledir bundledir mspdir vstdir benchdir sndfiledir plotdir benchdir supercolliderdir puredatadir qdir plotdir jackconsoledir matlabplotdir *-ps *-svg
+
+
--- /dev/null
+dspsrc := $(wildcard *.dsp)
+cppsrc := $(addprefix $(DEST), $(dspsrc:.dsp=.cpp))
+appl := $(addprefix $(DEST), $(dspsrc:.dsp=$(EXT)))
+
+
+all : $(appl)
+
+
+$(DEST)%$(EXT) : %.dsp
+ faust $(VEC) -a $(ARCH) $< -o $@.cpp
+ $(CXX) -O3 $(CXXFLAGS) $(LIB) $@.cpp -o $@
+
+
+clean :
+ rm -f $(DEST)
--- /dev/null
+DEST := ladspadir/
+dspsrc := $(wildcard *.dsp)
+cppsrc := $(addprefix $(DEST), $(dspsrc:.dsp=.cpp))
+modules := $(addprefix $(DEST), $(dspsrc:%.dsp=%.so))
+os := $(shell uname)
+
+###allcpp: $(cppsrc)
+
+allmodules: $(modules)
+
+$(DEST)%.so: $(DEST)%.cpp
+ifeq ($(os), Darwin)
+ $(CXX) -fPIC -bundle -O3 $(CXXFLAGS) -Dmydsp=$(patsubst %.so,%,$(notdir $@)) $< -o $@
+else
+ $(CXX) -fPIC -shared -O3 $(CXXFLAGS) -Dmydsp=$(patsubst %.so,%,$(notdir $@)) $< -o $@
+endif
+
+$(DEST)%.cpp: %.dsp
+ faust $(VEC) -a ladspa.cpp $< -o $@
+
+clean:
+ rm -rf $(DEST)
--- /dev/null
+dspsrc := $(wildcard *.dsp)
+cppsrc := $(addprefix $(DEST), $(dspsrc:.dsp=.cpp))
+appl := $(addprefix $(DEST), $(dspsrc:.dsp=~.mxo))
+processor := $(shell uname -p)
+
+INC := -I/usr/local/include/c74support/max-includes -I/usr/local/include/c74support/msp-includes
+
+all : $(appl)
+
+$(DEST)%~.mxo : %.dsp Info.plist.template
+ install -d $@/Contents/MacOS
+ faust $(VEC) -a $(ARCH) $< -o $@/$(<:.dsp=.cpp)
+ifeq ($(processor), i386)
+ g++ -arch i386 -fpascal-strings -fasm-blocks -g -O3 $(INC) -c $@/$(<:.dsp=.cpp) -o $@/$(<:.dsp=.i386.o)
+ g++ -framework MaxAPI -framework Carbon -framework MaxAudioAPI -arch i386 -Wl,-Y,1455 -bundle $@/$(<:.dsp=.i386.o) -o $@/$(<:.dsp=.i386~)
+ g++ -arch ppc -fpascal-strings -fasm-blocks -g -O3 $(INC) -c $@/$(<:.dsp=.cpp) -o $@/$(<:.dsp=.ppc.o)
+ g++ -framework Carbon -framework MaxAPI -framework MaxAudioAPI -arch ppc -Wl,-Y,1455 -bundle $@/$(<:.dsp=.ppc.o) -o $@/$(<:.dsp=.ppc~)
+ sed s/FOO/$(<:.dsp=~)/ <Info.plist.template >$@/Contents/Info.plist
+ lipo -create $@/$(<:.dsp=.i386~) $@/$(<:.dsp=.ppc~) -output $@/Contents/MacOS/$(<:.dsp=~)
+ rm -f $@/$(<:.dsp=.ppc~) $@/$(<:.dsp=.ppc.o) $@/$(<:.dsp=.i386.o) $@/$(<:.dsp=.i386~)
+else
+ g++ -arch ppc -fpascal-strings -fasm-blocks -g -O3 $(INC) -c $@/$(<:.dsp=.cpp) -o $@/$(<:.dsp=.ppc.o)
+ g++ -framework Carbon -framework MaxAPI -framework MaxAudioAPI -arch ppc -Wl,-Y,1455 -bundle $@/$(<:.dsp=.ppc.o) -o $@/$(<:.dsp=.ppc~)
+ sed s/FOO/$(<:.dsp=~)/ <Info.plist.template >$@/Contents/Info.plist
+ lipo -create $@/$(<:.dsp=.ppc~) -output $@/Contents/MacOS/$(<:.dsp=~)
+ rm -f $@/$(<:.dsp=.ppc~) $@/$(<:.dsp=.ppc.o)
+endif
+
+Info.plist.template :
+ echo '<?xml version="1.0" encoding="UTF-8"?>' > Info.plist.template
+ echo '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >> Info.plist.template
+ echo '<plist version="1.0">' >> Info.plist.template
+ echo '<dict>' >> Info.plist.template
+ echo ' <key>CFBundleExecutable</key>' >> Info.plist.template
+ echo ' <string>FOO</string>' >> Info.plist.template
+ echo ' <key>CFBundleName</key>' >> Info.plist.template
+ echo ' <string>FOO</string>' >> Info.plist.template
+ echo ' <key>CFBundlePackageType</key>' >> Info.plist.template
+ echo ' <string>iLaX</string>' >> Info.plist.template
+ echo '</dict>' >> Info.plist.template
+ echo '</plist>' >> Info.plist.template
+
+clean :
+ rm -f $(DEST)
--- /dev/null
+DEST := pddir/
+dspsrc := $(wildcard *.dsp)
+cppsrc := $(addprefix $(DEST), $(dspsrc:.dsp=.cpp))
+modules := $(addprefix $(DEST), $(dspsrc:.dsp=~.pd_linux))
+patches := $(addprefix $(DEST), $(dspsrc:.dsp=.pd))
+FAUST2PD := faust2pd
+F2PDFLAGS := -r 10 -s
+
+LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -fPIC \
+ -Wall -W -Wshadow -Wno-unused -Wno-parentheses -Wno-switch $(CFLAGS)
+
+LINUXINCLUDE =
+
+
+###--------------------------------------------
+### Will use faust2pd to create the GUI patches
+### only if it is installed
+
+helper:=$(shell whereis faust2pd)
+
+ifeq ($(helper),faust2pd:)
+ todo:=$(modules)
+else
+ todo:=$(modules) $(patches)
+endif
+
+###--------------------------------------------
+
+
+allmodules: $(todo)
+
+$(DEST)%~.pd_linux: $(DEST)%.cpp
+ $(CXX) $(LINUXCFLAGS) $(LINUXINCLUDE) -shared -Dmydsp=$(patsubst %~.pd_linux,%,$(notdir $@)) $< -o $@
+
+$(DEST)%.cpp: %.dsp
+ faust -a $(ARCH) $< -o $@
+
+$(DEST)%.pd: %.dsp
+ faust -xml $< -o /dev/null
+ $(FAUST2PD) $(F2PDFLAGS) $<.xml
+ mv $(<:.dsp=.pd) $(DEST)
+ rm -f $<.xml
+
+clean:
+ rm -rf $(DEST)
--- /dev/null
+DEST := qdir/
+dspsrc := $(wildcard *.dsp)
+cppsrc := $(addprefix $(DEST), $(dspsrc:.dsp=.cpp))
+modules := $(addprefix $(DEST), $(dspsrc:%.dsp=%.so))
+
+###allcpp: $(cppsrc)
+
+allmodules: $(modules)
+
+$(DEST)%.so: $(DEST)%.cpp
+ $(CXX) -shared -O3 $(CXXFLAGS) -Dmydsp=$(patsubst %.so,%,$(notdir $@)) $< -o $@
+
+$(DEST)%.cpp: %.dsp
+ faust $(VEC) -a q.cpp $< -o $@
+
+clean:
+ rm -rf $(DEST)
--- /dev/null
+###--------------------------------------------
+### DEST : directory where to put binaries
+### ARCH : faust architecture file
+
+system := $(shell uname -s)
+dspsrc := $(wildcard *.dsp)
+cppsrc := $(addprefix $(DEST), $(dspsrc:.dsp=.cpp))
+
+
+### check what type of applications to build (MacOSX Darwin or Linux)
+ifeq ($(system), Darwin)
+appls := $(addprefix $(DEST), $(dspsrc:.dsp=.app))
+else
+appls := $(addprefix $(DEST), $(dspsrc:.dsp=))
+endif
+
+
+TMP = /var/tmp/$(<:.dsp=)
+###--------------------------------------------
+
+
+all : $(appls)
+
+
+### Darwin
+$(DEST)%.app : %.dsp
+ rm -rf $(TMP)
+ install -d $(TMP)
+ faust -a $(ARCH) $< -o $(TMP)/$<.cpp
+ cd $(TMP); qmake -project "INCLUDEPATH+=/usr/local/lib/faust/" "LIBS+=$(LIB)" "HEADERS+=/usr/local/lib/faust/faustqt.h"
+ cd $(TMP); qmake
+ cd $(TMP); xcodebuild -project $(<:.dsp=).xcodeproj
+ mv $(TMP)/build/Default/$(<:.dsp=.app) $@
+ rm -rf $(TMP)
+
+
+### Linux
+$(DEST)% : %.dsp
+ rm -rf $(TMP)
+ install -d $(TMP)
+ faust -a $(ARCH) $< -o $(TMP)/$<.cpp
+ cd $(TMP); qmake -project "INCLUDEPATH+=/usr/local/lib/faust/" "LIBS+=$(LIB)" "HEADERS+=/usr/local/lib/faust/faustqt.h"
+ cd $(TMP); qmake
+ make -C $(TMP)
+ mv $(TMP)/$(<:.dsp=) $@
+ rm -rf $(TMP)
+
+clean:
+ rm -rf $(DEST)
--- /dev/null
+# Makefile to produce supercollider plugins with Faust
+# 'foo.dsp' -> 'foo.so' and 'foo.sc'
+#
+
+dspsrc := $(wildcard *.dsp)
+scfiles := $(addprefix $(DEST), $(dspsrc:.dsp=.sc))
+sofiles := $(addprefix $(DEST), $(dspsrc:.dsp=.so))
+CXXFLAGS := `pkg-config --cflags libscsynth` $(CXXFLAGS)
+LIB := -shared
+
+
+###--------------------------------------------
+### Will use faust2sc to create the class file
+### only if it is installed
+
+helper:=$(shell whereis faust2sc)
+
+ifeq ($(helper),faust2sc:)
+ todo:=$(sofiles)
+else
+ todo:=$(sofiles) $(scfiles)
+endif
+
+
+###--------------------------------------------
+
+
+all : $(todo)
+
+$(DEST)%.cpp: %.dsp
+ faust -a $(ARCH) $< -o $@
+
+$(DEST)%.so: $(DEST)%.cpp
+ $(CXX) $(CXXFLAGS) $(OPTFLAGS) $(LIB) $< -o $@
+
+$(DEST)%.sc : %.dsp.xml
+ faust2sc --prefix=Faust $< --output=$@
+
+%.dsp.xml: %.dsp
+ faust --xml -o /dev/null $<
+
--- /dev/null
+src := $(wildcard *.dsp)
+target := $(src:.dsp=.dsp-svg)
+
+all : $(target)
+
+
+%.dsp-svg : %.dsp
+ faust -svg $< > /dev/null
+
+
+clean :
+ rm -rf $(target)
--- /dev/null
+dspsrc := $(wildcard *.dsp)
+cppsrc := $(addprefix $(DEST), $(dspsrc:.dsp=.cpp))
+appl := $(addprefix $(DEST), $(dspsrc:.dsp=$(EXT)))
+
+# Setup this variable to access the VST SDK files
+vst_sdk := "/Volumes/Document1/Developpement/ProjectsCVS/JackCVS/JackOSX/jackosx/jackplugins/JACK-ASinsert/VST/VSTSDK"
+
+# Setup this variable with the location for the compiled VST plug-ins
+install_plug_ins := "/Library/Audio/Plug-Ins/VST"
+
+all : $(appl)
+
+
+$(DEST)% : %.dsp
+ install -d $@
+ cp -r $(vst_sdk) $@
+ cp -r /usr/local/lib/faust/VST/* $@
+ faust $(VEC) -a $(ARCH) $< -o $@/vst-output.cpp
+ mv $@/vst-output.cpp $@/$(<:.dsp=.cpp)
+ sed -e 's/vst-output.cpp/$(<:.dsp=.cpp)/' $@/VST.xcode/project.pbxproj > $@/VST.xcode/new_project.pbxproj && mv $@/VST.xcode/new_project.pbxproj $@/VST.xcode/project.pbxproj
+ sed -e 's/XXXX/$(<:.dsp=)/' $@/Info.plist > $@/new_Info.plist && mv $@/new_Info.plist $@/Info.plist
+ xcodebuild -project $@/VST.xcode clean
+ xcodebuild -project $@/VST.xcode
+ mv $@/build/FaustVST.vst $@/build/$(<:.dsp=.vst)
+ rm -r $@/build/VST.build
+ install -d $(install_plug_ins)
+ cp -r $@/build/$(<:.dsp=.vst) $(install_plug_ins)
+
+
+clean :
+ rm -f $(DEST)
--- /dev/null
+#ifdef __GNUC__
+
+#define max(x,y) (((x)>(y)) ? (x) : (y))
+#define min(x,y) (((x)<(y)) ? (x) : (y))
+
+// abs is now predefined
+//template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
+
+
+inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
+
+/******************************************************************************
+*******************************************************************************
+
+ VECTOR INTRINSICS
+
+*******************************************************************************
+*******************************************************************************/
+
+//inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
+inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
+
+<<includeIntrinsic>>
+
+/******************************************************************************
+*******************************************************************************
+
+ ABSTRACT USER INTERFACE
+
+*******************************************************************************
+*******************************************************************************/
+
+class UI
+{
+ bool fStopped;
+public:
+
+ UI() : fStopped(false) {}
+ virtual ~UI() {}
+
+ virtual void addButton(char* label, float* zone) = 0;
+ virtual void addToggleButton(char* label, float* zone) = 0;
+ virtual void addCheckButton(char* label, float* zone) = 0;
+ virtual void addVerticalSlider(char* label, float* zone, float init, float min, float max, float step) = 0;
+ virtual void addHorizontalSlider(char* label, float* zone, float init, float min, float max, float step) = 0;
+ virtual void addNumEntry(char* label, float* zone, float init, float min, float max, float step) = 0;
+
+ virtual void openFrameBox(char* label) = 0;
+ virtual void openTabBox(char* label) = 0;
+ virtual void openHorizontalBox(char* label) = 0;
+ virtual void openVerticalBox(char* label) = 0;
+ virtual void closeBox() = 0;
+
+ virtual void run() = 0;
+
+ void stop() { fStopped = true; }
+ bool stopped() { return fStopped; }
+};
+
+
+
+
+/******************************************************************************
+*******************************************************************************
+
+ FAUST DSP
+
+*******************************************************************************
+*******************************************************************************/
+
+
+
+//----------------------------------------------------------------
+// abstract definition of a signal processor
+//----------------------------------------------------------------
+
+class dsp {
+ protected:
+ int fSamplingFreq;
+ public:
+ dsp() {}
+ virtual ~dsp() {}
+
+ virtual int getNumInputs() = 0;
+ virtual int getNumOutputs() = 0;
+ virtual void buildUserInterface(UI* interface) = 0;
+ virtual void init(int samplingRate) = 0;
+ virtual void compute(int len, float** inputs, float** outputs) = 0;
+};
+
+
+//----------------------------------------------------------------------------
+// FAUST generated signal processor
+//----------------------------------------------------------------------------
+
+
+<<includeclass>>
--- /dev/null
+declare name "net-ks";
+declare version "1.0";
+declare author "Juan-Pablo Caceres";
+declare license "MIT";
+declare copyright "(c) Juan-Pablo Caceres 2008";
+
+//-----------------------------------------------------
+// Network-karplus-strong,
+// Based on 'karplus' from Faust Examples
+//-----------------------------------------------------
+
+import("music.lib");
+
+// Excitation
+//-----------
+upfront(x) = (x-x') > 0.0;
+decay(n,x) = x - (x>0.0)/n;
+release(n) = + ~ decay(n);
+trigger(n) = upfront : release(n) : >(0.0);
+
+// Filters
+//--------
+// Average LowPass Filter
+av_lowpass(x) = (x+x')/2;
+
+process = _ ,
+ ( noise * 0.9 :
+ vgroup("excitator", *(button("play") : trigger(300))) )
+ :> av_lowpass;
--- /dev/null
+# Doxyfile 1.5.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = JackTrip
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ./WWW/
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
+# and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+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
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ./src ./documentation
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = ./documentation/img
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER = ./documentation/html_footer.html
+
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to FRAME, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature. Other possible values
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
+# and Class Hiererachy pages using a tree view instead of an ordered list;
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
+# disables this behavior completely. For backwards compatibility with previous
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
+# respectively.
+
+GENERATE_TREEVIEW = NONE
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = Sans
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is enabled by default, which results in a transparent
+# background. Warning: Depending on the platform used, enabling this option
+# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
+# become hard to read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
--- /dev/null
+//*****************************************************************
+/*
+ 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 DataProtocol.cpp
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+#include "DataProtocol.h"
+#include "jacktrip_globals.h"
+#include "JackTrip.h"
+
+#include <iostream>
+#include <cstdlib>
+
+#include <QHostInfo>
+#include <QHostAddress>
+
+using std::cout; using std::endl;
+
+
+//*******************************************************************************
+DataProtocol::DataProtocol(JackTrip* jacktrip,
+ const runModeT runmode,
+ int /*bind_port*/, int /*peer_port*/) :
+ mStopped(false), mHasPacketsToReceive(false), mRunMode(runmode), mJackTrip(jacktrip)
+{}
+
+
+//*******************************************************************************
+DataProtocol::~DataProtocol()
+{}
--- /dev/null
+//*****************************************************************
+/*
+ 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 DataProtocol.h
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+#ifndef __DATAPROTOCOL_H__
+#define __DATAPROTOCOL_H__
+
+//#include <sys/socket.h> //basic socket definitions
+#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 <QThread>
+#include <QHostAddress>
+
+class JackTrip; // forward declaration
+
+
+/** \brief Base class that defines the transmission protocol.
+ *
+ * This base class defines most of the common method to setup and connect
+ * sockets using the individual protocols (UDP, TCP, SCTP, etc).
+ *
+ * The class has to be constructed using one of two modes (runModeT):\n
+ * - SENDER
+ * - RECEIVER
+ *
+ * This has to be specified as a constructor argument. When using, create two instances
+ * of the class, one to receive and one to send packets. Each instance will run on a
+ * separate thread.
+ *
+ * Redundancy and forward error correction should be implemented on each
+ * Transport protocol, cause they depend on the protocol itself
+ *
+ * \todo This Class should contain definition of jacktrip header and basic funcionality to obtain
+ * local machine IPs and maybe functions to manipulate IPs.
+ * Redundancy and forward error correction should be implemented on each
+ * Transport protocol, cause they depend on the protocol itself
+ *
+ * \todo The transport protocol itself has to be implemented subclassing this class, i.e.,
+ * using a TCP or UDP protocol.
+ *
+ * Even if the underlined transmission protocol is stream oriented (as in TCP),
+ * we send packets that are the size of the audio processing buffer.
+ * Use AudioInterface::getBufferSize to obtain this value.
+ *
+ * Each transmission (i.e., inputs and outputs) run on its own thread.
+ */
+class DataProtocol : public QThread
+{
+public:
+
+ //----------ENUMS------------------------------------------
+ /// \brief Enum to define packet header types
+ enum packetHeaderTypeT {
+ DEFAULT, ///< Default application header
+ JAMLINK, ///< Header to use with Jamlinks
+ EMPTY ///< Empty Header
+ };
+
+ /// \brief Enum to define class modes, SENDER or RECEIVER
+ enum runModeT {
+ SENDER, ///< Set class as a Sender (send packets)
+ RECEIVER ///< Set class as a Receiver (receives packets)
+ };
+ //---------------------------------------------------------
+
+
+ /** \brief The class constructor
+ * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
+ * \param runmode Sets the run mode, use either DataProtocol::SENDER or
+ * DataProtocol::RECEIVER
+ * \param headertype packetHeaderTypeT header type to use for packets
+ * \param bind_port Port number to bind for this socket (this is the receive or send port depending on the runmode)
+ * \param peer_port Peer port number (this is the receive or send port depending on the runmode)
+ */
+ DataProtocol(JackTrip* jacktrip,
+ const runModeT runmode,
+ int bind_port, int peer_port);
+
+ /// \brief The class destructor
+ virtual ~DataProtocol();
+
+ /** \brief Implements the thread loop
+ *
+ * Depending on the runmode, with will run a DataProtocol::SENDER thread or
+ * DataProtocol::RECEIVER thread
+ */
+ virtual void run() = 0;
+
+ /// \brief Stops the execution of the Thread
+ virtual void stop() { 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; };
+
+ /** \brief Get the size of the audio part of the packets
+ * \return size_bytes Size in bytes
+ */
+ size_t getAudioPacketSizeInBites() { return(mAudioPacketSize); };
+
+ /** \brief Set the peer address
+ * \param peerHostOrIP IPv4 number or host name
+ * \todo implement here instead of in the subclass UDP
+ */
+ virtual void setPeerAddress(const char* peerHostOrIP) = 0;
+
+ /** \brief Set the peer incomming (receiving) port number
+ * \param port Port number
+ * \todo implement here instead of in the subclass UDP
+ */
+ virtual void setPeerPort(int port) = 0;
+
+ //virtual void getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
+ // uint16_t& port) = 0;
+
+protected:
+
+ /** \brief Get the Run Mode of the object
+ * \return SENDER or RECEIVER
+ */
+ runModeT getRunMode() const { return mRunMode; };
+
+ /// Boolean stop the execution of the thread
+ volatile bool mStopped;
+ /// Boolean to indicate if the RECEIVER is waiting to obtain peer address
+ volatile bool mHasPeerAddress;
+ /// Boolean that indicates if a packet was received
+ volatile bool mHasPacketsToReceive;
+
+
+private:
+
+ int mLocalPort; ///< Local Port number to Bind
+ int mPeerPort; ///< Peer Port number to Bind
+ const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
+
+ struct sockaddr_in mLocalIPv4Addr; ///< Local IPv4 Address struct
+ struct sockaddr_in mPeerIPv4Addr; ///< Peer IPv4 Address struct
+
+ /// Number of clients running to check for ports already used
+ /// \note Unimplemented, try to find another way to check for used ports
+ static int sClientsRunning;
+
+ size_t mAudioPacketSize; ///< Packet audio part size
+
+
+ /// \todo check a better way to access the header from the subclasses
+protected:
+ //PacketHeader* mHeader; ///< Packet Header
+ JackTrip* mJackTrip; ///< JackTrip mediator class
+
+};
+
+#endif
--- /dev/null
+//*****************************************************************
+/*
+ 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 DataProtocol.cpp
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+#include "DataProtocol.h"
+#include "jacktrip_globals.h"
+#include "JackAudioInterface.h"
+#include "PacketHeader.h"
+
+#include <iostream>
+#include <cstdlib>
+
+#include <QHostInfo>
+#include <QHostAddress>
+
+using std::cout; using std::endl;
+
+//*******************************************************************************
+DataProtocol::DataProtocol(const runModeT runmode,
+ const packetHeaderTypeT headertype) :
+ mRunMode(runmode), mStopped(false), mHasPacketsToReceive(false), mHeader(NULL)
+{
+ //--------PROTOTYPE-------------------------
+ if ( headertype == DEFAULT ) {
+ mHeader = new DefaultHeader;
+ }
+ else if ( headertype == JAMLINK ) {
+ mHeader = new JamLinkHeader;
+ }
+ //------------------------------------------
+
+ // Base ports gInputPort_0 and gOutputPort_0defined at globals.h
+ if (mRunMode == RECEIVER) {
+ mLocalPort = gInputPort_0;
+ mPeerPort = gOutputPort_0;
+ }
+ else if (mRunMode == SENDER) {
+ mLocalPort = gOutputPort_0;
+ mPeerPort = gInputPort_0;
+ }
+
+ this->setLocalIPv4Address();
+}
+
+
+//*******************************************************************************
+DataProtocol::~DataProtocol()
+{
+ delete mHeader;
+}
+
+
+//*******************************************************************************
+void DataProtocol::stop()
+{
+ mStopped = true;
+}
+
+
+//*******************************************************************************
+void DataProtocol::setLocalIPv4Address()
+{
+ bzero(&mLocalIPv4Addr, sizeof(mLocalIPv4Addr));
+ mLocalIPv4Addr.sin_family = AF_INET;//AF_INET: IPv4 Protocol
+ mLocalIPv4Addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY: let the kernel decide the active address
+ mLocalIPv4Addr.sin_port = htons(mLocalPort);//set local port
+ //std::cout << "mLocalPort = " << mLocalPort << std::endl;
+}
+
+
+//*******************************************************************************
+void DataProtocol::setPeerIPv4Address(const char* peerHostOrIP)
+{
+ const char* peerAddress; // dotted decimal address to use in the struct below
+
+ /// \todo Improve this to make it work also with local ip numbers, in a LAN,
+ /// that don't have an assigned host name
+ /*
+ // Resolve Peer IPv4 with either doted integer IP or hostname
+ //----------------------------------------------------------
+ std::cout << "Resolving Peer IPv4 address..." << std::endl;
+ QHostInfo info = QHostInfo::fromName(peerHostOrIP);
+ if ( !info.addresses().isEmpty() ) {
+ std::cout << "Peer Address Found" << std::endl;
+ QHostAddress address = info.addresses().first(); // use the first address in list
+ peerAddress = address.toString().toLatin1();
+ }
+ else {
+ std::cerr << "ERROR: Could not set Peer IP Address" << std::endl;
+ std::cerr << "Check that it's public or that the hostname exists" << std::endl;
+ std::exit(1);
+ }
+ */
+
+ // temporary implementation to make this work
+ /// \todo change this
+ peerAddress = peerHostOrIP;
+
+ // Set the Peer IPv4 Address struct
+ //---------------------------------
+ bzero(&mPeerIPv4Addr, sizeof(mPeerIPv4Addr));
+ mPeerIPv4Addr.sin_family = AF_INET;//AF_INET: IPv4 Protocol
+ mPeerIPv4Addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY: let the kernel decide the active address
+ mPeerIPv4Addr.sin_port = htons(mPeerPort);//set Peer port
+ //std::cout << "mPeerPort = " << mPeerPort << std::endl;
+ int nPeer = inet_pton(AF_INET, peerAddress, &mPeerIPv4Addr.sin_addr);
+ if ( nPeer == 1 ) {
+ std::cout << "Successful Set Peer Address" << std::endl;
+ }
+ else if ( nPeer == 0 ) {
+ std::cout << "Error: Incorrect presentation format for address" << std::endl;
+ std::exit(1);
+ }
+ else {
+ std::cout << "Error: Could not set Peer Address" << std::endl;
+ std::exit(1);
+ }
+
+}
+
+
+//*******************************************************************************
+void DataProtocol::setRingBuffer(std::tr1::shared_ptr<RingBuffer> RingBuffer)
+{
+ mRingBuffer = RingBuffer;
+}
+
+
+//*******************************************************************************
+void DataProtocol::run()
+{
+ std::cout << "Running DataProtocol Thread" << std::endl;
+ std::cout << gPrintSeparator << std::endl;
+ size_t packet_size = getAudioPacketSize();
+ int8_t packet[packet_size];
+
+ switch ( mRunMode )
+ {
+ case RECEIVER :
+ //-----------------------------------------------------------------------------------
+ // Wait for the first packet to be ready and obtain address
+ // from that packet
+ /// \todo here is the place to read the datagram and check if the settings match
+ /// the local ones. Extract this information from the header
+ std::cout << "Waiting for Peer..." << std::endl;
+ this->receivePacket( (char*) packet, packet_size); // This blocks waiting for the first packet
+ std::cout << "Received Connection for Peer!" << std::endl;
+
+ while ( !mStopped )
+ {
+ //std::cout << "RECEIVING PACKETS" << std::endl;
+ /// \todo Set a timer to report packats arriving too late
+ //std::cout << "RECIEVING THREAD" << std::endl;
+
+ this->receivePacket( (char*) packet, packet_size);
+ /// \todo Change this to match buffer size
+ //std::cout << "PACKET RECIEVED" << std::endl;
+ mRingBuffer->insertSlotBlocking(packet);
+ //std::cout << buf << std::endl;
+ }
+ break;
+
+
+ case SENDER :
+ //-----------------------------------------------------------------------------------
+ while ( !mStopped )
+ {
+ //std::cout << "SENDING PACKETS --------------------------" << std::endl;
+ /// \todo This should be blocking, since we don't want to send trash
+ mRingBuffer->readSlotBlocking(packet);
+ //std::cout << "SENDING PACKETS" << std::endl;
+ this->sendPacket( (char*) packet, packet_size);
+ //std::cout << "SENDING PACKETS DONE!!!" << std::endl;
+ //this->sendPacket( sendtest, 64);
+ }
+ break;
+ }
+}
+
+void DataProtocol::setAudioPacketSize(size_t size_bytes)
+{
+ mAudioPacketSize = size_bytes;
+}
+
+
+size_t DataProtocol::getAudioPacketSize()
+{
+ return(mAudioPacketSize);
+}
--- /dev/null
+//*****************************************************************
+/*
+ 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 DataProtocol.h
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+#ifndef __DATAPROTOCOL_H__
+#define __DATAPROTOCOL_H__
+
+//#include <sys/socket.h> //basic socket definitions
+#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 <QThread>
+
+#include "RingBuffer.h"
+//#include "PacketHeader.h"
+class PacketHeader; // forward declaration
+
+
+/** \brief Base class that defines the transmission protocol.
+ *
+ * This base class defines most of the common method to setup and connect
+ * sockets using the individual protocols (UDP, TCP, SCTP, etc).
+ *
+ * The class has to be constructed using one of two modes (runModeT):\n
+ * - SENDER
+ * - RECEIVER
+ *
+ * This has to be specified as a constructor argument. When using, create two instances
+ * of the class, one to receive and one to send packets. Each instance will run on a
+ * separate thread.
+ *
+ * Redundancy and forward error correction should be implemented on each
+ * Transport protocol, cause they depend on the protocol itself
+ *
+ * \todo This Class should contain definition of jacktrip header and basic funcionality to obtain
+ * local machine IPs and maybe functions to manipulate IPs.
+ * Redundancy and forward error correction should be implemented on each
+ * Transport protocol, cause they depend on the protocol itself
+ *
+ * \todo The transport protocol itself has to be implemented subclassing this class, i.e.,
+ * using a TCP or UDP protocol.
+ *
+ * Even if the underlined transmission protocol is stream oriented (as in TCP),
+ * we send packets that are the size of the audio processing buffer.
+ * Use AudioInterface::getBufferSize to obtain this value.
+ *
+ * Each transmission (i.e., inputs and outputs) run on its own thread.
+ */
+class DataProtocol : public QThread
+{
+public:
+
+ /// \brief Enum to define packet header types
+ enum packetHeaderTypeT {
+ DEFAULT, ///< Default application header
+ JAMLINK ///< Header to use with Jamlinks
+ };
+
+ /// \brief Enum to define class modes, SENDER or RECEIVER
+ enum runModeT {
+ SENDER, ///< Set class as a Sender (send packets)
+ RECEIVER ///< Set class as a Receiver (receives packets)
+ };
+
+
+ /** \brief The class constructor
+ * \param runmode Sets the run mode, use either SENDER or RECEIVER
+ */
+ DataProtocol(const runModeT runmode,
+ const packetHeaderTypeT headertype = DEFAULT);
+
+ /// \brief The class destructor
+ virtual ~DataProtocol();
+
+ /** \brief Sets the peer (remote) IPv4 address struct
+ * \param peerHostOrIP Either an IPv4 dotted integer number or a hostname
+ */
+ virtual void setPeerIPv4Address(const char* peerHostOrIP);
+
+ /** \brief Receive a packet from the UDPSocket
+ *
+ * This method has to be implemented in the sub-classes
+ * \param buf Location at which to store the buffer
+ * \param n size of packet to receive in bytes
+ * \return number of bytes read, -1 on error
+ */
+ virtual size_t receivePacket(char* buf, size_t n) = 0;
+
+ /** \brief Sends a packet
+ *
+ * This method has to be implemented in the sub-classes
+ * \param buff Buffer to send
+ * \param n size of packet to receive in bytes
+ * \return number of bytes read, -1 on error
+ */
+ virtual size_t sendPacket(const char* buff, size_t n) = 0;
+
+ /** \brief Implements the thread loop
+ *
+ * Depending on the runmode, with will run a RECEIVE thread or
+ * SEND thread
+ */
+ virtual void run();
+
+ /** \brief Set the pointer to the RingBuffer that'll be use to read
+ * or write
+ */
+ void setRingBuffer(std::tr1::shared_ptr<RingBuffer> RingBuffer);
+
+ /// \brief Stops the execution of the Thread
+ void stop();
+
+ /** \brief Sets the size of the audio part of the packets
+ * \param size_bytes Size in bytes
+ */
+ void setAudioPacketSize(size_t size_bytes);
+
+ /** \brief Get the size of the audio part of the packets
+ * \return size_bytes Size in bytes
+ */
+ size_t getAudioPacketSize();
+
+ //virtual void getIPAddressFromFirstPacket() = 0;
+
+
+protected:
+
+ /** \brief Sets the local IPv4 address struct
+ *
+ * It uses the default active device.
+ */
+ virtual void setLocalIPv4Address();
+
+ /** \brief Get the Run Mode of the object
+ * \return SENDER or RECEIVER
+ */
+ runModeT getRunMode() const { return mRunMode; };
+
+ /** \brief Returns the Local machine IPv4 socket address stuct
+ * \return Socket address stuct
+ */
+ const sockaddr_in& getLocalIPv4AddressStruct() const { return mLocalIPv4Addr; };
+
+ /** \brief Returns the Peer IPv4 socket address stuct
+ * \return Socket address stuct
+ */
+ const sockaddr_in& getPeerIPv4AddressStruct() const { return mPeerIPv4Addr; };
+
+
+private:
+
+ int mLocalPort; ///< Local Port number to Bind
+ int mPeerPort; ///< Peer Port number to Bind
+ const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
+
+ struct sockaddr_in mLocalIPv4Addr; ///< Local IPv4 Address struct
+ struct sockaddr_in mPeerIPv4Addr; ///< Peer IPv4 Address struct
+
+ /// Smart Pointer to RingBuffer to read (for SENDER) or write (for RECEIVER)
+ std::tr1::shared_ptr<RingBuffer> mRingBuffer;
+
+ /// Boolean stop the execution of the thread
+ volatile bool mStopped;
+ /// Boolean to indicate if the RECEIVER is waiting to obtain peer address
+ volatile bool mHasPeerAddress;
+ /// Boolean that indicates if a packet was received
+ volatile bool mHasPacketsToReceive;
+
+ /// Number of clients running to check for ports already used
+ /// \note Unimplemented, try to find another way to check for used ports
+ static int sClientsRunning;
+
+ size_t mAudioPacketSize; ///< Packet audio part size
+
+ PacketHeader* mHeader; ///< Packet Header
+};
+
+#endif
--- /dev/null
+//*****************************************************************
+/*
+ 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 JackAudioInterface.cpp
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+#include "JackAudioInterface.h"
+#include "jacktrip_globals.h"
+#include "JackTrip.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <cmath>
+#include <stdexcept>
+
+///************PROTORYPE FOR CELT**************************
+//#include <celt/celt.h>
+//#include <celt/celt_header.h>
+//#include <celt/celt_types.h>
+///********************************************************
+
+#include <QTextStream>
+#include <QMutexLocker>
+
+using std::cout; using std::endl;
+
+
+// sJackMutex definition
+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();
+}
+
+
+//*******************************************************************************
+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();
+ setProcessCallback();
+}
+
+
+//*******************************************************************************
+void JackAudioInterface::setupClient()
+{
+ const char* client_name = mClientName;
+ const char* server_name = NULL;
+ jack_options_t options = JackNoStartServer;
+ jack_status_t status;
+
+ // Try to connect to the server
+ /// \todo Write better warning messages. This following line displays very
+ /// verbose message, check how to desable them.
+ {
+ QMutexLocker locker(&sJackMutex);
+ mClient = jack_client_open (client_name, options, &status, server_name);
+ }
+
+ if (mClient == NULL) {
+ //fprintf (stderr, "jack_client_open() failed, "
+ // "status = 0x%2.0x\n", status);
+ if (status & JackServerFailed) {
+ fprintf (stderr, "Unable to connect to JACK server\n");
+ //std::cerr << "ERROR: Maybe the JACK server is not running?" << std::endl;
+ //std::cerr << gPrintSeparator << std::endl;
+ }
+ //std::exit(1);
+ throw std::runtime_error("Maybe the JACK server is not running?");
+ }
+ if (status & JackServerStarted) {
+ fprintf (stderr, "JACK server started\n");
+ }
+ if (status & JackNameNotUnique) {
+ client_name = jack_get_client_name(mClient);
+ fprintf (stderr, "unique name `%s' assigned\n", client_name);
+ }
+
+ // Set function to call if Jack shuts down
+ jack_on_shutdown (mClient, this->jackShutdown, 0);
+
+ // 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);
+ }
+}
+
+
+//*******************************************************************************
+void JackAudioInterface::createChannels()
+{
+ //Create Input Ports
+ mInPorts.resize(mNumInChans);
+ for (int i = 0; i < mNumInChans; i++)
+ {
+ QString inName;
+ QTextStream (&inName) << "send_" << i+1;
+ mInPorts[i] = jack_port_register (mClient, inName.toLatin1(),
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput, 0);
+ }
+
+ //Create Output Ports
+ mOutPorts.resize(mNumOutChans);
+ for (int i = 0; i < mNumInChans; i++)
+ {
+ QString outName;
+ QTextStream (&outName) << "receive_" << i+1;
+ mOutPorts[i] = jack_port_register (mClient, outName.toLatin1(),
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
+ }
+}
+
+
+//*******************************************************************************
+uint32_t JackAudioInterface::getSampleRate() const
+{
+ return jack_get_sample_rate(mClient);
+}
+
+
+//*******************************************************************************
+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);
+}
+
+
+//*******************************************************************************
+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);
+}
+
+//*******************************************************************************
+void JackAudioInterface::setProcessCallback()
+{
+ std::cout << "Setting JACK Process Callback..." << std::endl;
+ if ( int code =
+ jack_set_process_callback(mClient, JackAudioInterface::wrapperProcessCallback, this)
+ )
+ {
+ //std::cerr << "Could not set the process callback" << std::endl;
+ //return(code);
+ (void) code; // to avoid compiler warnings
+ throw std::runtime_error("Could not set the Jack process callback");
+ //std::exit(1);
+ }
+ std::cout << "SUCCESS" << std::endl;
+ std::cout << gPrintSeparator << std::endl;
+ //return(0);
+}
+
+
+//*******************************************************************************
+int JackAudioInterface::startProcess() const
+{
+ //Tell the JACK server that we are ready to roll. Our
+ //process() callback will start running now.
+ if ( int code = (jack_activate(mClient)) )
+ {
+ std::cerr << "Cannot activate client" << std::endl;
+ return(code);
+ }
+ return(0);
+}
+
+
+//*******************************************************************************
+int JackAudioInterface::stopProcess() const
+{
+ QMutexLocker locker(&sJackMutex);
+ if ( int code = (jack_client_close(mClient)) )
+ {
+ std::cerr << "Cannot disconnect client" << std::endl;
+ return(code);
+ }
+ return(0);
+}
+
+
+//*******************************************************************************
+void JackAudioInterface::jackShutdown (void*)
+{
+ //std::cout << "The Jack Server was shut down!" << std::endl;
+ throw std::runtime_error("The Jack Server was shut down!");
+ //std::cout << "Exiting program..." << std::endl;
+ //std::exit(1);
+}
+
+
+//*******************************************************************************
+/*
+void JackAudioInterface::setRingBuffers
+(const std::tr1::shared_ptr<RingBuffer> InRingBuffer,
+ const std::tr1::shared_ptr<RingBuffer> OutRingBuffer)
+{
+ mInRingBuffer = InRingBuffer;
+ mOutRingBuffer = OutRingBuffer;
+}
+*/
+
+
+//*******************************************************************************
+// 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()
+{
+ /// \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::computeNetworkProcessToNetwork()
+{
+ // 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 );
+}
+
+
+//*******************************************************************************
+int JackAudioInterface::processCallback(jack_nframes_t nframes)
+{
+ // Get input and output buffers from JACK
+ //-------------------------------------------------------------------
+ for (int i = 0; i < mNumInChans; i++) {
+ // Input Ports are READ ONLY
+ mInBuffer[i] = (sample_t*) jack_port_get_buffer(mInPorts[i], nframes);
+ }
+ for (int i = 0; i < mNumOutChans; i++) {
+ // Output Ports are WRITABLE
+ mOutBuffer[i] = (sample_t*) jack_port_get_buffer(mOutPorts[i], nframes);
+ }
+ //-------------------------------------------------------------------
+ // TEST: Loopback
+ // To test, uncomment and send audio to client input. The same audio
+ // should come out as output in the first channel
+ //memcpy (mOutBuffer[0], mInBuffer[0], sizeof(sample_t) * nframes);
+ //memcpy (mOutBuffer[1], mInBuffer[1], sizeof(sample_t) * nframes);
+ //-------------------------------------------------------------------
+
+ // Allocate the Process Callback
+ //-------------------------------------------------------------------
+ // 1) First, process incoming packets
+ // ----------------------------------
+ computeNetworkProcessFromNetwork();
+
+
+ // 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) * nframes);
+ std::memcpy(mInProcessBuffer[i], mOutBuffer[i], sizeof(sample_t) * nframes);
+ }
+ for (int i = 0; i < mNumOutChans; i++) {
+ std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * nframes);
+ }
+
+ for (int i = 0; i < mProcessPlugins.size(); i++) {
+ //mProcessPlugins[i]->compute(nframes, mOutBuffer.data(), mInBuffer.data());
+ mProcessPlugins[i]->compute(nframes, mInProcessBuffer.data(), mOutProcessBuffer.data());
+ }
+
+
+ // 3) Finally, send packets to peer
+ // --------------------------------
+ computeNetworkProcessToNetwork();
+
+
+ ///************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, );
+
+ ///********************************************************
+ ///********************************************************
+
+
+
+ return 0;
+}
+
+
+//*******************************************************************************
+int JackAudioInterface::wrapperProcessCallback(jack_nframes_t nframes, void *arg)
+{
+ return static_cast<JackAudioInterface*>(arg)->processCallback(nframes);
+}
+
+
+//*******************************************************************************
+// 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)
+{
+ 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 JackAudioInterface::fromBitToSampleConversion(const int8_t* const input,
+ sample_t* output,
+ const 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 JackAudioInterface::appendProcessPlugin(const std::tr1::shared_ptr<ProcessPlugin> plugin)
+void JackAudioInterface::appendProcessPlugin(ProcessPlugin* plugin)
+{
+ /// \todo check that channels in ProcessPlugins are less or same that jack channels
+ 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);
+ }
+}
--- /dev/null
+//*****************************************************************
+/*
+ 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 JackAudioInterface.h
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+
+#ifndef __JACKAUDIOINTERFACE_H__
+#define __JACKAUDIOINTERFACE_H__
+
+#include <iostream>
+#include <tr1/memory> //for shared_ptr
+#include <functional> //for mem_fun_ref
+#include <jack/jack.h>
+
+#include <QVector>
+#include <QVarLengthArray>
+#include <QMutex>
+
+
+#include "jacktrip_types.h"
+#include "ProcessPlugin.h"
+
+class JackTrip; //forward declaration
+
+
+/** \brief Class that provides an interface with the Jack Audio Server
+ *
+ * \todo implement srate_callback
+ * \todo automatically starts jack with buffer and sample rate settings specified by the user
+ */
+class JackAudioInterface
+{
+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
+ * \param NumOutChans Number of Output Channels
+ * \param AudioBitResolution Audio Sample Resolutions in bits
+ * \param ClientName Client name in Jack
+ */
+ JackAudioInterface(JackTrip* jacktrip,
+ int NumInChans, int NumOutChans,
+ audioBitResolutionT AudioBitResolution = 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 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;
+
+ /** \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);
+
+ /// \brief Connect the default ports, capture to sends, and receives to playback
+ void connectDefaultPorts();
+
+ /// \brief Set Client Name to something different that the default (JackTrip)
+ void setClientName(const char* ClientName)
+ { mClientName = ClientName; }
+
+private:
+
+ /** \brief Private method to setup a client of the Jack server.
+ * \exception std::runtime_error Can't start Jack
+ *
+ * This method is called by the class constructors. It does the following:\n
+ * - Connects to the JACK server
+ * - Sets the shutdown process callback
+ * - Creates the appropriate number of input and output channels
+ */
+ void setupClient();
+
+ /** \brief Creates input and output channels in the Jack client
+ */
+ void createChannels();
+
+ /** \brief JACK calls this shutdown_callback if the server ever shuts down or
+ * 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
+ * of the type JackProcessCallback, which is defined as:\n
+ * <tt>typedef int(* JackProcessCallback)(jack_nframes_t nframes, void *arg)</tt>
+ * \n
+ * See
+ * http://jackaudio.org/files/docs/html/types_8h.html#4923142208a8e7dacf00ca7a10681d2b
+ * for more details
+ */
+ int processCallback(jack_nframes_t nframes);
+
+ /** \brief Wrapper to cast the member processCallback to a static function pointer
+ * that can be used with <tt>jack_set_process_callback</tt>
+ *
+ * <tt>jack_set_process_callback</tt> needs a static member function pointer. A normal
+ * member function won't work because a <b><i>this</i></b> pointer is passed under the scenes.
+ * That's why we
+ * need to cast the member funcion processCallback to the static function
+ * wrapperProcessCallback. The callback is then set as:\n
+ * <tt>jack_set_process_callback(mClient, JackAudioInterface::wrapperProcessCallback,
+ * this)</tt>
+ */
+ // reference : http://article.gmane.org/gmane.comp.audio.jackit/12873
+ static int wrapperProcessCallback(jack_nframes_t nframes, void *arg) ;
+
+
+ int mNumInChans;///< Number of Input Channels
+ int mNumOutChans; ///< Number of Output Channels
+ int mNumFrames; ///< Buffer block size, in samples
+ int mAudioBitResolution; ///< Bit resolution in audio samples
+ 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
+};
+
+
+#endif
--- /dev/null
+//*****************************************************************
+/*
+ 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 JackTrip.cpp
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+#include "JackTrip.h"
+#include "UdpDataProtocol.h"
+#include "RingBufferWavetable.h"
+#include "jacktrip_globals.h"
+
+#include <iostream>
+//#include <unistd.h> // for usleep, sleep
+#include <cstdlib>
+#include <stdexcept>
+
+#include <QHostAddress>
+#include <QThread>
+
+using std::cout; using std::endl;
+
+
+
+//*******************************************************************************
+JackTrip::JackTrip(jacktripModeT JacktripMode,
+ dataProtocolT DataProtocolType,
+ int NumChans,
+ int BufferQueueLength,
+ unsigned int redundancy,
+ JackAudioInterface::audioBitResolutionT AudioBitResolution,
+ DataProtocol::packetHeaderTypeT PacketHeaderType,
+ underrunModeT UnderRunMode,
+ int receiver_bind_port, int sender_bind_port,
+ int receiver_peer_port, int sender_peer_port) :
+ mJackTripMode(JacktripMode),
+ mDataProtocol(DataProtocolType),
+ mPacketHeaderType(PacketHeaderType),
+ mNumChans(NumChans),
+ mBufferQueueLength(BufferQueueLength),
+ mSampleRate(0),
+ mAudioBufferSize(0),
+ mAudioBitResolution(AudioBitResolution),
+ mDataProtocolSender(NULL),
+ mDataProtocolReceiver(NULL),
+ mJackAudio(NULL),
+ mPacketHeader(NULL),
+ mUnderRunMode(UnderRunMode),
+ mSendRingBuffer(NULL),
+ mReceiveRingBuffer(NULL),
+ mReceiverBindPort(receiver_bind_port),
+ mSenderPeerPort(sender_peer_port),
+ mSenderBindPort(sender_bind_port),
+ mReceiverPeerPort(receiver_peer_port),
+ mRedundancy(redundancy),
+ mJackClientName("JackTrip")
+{}
+
+
+//*******************************************************************************
+JackTrip::~JackTrip()
+{
+ delete mDataProtocolSender;
+ delete mDataProtocolReceiver;
+ delete mJackAudio;
+ delete mPacketHeader;
+ delete mSendRingBuffer;
+ delete mReceiveRingBuffer;
+}
+
+
+//*******************************************************************************
+void JackTrip::setupJackAudio()
+{
+ // Create JackAudioInterface Client Object
+ mJackAudio = new JackAudioInterface(this, mNumChans, mNumChans, mAudioBitResolution);
+ mJackAudio->setClientName(mJackClientName);
+ mJackAudio->setup();
+ mSampleRate = mJackAudio->getSampleRate();
+ 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 << gPrintSeparator << std::endl;
+ cout << "The Number of Channels is: " << mJackAudio->getNumInputChannels() << endl;
+ std::cout << gPrintSeparator << std::endl;
+ QThread::usleep(100);
+}
+
+
+//*******************************************************************************
+void JackTrip::setupDataProtocol()
+{
+ // Create DataProtocol Objects
+ switch (mDataProtocol) {
+ case UDP:
+ std::cout << "Using UDP Protocol" << std::endl;
+ std::cout << gPrintSeparator << std::endl;
+ QThread::usleep(100);
+ mDataProtocolSender = new UdpDataProtocol(this, DataProtocol::SENDER,
+ //mSenderPeerPort, mSenderBindPort,
+ mSenderBindPort, mSenderPeerPort,
+ mRedundancy);
+ mDataProtocolReceiver = new UdpDataProtocol(this, DataProtocol::RECEIVER,
+ mReceiverBindPort, mReceiverPeerPort,
+ mRedundancy);
+ break;
+ case TCP:
+ throw std::invalid_argument("TCP Protocol is not implemented");
+ break;
+ case SCTP:
+ throw std::invalid_argument("SCTP Protocol is not implemented");
+ break;
+ default:
+ throw std::invalid_argument("Protocol not defined or unimplemented");
+ break;
+ }
+
+ // Set Audio Packet Size
+ mDataProtocolSender->setAudioPacketSize
+ (mJackAudio->getSizeInBytesPerChannel() * mNumChans);
+ mDataProtocolReceiver->setAudioPacketSize
+ (mJackAudio->getSizeInBytesPerChannel() * mNumChans);
+}
+
+
+//*******************************************************************************
+void JackTrip::setupRingBuffers()
+{
+ // Create RingBuffers with the apprioprate size
+ /// \todo Make all this operations cleaner
+ switch (mUnderRunMode) {
+ case WAVETABLE:
+ mSendRingBuffer = new RingBufferWavetable(mJackAudio->getSizeInBytesPerChannel() * mNumChans,
+ gDefaultOutputQueueLength);
+ mReceiveRingBuffer = new RingBufferWavetable(mJackAudio->getSizeInBytesPerChannel() * mNumChans,
+ mBufferQueueLength);
+
+ break;
+ case ZEROS:
+ mSendRingBuffer = new RingBuffer(mJackAudio->getSizeInBytesPerChannel() * mNumChans,
+ gDefaultOutputQueueLength);
+ mReceiveRingBuffer = new RingBuffer(mJackAudio->getSizeInBytesPerChannel() * mNumChans,
+ mBufferQueueLength);
+ break;
+ default:
+ throw std::invalid_argument("Underrun Mode undefined");
+ break;
+ }
+}
+
+
+//*******************************************************************************
+void JackTrip::setPeerAddress(const char* PeerHostOrIP)
+{
+ mPeerAddress = PeerHostOrIP;
+}
+
+
+//*******************************************************************************
+void JackTrip::appendProcessPlugin(ProcessPlugin* plugin)
+{
+ mProcessPlugins.append(plugin);
+ //mJackAudio->appendProcessPlugin(plugin);
+}
+
+
+//*******************************************************************************
+void JackTrip::start()
+{
+ // Check if ports are already binded by another process on this machine
+ checkIfPortIsBinded(mReceiverBindPort);
+ checkIfPortIsBinded(mSenderBindPort);
+
+ // Set all classes and parameters
+ setupJackAudio();
+ createHeader(mPacketHeaderType);
+ setupDataProtocol();
+ setupRingBuffers();
+
+ // 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;
+ }
+
+ // Start Threads
+ mJackAudio->startProcess();
+ for (int i = 0; i < mProcessPlugins.size(); ++i) {
+ mJackAudio->appendProcessPlugin(mProcessPlugins[i]);
+ }
+ mJackAudio->connectDefaultPorts();
+ mDataProtocolSender->start();
+ mDataProtocolReceiver->start();
+}
+
+
+//*******************************************************************************
+void JackTrip::stop()
+{
+ // Stop The Sender
+ mDataProtocolSender->stop();
+ mDataProtocolSender->wait();
+
+ // Stop The Receiver
+ mDataProtocolReceiver->stop();
+ mDataProtocolReceiver->wait();
+
+ // Stop the jack process callback
+ mJackAudio->stopProcess();
+
+ cout << "JackTrip Processes STOPPED!" << endl;
+ cout << gPrintSeparator << endl;
+
+ // Emit the jack stopped signal
+ emit signalProcessesStopped();
+}
+
+//*******************************************************************************
+void JackTrip::wait()
+{
+ mDataProtocolSender->wait();
+ mDataProtocolReceiver->wait();
+}
+
+
+//*******************************************************************************
+void JackTrip::clientStart()
+{
+ // 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;
+ cout << gPrintSeparator << endl;
+ }
+}
+
+
+//*******************************************************************************
+void JackTrip::serverStart()
+{
+ // Set the peer address
+ if ( !mPeerAddress.isEmpty() ) {
+ std::cout << "WARNING: SERVER mode: Peer Address was set but will be deleted." << endl;
+ mPeerAddress.clear();
+ }
+
+ // Get the client address when it connects
+ cout << "Waiting for Connection From Client..." << endl;
+ QHostAddress peerHostAddress;
+ uint16_t peer_port;
+ QUdpSocket UdpSockTemp;// Create socket to wait for client
+
+ // Bind the socket
+ if ( !UdpSockTemp.bind(QHostAddress::Any, mReceiverBindPort,
+ QUdpSocket::DefaultForPlatform) )
+ {
+ throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
+ }
+ // Listen to client
+ while ( !UdpSockTemp.hasPendingDatagrams() ) { QThread::usleep(100000); }
+ char buf[1];
+ // set client address
+ UdpSockTemp.readDatagram(buf, 1, &peerHostAddress, &peer_port);
+ UdpSockTemp.close(); // close the socket
+
+ mPeerAddress = peerHostAddress.toString();
+ cout << "Client Connection Received from IP : "
+ << qPrintable(mPeerAddress) << endl;
+ cout << gPrintSeparator << endl;
+
+ // 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
+ // This way we can go through NAT
+ // Because of the NAT traversal scheme, the portn need to be
+ // "symetric", e.g.:
+ // from Client to Server : src = 4474, dest = 4464
+ // from Server to Client : src = 4464, dest = 4474
+ mDataProtocolSender->setPeerPort(peer_port);
+ mDataProtocolReceiver->setPeerPort(peer_port);
+ setPeerPorts(peer_port);
+}
+
+//*******************************************************************************
+void JackTrip::clientPingToServerStart()
+{
+ // 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");
+ }
+ else {
+ // Set the peer address
+ mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
+ }
+
+ // Start Threads
+ mJackAudio->startProcess();
+ //mJackAudio->connectDefaultPorts();
+ mDataProtocolSender->start();
+ //cout << "STARTED DATA PROTOCOL SENDER-----------------------------" << endl;
+ //mDataProtocolReceiver->start();
+
+ QHostAddress serverHostAddress;
+ QUdpSocket UdpSockTemp;// Create socket to wait for server answer
+ uint16_t server_port;
+
+ // Bind the socket
+ if ( !UdpSockTemp.bind(QHostAddress::Any,
+ mReceiverBindPort,
+ QUdpSocket::DefaultForPlatform) ) {
+ throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
+ }
+ // Listen to server response
+ cout << "Waiting for server response..." << endl;
+ while ( !UdpSockTemp.hasPendingDatagrams() ) { QThread::usleep(100000); }
+ cout << "Received response from server!" << endl;
+ char buf[1];
+ // set client address
+ UdpSockTemp.readDatagram(buf, 1, &serverHostAddress, &server_port);
+ UdpSockTemp.close(); // close the socket
+
+ // 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 << gPrintSeparator << endl;
+ mDataProtocolSender->setPeerPort(server_port-1);
+
+ // Start Threads
+ //mJackAudio->connectDefaultPorts();
+ mDataProtocolSender->start();
+ mDataProtocolReceiver->start();
+}
+
+
+//*******************************************************************************
+void JackTrip::createHeader(const DataProtocol::packetHeaderTypeT headertype)
+{
+ switch (headertype) {
+ case DataProtocol::DEFAULT :
+ mPacketHeader = new DefaultHeader(this);
+ break;
+ case DataProtocol::JAMLINK :
+ mPacketHeader = new JamLinkHeader(this);
+ break;
+ case DataProtocol::EMPTY :
+ mPacketHeader = new EmptyHeader(this);
+ break;
+ default :
+ throw std::invalid_argument("Undefined Header Type");
+ break;
+ }
+}
+
+
+//*******************************************************************************
+void JackTrip::putHeaderInPacket(int8_t* full_packet, int8_t* audio_packet)
+{
+ mPacketHeader->fillHeaderCommonFromAudio();
+ mPacketHeader->putHeaderInPacket(full_packet);
+
+ int8_t* audio_part;
+ audio_part = full_packet + mPacketHeader->getHeaderSizeInBytes();
+ //std::memcpy(audio_part, audio_packet, mJackAudio->getBufferSizeInBytes());
+ std::memcpy(audio_part, audio_packet, mJackAudio->getSizeInBytesPerChannel() * mNumChans);
+}
+
+
+//*******************************************************************************
+int JackTrip::getPacketSizeInBytes() const
+{
+ //return (mJackAudio->getBufferSizeInBytes() + mPacketHeader->getHeaderSizeInBytes());
+ return (mJackAudio->getSizeInBytesPerChannel() * mNumChans +
+ mPacketHeader->getHeaderSizeInBytes());
+}
+
+
+//*******************************************************************************
+void JackTrip::parseAudioPacket(int8_t* full_packet, int8_t* audio_packet)
+{
+ int8_t* audio_part;
+ audio_part = full_packet + mPacketHeader->getHeaderSizeInBytes();
+ //std::memcpy(audio_packet, audio_part, mJackAudio->getBufferSizeInBytes());
+ std::memcpy(audio_packet, audio_part, mJackAudio->getSizeInBytesPerChannel() * mNumChans);
+}
+
+
+//*******************************************************************************
+void JackTrip::checkPeerSettings(int8_t* full_packet)
+{
+ mPacketHeader->checkPeerSettings(full_packet);
+}
+
+
+//*******************************************************************************
+void JackTrip::checkIfPortIsBinded(int port)
+{
+ QUdpSocket UdpSockTemp;// Create socket to wait for client
+
+ // Bind the socket
+ if ( !UdpSockTemp.bind(QHostAddress::Any, port, QUdpSocket::DontShareAddress) )
+ {
+ UdpSockTemp.close(); // close the socket
+ throw std::runtime_error(
+ "Could not bind UDP socket. It may already be binded by another process on your machine. Try using a different port number");
+ }
+ UdpSockTemp.close(); // close the socket
+}
--- /dev/null
+//*****************************************************************
+/*
+ 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 JackTrip.h
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+#ifndef __JACKTRIP_H__
+#define __JACKTRIP_H__
+
+#include <tr1/memory> //for shared_ptr
+
+#include <QObject>
+#include <QString>
+
+#include "DataProtocol.h"
+#include "JackAudioInterface.h"
+#include "PacketHeader.h"
+#include "RingBuffer.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.
+ *
+ * All audio and network settings can be set in this class.
+ * 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;
+
+public:
+
+ //----------ENUMS------------------------------------------
+ /// \brief Enum for the data Protocol. At this time only UDP is implemented
+ enum dataProtocolT {
+ UDP, ///< Use UDP (User Datagram Protocol)
+ TCP, ///< <B>NOT IMPLEMENTED</B>: Use TCP (Transmission Control Protocol)
+ SCTP ///< <B>NOT IMPLEMENTED</B>: Use SCTP (Stream Control Transmission Protocol)
+ };
+
+ /// \brief Enum for the JackTrip mode
+ enum jacktripModeT {
+ SERVER, ///< Run in Server Mode
+ CLIENT, ///< Run in Client Mode
+ CLIENTTOPINGSERVER ///< Client of the Ping Server Mode
+ };
+
+ /// \brief Enum for the JackTrip Underrun Mode, when packets
+ enum underrunModeT {
+ WAVETABLE, ///< Loops on the last received packet
+ ZEROS ///< Set new buffers to zero if there are no new ones
+ };
+ //---------------------------------------------------------
+
+
+ /** \brief The class Constructor with Default Parameters
+ * \param JacktripMode JackTrip::CLIENT or JackTrip::SERVER
+ * \param DataProtocolType JackTrip::dataProtocolT
+ * \param NumChans Number of Audio Channels (same for inputs and outputs)
+ * \param BufferQueueLength Audio Buffer for receiving packets
+ * \param AudioBitResolution Audio Sample Resolutions in bits
+ * \param redundancy redundancy factor for network data
+ */
+ JackTrip(jacktripModeT JacktripMode = CLIENT,
+ dataProtocolT DataProtocolType = UDP,
+ int NumChans = 2,
+ int BufferQueueLength = 8,
+ unsigned int redundancy = 1,
+ JackAudioInterface::audioBitResolutionT AudioBitResolution =
+ JackAudioInterface::BIT16,
+ DataProtocol::packetHeaderTypeT PacketHeaderType =
+ DataProtocol::DEFAULT,
+ underrunModeT UnderRunMode = WAVETABLE,
+ int receiver_bind_port = gDefaultPort,
+ int sender_bind_port = gDefaultPort,
+ int receiver_peer_port = gDefaultPort,
+ int sender_peer_port = gDefaultPort);
+
+ /// \brief The class destructor
+ virtual ~JackTrip();
+
+ /// \brief Set the Peer Address for jacktripModeT::CLIENT mode only
+ 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);
+
+ /// \brief Start the processing threads
+ void start();
+
+ /// \brief Stop the processing threads
+ void stop();
+
+ /// \brief Wait for all the threads to finish. This functions is used when JackTrip is
+ /// run as a thread
+ void wait();
+
+ /// \brief Check if UDP port is already binded
+ /// \param port Port number
+ void checkIfPortIsBinded(int port);
+
+ //------------------------------------------------------------------------------------
+ /// \name Methods to change parameters after construction
+ //@{
+ //
+ /// \brief Sets (override) JackTrip Mode after construction
+ void setJackTripMode(jacktripModeT JacktripMode)
+ { mJackTripMode = JacktripMode; }
+ /// \brief Sets (override) DataProtocol Type after construction
+ void setDataProtocoType(dataProtocolT DataProtocolType)
+ { mDataProtocol = DataProtocolType; }
+ /// \brief Sets the Packet header type
+ 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)
+ { mBufferQueueLength = BufferQueueLength; }
+ /// \brief Sets (override) Audio Bit Resolution after construction
+ void setAudioBitResolution(JackAudioInterface::audioBitResolutionT AudioBitResolution)
+ { mAudioBitResolution = AudioBitResolution; }
+ /// \brief Sets (override) Underrun Mode
+ 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)
+ {
+ mReceiverBindPort = port;
+ mSenderPeerPort = port;
+ mSenderBindPort = port;
+ mReceiverPeerPort = port;
+ }
+ /// \brief Sets port numbers to bind in RECEIVER and SENDER sockets.
+ void setBindPorts(int port)
+ {
+ mReceiverBindPort = port;
+ mSenderBindPort = port;
+ }
+ /// \brief Sets port numbers for the peer (remote) machine.
+ void setPeerPorts(int port)
+ {
+ mSenderPeerPort = port;
+ mReceiverPeerPort = port;
+ }
+ /// \brief Set Client Name to something different that the default (JackTrip)
+ void setClientName(char* ClientName)
+ { mJackClientName = ClientName; }
+ //@}
+ //------------------------------------------------------------------------------------
+
+
+ //------------------------------------------------------------------------------------
+ /// \name Mediator Functions
+ //@{
+ /// \todo Document all these functions
+ void createHeader(const DataProtocol::packetHeaderTypeT headertype);
+ void putHeaderInPacket(int8_t* full_packet, int8_t* audio_packet);
+ int getPacketSizeInBytes() const;
+ void parseAudioPacket(int8_t* full_packet, int8_t* audio_packet);
+ void sendNetworkPacket(const int8_t* ptrToSlot)
+ { mSendRingBuffer->insertSlotNonBlocking(ptrToSlot); }
+ void receiveNetworkPacket(int8_t* ptrToReadSlot)
+ { mReceiveRingBuffer->readSlotNonBlocking(ptrToReadSlot); }
+ void readAudioBuffer(int8_t* ptrToReadSlot)
+ { mSendRingBuffer->readSlotBlocking(ptrToReadSlot); }
+ void writeAudioBuffer(const int8_t* ptrToSlot)
+ { mReceiveRingBuffer->insertSlotNonBlocking(ptrToSlot); }
+ uint32_t getBufferSizeInSamples() const
+ { return mJackAudio->getBufferSizeInSamples(); }
+ JackAudioInterface::samplingRateT getSampleRateType() const
+ { return mJackAudio->getSampleRateType(); }
+ 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);
+ void increaseSequenceNumber()
+ { mPacketHeader->increaseSequenceNumber(); }
+ int getSequenceNumber() const
+ { return mPacketHeader->getSequenceNumber(); }
+ int getPeerSequenceNumber(int8_t* full_packet) const
+ { return mPacketHeader->getPeerSequenceNumber(full_packet); }
+ //@}
+ //------------------------------------------------------------------------------------
+
+
+public slots:
+ /// \brief Slot to stop all the processes and threads
+ void slotStopProcesses()
+ {
+ std::cout << "Stopping JackTrip..." << std::endl;
+ stop();
+ };
+
+ /** \brief This slot emits in turn the signal signalNoUdpPacketsForSeconds
+ * when UDP is waited for more than 30 seconds.
+ *
+ * It is used to remove the thread from the server.
+ */
+ void slotUdpWatingTooLong(int wait_msec)
+ {
+ int wait_time = 30000; // msec
+ if ( !(wait_msec%wait_time) ) {
+ std::cerr << "UDP WAITED MORE THAN 30 seconds." << std::endl;
+ emit signalNoUdpPacketsForSeconds();
+ }
+ }
+
+
+signals:
+ /// \brieg 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
+ void signalNoUdpPacketsForSeconds();
+
+
+private:
+
+ /// \brief Set the JackAudioInteface object
+ void setupJackAudio();
+ /// \brief Set the DataProtocol objects
+ void setupDataProtocol();
+ /// \brief Set the RingBuffer objects
+ void setupRingBuffers();
+ /// \brief Starts for the CLIENT mode
+ void clientStart();
+ /// \brief Starts for the SERVER mode
+ void serverStart();
+ /// \brief Stats for the Client to Ping Server
+ void clientPingToServerStart();
+
+ jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
+ dataProtocolT mDataProtocol; ///< Data Protocol Tipe
+ DataProtocol::packetHeaderTypeT mPacketHeaderType; ///< Packet Header Type
+
+ 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
+ QString mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
+
+ /// Pointer to Abstract Type DataProtocol that sends packets
+ DataProtocol* mDataProtocolSender;
+ ///< Pointer to Abstract Type DataProtocol that receives packets
+ DataProtocol* mDataProtocolReceiver;
+ JackAudioInterface* mJackAudio; ///< Interface to Jack Client
+ PacketHeader* mPacketHeader; ///< Pointer to Packet Header
+ underrunModeT mUnderRunMode; ///< underrunModeT Mode
+
+ /// Pointer for the Send RingBuffer
+ RingBuffer* mSendRingBuffer;
+ /// Pointer for the Receive RingBuffer
+ RingBuffer* mReceiveRingBuffer;
+
+ int mReceiverBindPort; ///< Incoming (receiving) port for local machine
+ int mSenderPeerPort; ///< Incoming (receiving) port for peer machine
+ int mSenderBindPort; ///< Outgoing (sending) port for local machine
+ int mReceiverPeerPort; ///< Outgoing (sending) port for peer machine
+
+ unsigned int mRedundancy; ///< Redundancy factor in network data
+ const char* mJackClientName; ///< JackAudio Client Name
+
+ QVector<ProcessPlugin*> mProcessPlugins; ///< Vector of ProcesPlugin<EM>s</EM>
+};
+
+#endif
--- /dev/null
+//*****************************************************************
+/*
+ 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 JackTripThread.cpp
+ * \author Juan-Pablo Caceres
+ * \date September 2008
+ */
+
+
+#include "JackTripThread.h"
+#include "NetKS.h"
+
+#include <iostream>
+#include <cstdlib>
+
+using std::cout; using std::endl;
+
+
+//*******************************************************************************
+void JackTripThread::run()
+{
+ JackTrip jacktrip(mJackTripMode);
+ jacktrip.setAllPorts(mPortNum);
+
+ if ( mJackTripMode == JackTrip::CLIENT )
+ {
+ jacktrip.setPeerAddress(mPeerAddress);
+ }
+
+ NetKS netks;
+ jacktrip.appendProcessPlugin(&netks);
+ //netks.play();
+
+
+ //QThread::sleep(1);
+ jacktrip.start();
+ //netks.play();
+ jacktrip.wait();
+
+
+ cout << "******** AFTER JACKTRIPTHREAD START **************" << endl;
+ //QThread::sleep(9999999);
+
+
+
+ /*
+ jack_client_t* mClient;
+ const char* client_name = "JackThread";
+ const char* server_name = NULL;
+ jack_options_t options = JackNoStartServer;
+ jack_status_t status;
+
+ mClient = jack_client_open (client_name, options, &status, server_name);
+
+ if (mClient == NULL) {
+ fprintf (stderr, "jack_client_open() failed, "
+ "status = 0x%2.0x\n", status);
+ if (status & JackServerFailed) {
+ fprintf (stderr, "Unable to connect to JACK server\n");
+ }
+ std::exit(1);
+ }
+ if (status & JackServerStarted) {
+ fprintf (stderr, "JACK server started\n");
+ }
+ if (status & JackNameNotUnique) {
+ client_name = jack_get_client_name(mClient);
+ fprintf (stderr, "unique name `%s' assigned\n", client_name);
+ }
+ */
+
+
+}
--- /dev/null
+//*****************************************************************
+/*
+ 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 JackTripThread.h
+ * \author Juan-Pablo Caceres
+ * \date September 2008
+ */
+
+#ifndef __JACKTRIPTHREAD_H__
+#define __JACKTRIPTHREAD_H__
+
+#include <QThread>
+
+#include "JackTrip.h"
+
+/** \brief Test class that runs JackTrip inside a thread
+ */
+class JackTripThread : public QThread
+{
+public:
+ JackTripThread(JackTrip::jacktripModeT JacktripMode) : mJackTripMode(JacktripMode) {};
+ virtual ~JackTripThread(){};
+ void run();
+
+ void setPort(int port_num) { mPortNum = port_num; } ;
+ void setPeerAddress(const char* PeerHostOrIP) { mPeerAddress = PeerHostOrIP; }
+
+private:
+ JackTrip::jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
+ int mPortNum;
+ const char* mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
+};
+
+
+#endif //__JACKTRIPTHREAD_H__
--- /dev/null
+//*****************************************************************
+/*
+ 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 JackTripWorker.cpp
+ * \author Juan-Pablo Caceres
+ * \date September 2008
+ */
+
+#include <iostream>
+#include <unistd.h>
+
+#include <QTimer>
+#include <QMutexLocker>
+
+#include "JackTripWorker.h"
+#include "JackTrip.h"
+#include "UdpMasterListener.h"
+#include "NetKS.h"
+#include "LoopBack.h"
+
+using std::cout; using std::endl;
+
+//*******************************************************************************
+JackTripWorker::JackTripWorker(UdpMasterListener* udpmasterlistener) :
+ mUdpMasterListener(NULL),
+ mSpawning(false),
+ mID(0),
+ mNumChans(1)
+{
+ /* From the QT Documentation:
+ QThreadPool supports executing the same QRunnable more than once
+ by calling tryStart(this) from within QRunnable::run(). If autoDelete is
+ enabled the QRunnable will be deleted when the last thread exits the
+ run function. Calling start() multiple times with the same QRunnable
+ when autoDelete is enabled creates a race condition and is not recommended.
+ */
+ mUdpMasterListener = udpmasterlistener;
+ setAutoDelete(false); // stick around after calling run()
+ //mNetks = new NetKS;
+ //mNetks->play();
+}
+
+
+//*******************************************************************************
+JackTripWorker::~JackTripWorker()
+{
+ delete mUdpMasterListener;
+
+}
+
+
+//*******************************************************************************
+void JackTripWorker::setJackTrip(int id, uint32_t client_address,
+ uint16_t server_port, uint16_t client_port,
+ int num_channels)
+{
+ { //Start Spawning, so lock mSpawning
+ QMutexLocker locker(&mMutex);
+ mSpawning = true;
+ }
+ mID = id;
+ // Set the jacktrip address and ports
+ mClientAddress.setAddress(client_address);
+ mServerPort = server_port;
+ mClientPort = client_port;
+ mNumChans = num_channels;
+}
+
+
+//*******************************************************************************
+void JackTripWorker::run()
+{
+ /*
+ 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.'
+ */
+
+ // 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();
+
+ }
+ catch ( const std::exception & e )
+ {
+ std::cerr << "Couldn't send thread to the Pool" << endl;
+ std::cerr << e.what() << endl;
+ std::cerr << gPrintSeparator << endl;
+ }
+
+ mUdpMasterListener->releasePort(mID);
+ {
+ // 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;
+}
+
+
+//*******************************************************************************
+bool JackTripWorker::isSpawning()
+{
+ QMutexLocker locker(&mMutex);
+ return mSpawning;
+}
--- /dev/null
+//*****************************************************************
+/*
+ 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 JackTripWorker.h
+ * \author Juan-Pablo Caceres
+ * \date September 2008
+ */
+
+#ifndef __JACKTRIPWORKER_H__
+#define __JACKTRIPWORKER_H__
+
+#include <iostream>
+
+#include <QThreadPool>
+#include <QObject>
+#include <QEventLoop>
+#include <QHostAddress>
+#include <QMutex>
+
+#include "jacktrip_types.h"
+
+class JackTrip; // forward declaration
+class UdpMasterListener; // forward declaration
+
+
+/** \brief Prototype of the worker class that will be cloned through sending threads to the
+ * Thread Pool
+ *
+ * This class can be send to the ThreadPool using the start() method. Each time
+ * it is sent, it'll became "independent" of the prototype, which means
+ * that the prototype state can be changed, and used to send and start
+ * another thread into the pool. setAutoDelete must be set to false
+ * in order for this to work.
+ */
+// Note that it is not possible to start run() as an event loop. That has to be implemented
+// inside a QThread
+class JackTripWorker : public QObject, public QRunnable
+{
+ Q_OBJECT; // QRunnable is not a QObject, so I have to inherit from QObject as well
+
+public:
+ /// \brief The class constructor
+ JackTripWorker(UdpMasterListener* udpmasterlistener);
+
+ /// \brief The class destructor
+ virtual ~JackTripWorker();
+
+ /** \brief Implements the Thread Loop.
+ * To start the thread, call start() ( DO NOT CALL run() ).
+ */
+ void run();
+
+ /** \brief Check if the Thread is Spawning
+ * \return true is it is spawning, false if it's already running
+ */
+ bool isSpawning();
+
+ /** \brief Sets the JackTripWorker properties
+ * \param id ID number
+ * \param address
+ */
+ void setJackTrip(int id, uint32_t client_address,
+ uint16_t server_port, uint16_t client_port,
+ int num_channels);
+
+
+private slots:
+ void slotTest()
+ {
+ std::cout << "--- JackTripWorker TEST SLOT ---" << std::endl;
+ }
+
+
+private:
+
+ UdpMasterListener* mUdpMasterListener; ///< Master Listener Socket
+ QHostAddress mClientAddress; ///< Client Address
+ uint16_t mServerPort; ///< Server Ephemeral Incomming Port to use with Client
+
+ /// Client Outgoing Port. By convention, the receving port will be <tt>mClientPort -1</tt>
+ uint16_t mClientPort;
+
+ /// Thread spawning internal lock.
+ /// If true, the prototype is working on creating (spawning) a new thread
+ volatile bool mSpawning;
+ QMutex mMutex; ///< Mutex to protect mSpawning
+
+ int mID; ///< ID thread number
+ int mNumChans; ///< Number of Channels
+};
+
+
+#endif //__JACKTRIPWORKER_H__
--- /dev/null
+//*****************************************************************
+/*
+ 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 JackTripWorkerMessages.h
+ * \author Juan-Pablo Caceres
+ * \date October 2008
+ */
+
+#ifndef __JACKTRIPWORKERMESSAGES_H__
+#define __JACKTRIPWORKERMESSAGES_H__
+
+#include <QObject>
+#include <QTimer>
+
+#include <iostream>
+
+class JackTripWorkerMessages : public QObject
+{
+ Q_OBJECT;
+
+public:
+ JackTripWorkerMessages() {};
+ virtual ~JackTripWorkerMessages() {};
+
+ void play()
+ {
+ std::cout << "********** PALYING ***********************************" << std::endl;
+ QTimer *timer = new QTimer(this);
+ QObject::connect(timer, SIGNAL(timeout()), this, SLOT(slotTest()), Qt::QueuedConnection);
+ timer->start(300);
+ }
+
+public slots:
+ void slotTest()
+ {
+ std::cout << "---JackTripWorkerMessages slotTest()---" << std::endl;
+ }
+
+signals:
+ void signalTest();
+ /// Signal to stop the event loop inside the JackTripWorker Thread
+ void signalStopEventLoop();
+
+};
+
+#endif //__JACKTRIPWORKERMESSAGES_H__
--- /dev/null
+//*****************************************************************
+/*
+ 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 LoopBack.cpp
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+
+#include "LoopBack.h"
+#include "jacktrip_types.h"
+
+#include <cstring> // for memcpy
+
+
+//*******************************************************************************
+void LoopBack::compute(int nframes, float** inputs, float** outputs)
+{
+ for ( int i = 0; i < getNumInputs(); i++ ) {
+ // Everything that comes out, copy back to inputs
+ //memcpy(inputs[i], outputs[i], sizeof(sample_t) * nframes);
+ memcpy(outputs[i], inputs[i], sizeof(sample_t) * nframes);
+ }
+}
+
--- /dev/null
+//*****************************************************************
+/*
+ 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 LoopBack.h
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+
+/** \brief Connect Inputs to Outputs
+ *
+ */
+#ifndef __LOOPBACK_H__
+#define __LOOPBACK_H__
+
+#include "ProcessPlugin.h"
+
+
+/** \brief This Class just copy audio from its inputs to its outputs.
+ *
+ * It can be use to do loopback without the need to externally connect channels
+ * in JACK. Note that if you <EM>do</EM> connect the channels in jack, you'll
+ * be effectively multiplying the signal by 2.
+ */
+class LoopBack : public ProcessPlugin
+{
+public:
+ /// \brief The class constructor sets the number of channels to connect as loopback
+ LoopBack(int numchans) { mNumChannels = numchans; };
+ /// \brief The class destructor
+ virtual ~LoopBack() {};
+
+ virtual int getNumInputs() { return(mNumChannels); };
+ virtual int getNumOutputs() { return(mNumChannels); };
+ virtual void compute(int nframes, float** inputs, float** outputs);
+
+private:
+ int mNumChannels;
+};
+
+#endif
--- /dev/null
+//*****************************************************************
+/*
+ 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 JackTrip.h
+ * \author Juan-Pablo Caceres
+ * \date October 2008
+ */
+
+#ifndef __NETKS_H__
+#define __NETKS_H__
+
+#include <iostream>
+#include <unistd.h>
+
+#include <QTimer>
+
+#include "ProcessPlugin.h"
+
+/** \brief A simple (basic) network Karplus Strong.
+ *
+ * This plugin creates a one channel network karplus strong.
+ */
+class NetKS : public ProcessPlugin
+{
+ Q_OBJECT;
+
+
+public:
+ /*
+ void play()
+ {
+ std::cout << "********** PALYING ***********************************" << std::endl;
+ QTimer *timer = new QTimer(this);
+ QObject::connect(timer, SIGNAL(timeout()), this, SLOT(exciteString()));
+ timer->start(300);
+ }
+ */
+
+private slots:
+
+ /// \brief Stlot to excite (play) the string
+ void exciteString()
+ {
+ std::cout << "========= EXTICING STRING ===========" << std::endl;
+ fbutton0 = 1.0;
+ //std::cout << fbutton0 << std::endl;
+ usleep(280000); /// \todo Define this number based on the sampling rate and buffer size
+ fbutton0 = 0.0;
+ //std::cout << fbutton0 << std::endl;
+ }
+
+ //=========== FROM FAUST ===================================================
+ private:
+ float fbutton0;
+ float fVec0[2];
+ float fRec0[2];
+ int iRec1[2];
+ float fVec1[2];
+ public:
+ virtual int getNumInputs() { return 1; }
+ virtual int getNumOutputs() { return 1; }
+ static void classInit(int /*samplingFreq*/) {}
+ virtual void instanceInit(int samplingFreq) {
+ fSamplingFreq = samplingFreq;
+ fbutton0 = 0.0;
+ for (int i=0; i<2; i++) fVec0[i] = 0;
+ for (int i=0; i<2; i++) fRec0[i] = 0;
+ for (int i=0; i<2; i++) iRec1[i] = 0;
+ for (int i=0; i<2; i++) fVec1[i] = 0;
+ }
+ virtual void init(int samplingFreq) {
+ classInit(samplingFreq);
+ instanceInit(samplingFreq);
+ }
+ /*
+ virtual void buildUserInterface(UI* interface) {
+ interface->openVerticalBox("excitator");
+ interface->addButton("play", &fbutton0);
+ interface->closeBox();
+ }
+ */
+ virtual void compute (int count, float** input, float** output) {
+ float* input0 = input[0];
+ float* output0 = output[0];
+ float fSlow0 = fbutton0;
+ for (int i=0; i<count; i++) {
+ fVec0[0] = fSlow0;
+ fRec0[0] = ((((fSlow0 - fVec0[1]) > 0.000000f) + fRec0[1]) - (3.333333e-03f * (fRec0[1] > 0.000000f)));
+ iRec1[0] = (12345 + (1103515245 * iRec1[1]));
+ float fTemp0 = ((4.190951e-10f * iRec1[0]) * (fRec0[0] > 0.000000f));
+ float fTemp1 = input0[i];
+ fVec1[0] = (fTemp1 + fTemp0);
+ output0[i] = (0.500000f * ((fTemp0 + fTemp1) + fVec1[1]));
+ // post processing
+ fVec1[1] = fVec1[0];
+ iRec1[1] = iRec1[0];
+ fRec0[1] = fRec0[0];
+ fVec0[1] = fVec0[0];
+ }
+ }
+
+ //============================================================================
+
+};
+
+
+#endif // __NETKS_H__
+
--- /dev/null
+//*****************************************************************
+/*
+ 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 PacketHeader.cpp
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+#include "PacketHeader.h"
+#include "JackTrip.h"
+
+#include <sys/time.h>
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+using std::cout; using std::endl;
+
+
+//#######################################################################
+//####################### PacketHeader ##################################
+//#######################################################################
+//***********************************************************************
+PacketHeader::PacketHeader(JackTrip* jacktrip) :
+ mSeqNumber(0), mJackTrip(jacktrip)
+{}
+
+
+//***********************************************************************
+uint64_t PacketHeader::usecTime()
+{
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ return ( (tv.tv_sec * 1000000) + // seconds
+ (tv.tv_usec) ); // plus the microseconds. Type suseconds_t, range [-1, 1000000]
+}
+
+
+
+
+//#######################################################################
+//####################### DefaultHeader #################################
+//#######################################################################
+//***********************************************************************
+DefaultHeader::DefaultHeader(JackTrip* jacktrip) :
+ PacketHeader(jacktrip), mJackTrip(jacktrip)
+{
+ mHeader.TimeStamp = 0;
+ mHeader.SeqNumber = 0;
+ mHeader.BufferSize = 0;
+ mHeader.SamplingRate = 0;
+ mHeader.BitResolution = 0;
+ mHeader.NumInChannels = 0;
+ mHeader.NumOutChannels = 0;
+ //mHeader.Dummy = 0;
+}
+
+
+//***********************************************************************
+void DefaultHeader::fillHeaderCommonFromAudio()
+{
+ 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;
+ //printHeader();
+}
+
+
+//***********************************************************************
+void DefaultHeader::checkPeerSettings(int8_t* full_packet)
+{
+ bool error = false;
+
+ DefaultHeaderStruct* peer_header;
+ peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+
+ // Check Buffer Size
+ if ( peer_header->BufferSize != mHeader.BufferSize )
+ {
+ std::cerr << "ERROR: Peer Buffer Size is : " << peer_header->BufferSize << endl;
+ std::cerr << " Local Buffer Size is : " << mHeader.BufferSize << endl;
+ std::cerr << "Make sure both machines use same buffer size" << endl;
+ std::cerr << gPrintSeparator << endl;
+ error = true;
+ }
+
+ // Check 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;
+ }
+
+ // Check Audio Bit Resolution
+ if ( peer_header->BitResolution != mHeader.BitResolution )
+ {
+ std::cerr << "ERROR: Peer Audio Bit Resolution is : "
+ << static_cast<int>(peer_header->BitResolution) << endl;
+ std::cerr << " Local Audio Bit Resolution is : "
+ << static_cast<int>(mHeader.BitResolution) << endl;
+ std::cerr << "Make sure both machines use the same Bit Resolution" << endl;
+ std::cerr << gPrintSeparator << endl;
+ error = true;
+ }
+
+ // Exit program if error
+ if (error)
+ {
+ //std::cerr << "Exiting program..." << endl;
+ //std::exit(1);
+ throw std::logic_error("Local and Peer Settings don't match");
+ }
+ /// \todo Check number of channels and other parameters
+}
+
+
+//***********************************************************************
+void DefaultHeader::printHeader() const
+{
+ cout << "Default Packet Header:" << endl;
+ cout << "Buffer Size = " << static_cast<int>(mHeader.BufferSize) << endl;
+ // Get the sample rate in Hz form the JackAudioInterface::samplingRateT
+ int sample_rate =
+ JackAudioInterface::getSampleRateFromType
+ ( static_cast<JackAudioInterface::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 << "Sequence Number = " << static_cast<int>(mHeader.SeqNumber) << endl;
+ cout << "Time Stamp = " << mHeader.TimeStamp << endl;
+ cout << gPrintSeparator << endl;
+ cout << sizeof(mHeader) << endl;
+}
+
+
+//***********************************************************************
+uint16_t DefaultHeader::getPeerSequenceNumber(int8_t* full_packet) const
+{
+ DefaultHeaderStruct* peer_header;
+ peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+ return peer_header->SeqNumber;
+}
+
+
+
+
+
+
+
+
+//#######################################################################
+//####################### JamLinkHeader #################################
+//#######################################################################
+//***********************************************************************
+JamLinkHeader::JamLinkHeader(JackTrip* jacktrip) :
+ PacketHeader(jacktrip), mJackTrip(jacktrip)
+{
+ mHeader.Common = 0;
+ mHeader.SeqNumber = 0;
+ mHeader.TimeStamp = 0;
+}
+
+
+//***********************************************************************
+void JamLinkHeader::fillHeaderCommonFromAudio()
+{
+ // Check number of channels
+ int num_inchannels = mJackTrip->getNumInputChannels();
+ if ( num_inchannels != 1 ) {
+ //std::cerr << "ERROR: JamLink only support ONE channel. Run JackTrip using only one channel"
+ // << endl;
+ //std::exit(1);
+ throw std::logic_error("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.");
+ }
+
+ // 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.");
+ }
+
+ mHeader.Common = (ETX_MONO | ETX_16BIT | ETX_XTND) + 64;
+ switch (rate_type)
+ {
+ case JackAudioInterface::SR48 :
+ mHeader.Common = (mHeader.Common | ETX_48KHZ);
+ break;
+ case JackAudioInterface::SR44 :
+ mHeader.Common = (mHeader.Common | ETX_44KHZ);
+ break;
+ case JackAudioInterface::SR32 :
+ mHeader.Common = (mHeader.Common | ETX_32KHZ);
+ break;
+ case JackAudioInterface::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");
+ break;
+ }
+}
+
+
+
+
+
+
+//#######################################################################
+//####################### EmptyHeader #################################
+//#######################################################################
+//***********************************************************************
+EmptyHeader::EmptyHeader(JackTrip* jacktrip) :
+ PacketHeader(jacktrip), mJackTrip(jacktrip)
+{}
--- /dev/null
+//*****************************************************************
+/*
+ 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 PacketHeader.h
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+#ifndef __PACKETHEADER_H__
+#define __PACKETHEADER_H__
+
+#include <iostream>
+#include <tr1/memory> // for shared_ptr
+#include <cstring>
+
+#include "jacktrip_types.h"
+#include "jacktrip_globals.h"
+class JackTrip; // Forward Declaration
+
+
+/// \brief Abstract Header Struct, Header Stucts should subclass it
+struct HeaderStruct{};
+
+/// \brief Default Header Struct
+struct DefaultHeaderStruct : public HeaderStruct
+{
+public:
+ // watch out for alignment...
+ uint64_t TimeStamp; ///< Time Stamp
+ uint16_t SeqNumber; ///< Sequence Number
+ uint16_t BufferSize; ///< Buffer Size in Samples
+ uint8_t SamplingRate; ///< Sampling Rate in JackAudioInterface::samplingRateT
+ uint8_t BitResolution; ///< Audio Bit Resolution
+ uint8_t NumInChannels; ///< Number of Input Channels
+ uint8_t NumOutChannels; ///< Number of Output Channels
+ //uint8_t Dummy; ///< Dummy value to byte padding alignment
+};
+
+//---------------------------------------------------------
+//JamLink UDP Header:
+/************************************************************************/
+/* values for the UDP stream type */
+/* streamType is a 16-bit value at the head of each UDP stream */
+/* Its bit map is as follows: (b15-msb) */
+/* B15:reserved, B14:extended header, B13 Stereo, B12 not 16-bit */
+/* B11-B9: 0-48 Khz, 1-44 Khz, 2-32 Khz, 3-24 Khz, */
+/* 4-22 Khz, 5-16 Khz, 6-11 Khz, 7-8 Khz */
+/* B8-0: Samples in packet */
+/************************************************************************/
+const unsigned short ETX_RSVD = (0<<15);
+const unsigned short ETX_XTND = (1<<14);
+const unsigned short ETX_STEREO = (1<<13);
+const unsigned short ETX_MONO = (0<<13);
+const unsigned short ETX_16BIT = (0<<12);
+//inline unsigned short ETX_RATE_MASK(const unsigned short a) { a&(0x7<<9); }
+const unsigned short ETX_48KHZ = (0<<9);
+const unsigned short ETX_44KHZ = (1<<9);
+const unsigned short ETX_32KHZ = (2<<9);
+const unsigned short ETX_24KHZ = (3<<9);
+const unsigned short ETX_22KHZ = (4<<9);
+const unsigned short ETX_16KHZ = (5<<9);
+const unsigned short ETX_11KHZ = (6<<9);
+const unsigned short ETX_8KHZ = (7<<9);
+// able to express up to 512 SPP
+//inline unsigned short ETX_SPP(const unsigned short a) { (a&0x01FF); }
+
+/// \brief JamLink Header Struct
+struct JamLinkHeaderStuct : public HeaderStruct
+{
+ // watch out for alignment -- need to be on 4 byte chunks
+ uint16_t Common; ///< Common part of the header, 16 bit
+ uint16_t SeqNumber; ///< Sequence Number
+ uint32_t TimeStamp; ///< Time Stamp
+};
+
+
+//#######################################################################
+//####################### PacketHeader ##################################
+//#######################################################################
+/** \brief Base class for header type. Subclass this struct to
+ * create a new header.
+ */
+class PacketHeader
+{
+public:
+ /// \brief The class Constructor
+ PacketHeader(JackTrip* jacktrip);
+ /// \brief The class Destructor
+ virtual ~PacketHeader() {};
+
+ /** \brief Return a time stamp in microseconds
+ * \return Time stamp: microseconds since midnight (0 hour), January 1, 1970
+ */
+ static uint64_t usecTime();
+
+ /// \todo Implement this using a JackTrip Method (Mediator) member instead of the
+ /// reference to JackAudio
+ virtual void fillHeaderCommonFromAudio() = 0;
+
+ /* \brief Parse the packet header and take appropriate measures (like change settings, or
+ * quit the program if peer settings don't match)
+ */
+ virtual void parseHeader() = 0;
+
+ virtual void checkPeerSettings(int8_t* full_packet) = 0;
+ virtual uint16_t getPeerSequenceNumber(int8_t* full_packet) const = 0;
+
+ /* \brief Increase sequence number for counter, a 16bit number
+ */
+ virtual void increaseSequenceNumber()
+ {
+ mSeqNumber++;
+ };
+
+ /* \brief Returns the current sequence number
+ * \return 16bit Sequence number
+ */
+ virtual uint16_t getSequenceNumber() const
+ {
+ return mSeqNumber;
+ }
+
+ /* \brief Get the header size in bytes
+ */
+ virtual int getHeaderSizeInBytes() const = 0;
+
+
+ virtual void putHeaderInPacketBaseClass(int8_t* full_packet,
+ const HeaderStruct& header_struct)
+ {
+ std::memcpy(full_packet, reinterpret_cast<const void*>(&header_struct),
+ getHeaderSizeInBytes() );
+ };
+
+ /* \brief Put the header in buffer pointed by full_packet
+ * \param full_packet Pointer to full packet (audio+header). Size must be
+ * sizeof(header part) + sizeof(audio part)
+ */
+ virtual void putHeaderInPacket(int8_t* full_packet) = 0;
+
+private:
+ uint16_t mSeqNumber;
+ JackTrip* mJackTrip; ///< JackTrip mediator class
+};
+
+
+
+
+//#######################################################################
+//####################### DefaultHeader #################################
+//#######################################################################
+/** \brief Default Header
+ */
+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 void fillHeaderCommonFromAudio();
+ 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;
+ };
+ virtual uint16_t getSequenceNumber() const
+ {
+ return mHeader.SeqNumber;
+ }
+ virtual uint16_t getPeerSequenceNumber(int8_t* full_packet) const;
+ 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() );
+ };
+ void printHeader() const;
+
+private:
+ //DefaultHeaderStruct mHeader; ///< Header Struct
+ DefaultHeaderStruct mHeader;///< Default Header Struct
+ JackTrip* mJackTrip; ///< JackTrip mediator class
+};
+
+
+
+
+//#######################################################################
+//####################### JamLinkHeader #################################
+//#######################################################################
+
+/** \brief JamLink Header
+ */
+class JamLinkHeader : public PacketHeader
+{
+public:
+
+ JamLinkHeader(JackTrip* jacktrip);
+ virtual ~JamLinkHeader() {};
+
+ virtual void fillHeaderCommonFromAudio();
+ 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 void putHeaderInPacket(int8_t* full_packet)
+ {
+ putHeaderInPacketBaseClass(full_packet, mHeader);
+ };
+
+private:
+ JamLinkHeaderStuct mHeader; ///< JamLink Header Struct
+ JackTrip* mJackTrip; ///< JackTrip mediator class
+};
+
+
+
+//#######################################################################
+//####################### EmptyHeader #################################
+//#######################################################################
+
+/** \brief Empty Header to use with systems that don't include a header.
+ */
+class EmptyHeader : public PacketHeader
+{
+public:
+
+ EmptyHeader(JackTrip* jacktrip);
+ virtual ~EmptyHeader() {};
+
+ 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*/) {};
+
+private:
+ JackTrip* mJackTrip; ///< JackTrip mediator class
+};
+
+
+#endif //__PACKETHEADER_H__
--- /dev/null
+//#include "ProcessPlugin.h"
+
+/*
+//----------------------------------------------------------------------------
+// Jack Callbacks
+//----------------------------------------------------------------------------
+
+int srate(jack_nframes_t nframes, void *arg)
+{
+ printf("the sample rate is now %u/sec\n", nframes);
+ return 0;
+}
+
+void jack_shutdown(void *arg)
+{
+ std::cout << "" << std::endl;
+ std::exit(1);
+}
+
+int process (jack_nframes_t nframes, void *arg)
+{
+ for (int i = 0; i < gNumInChans; i++) {
+ gInChannel[i] = (float *)jack_port_get_buffer(input_ports[i], nframes);
+ }
+ for (int i = 0; i < gNumOutChans; i++) {
+ gOutChannel[i] = (float *)jack_port_get_buffer(output_ports[i], nframes);
+ }
+ DSP.compute(nframes, gInChannel, gOutChannel);
+ return 0;
+}
+*/
--- /dev/null
+//*****************************************************************
+/*
+ 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 ProcessPlugin.h
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+#ifndef __PROCESSPLUGIN_H__
+#define __PROCESSPLUGIN_H__
+
+#include <jack/jack.h>
+#include <QObject>
+
+/** \brief Interface for the process plugins to add to the JACK callback process in
+ * JackAudioInterface
+ *
+ * This class contains the same methods of the FAUST dsp class. A mydsp class can inherit from
+ * this class the same way it inherits from dsp. Subclass should implement all methods
+ * except init, which is optional for processing that are sampling rate dependent or
+ * that need specific initialization.
+ */
+class ProcessPlugin : public QObject
+{
+public:
+
+ /// \brief The Class Constructor
+ ProcessPlugin() {};
+ /// \brief The Class Destructor
+ virtual ~ProcessPlugin() {};
+
+ /// \brief Return Number of Input Channels
+ virtual int getNumInputs() = 0;
+ /// \brief Return Number of Output Channels
+ virtual int getNumOutputs() = 0;
+
+ //virtual void buildUserInterface(UI* interface) = 0;
+
+ /** \brief Do proper Initialization of members and class instances. By default this
+ * initializes the Sampling Frequency. If a class instance depends on the
+ * sampling frequency, it should be initialize here.
+ */
+ virtual void init(int samplingRate) { fSamplingFreq = samplingRate; };
+
+ /// \brief Compute process
+ virtual void compute(int nframes, float** inputs, float** outputs) = 0;
+
+protected:
+ int fSamplingFreq; ///< Faust Data member, Sampling Rate
+};
+
+#endif
--- /dev/null
+//*****************************************************************
+/*
+ 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 RingBuffer.cpp
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+
+#include "RingBuffer.h"
+
+#include <iostream>
+#include <cstring>
+#include <cstdlib>
+#include <stdexcept>
+
+using std::cout; using std::endl;
+
+
+//*******************************************************************************
+RingBuffer::RingBuffer(int SlotSize, int NumSlots) :
+ mSlotSize(SlotSize),
+ mNumSlots(NumSlots),
+ mTotalSize(mSlotSize*mNumSlots),
+ mReadPosition(0),
+ mWritePosition(0),
+ mFullSlots(0),
+ mRingBuffer(new int8_t[mTotalSize]),
+ mLastReadSlot(new int8_t[mSlotSize])
+{
+ //QMutexLocker locker(&mMutex); // lock the mutex
+
+ // Verify if there's enough space to for the buffers
+ if ( (mRingBuffer == NULL) || (mLastReadSlot == NULL) ) {
+ //std::cerr << "ERROR: RingBuffer out of memory!" << endl;
+ //std::cerr << "Exiting program..." << endl;
+ //std::exit(1);
+ throw std::length_error("RingBuffer out of memory!");
+ }
+
+ // Set the buffers to zeros
+ /*
+ for (int i=0; i<mTotalSize; i++) {
+ mRingBuffer[i] = 0; // Initialize all elements to zero.
+ }
+ */
+ std::memset(mRingBuffer, 0, mTotalSize); // set buffer to 0
+ /*
+ for (int i=0; i<mSlotSize; i++) {
+ mLastReadSlot[i] = 0; // Initialize all elements to zero.
+ }
+ */
+ std::memset(mLastReadSlot, 0, mSlotSize); // set buffer to 0
+
+
+ // Advance write position to half of the RingBuffer
+ mWritePosition = ( (NumSlots/2) * SlotSize ) % mTotalSize;
+ // Udpate Full Slots accordingly
+ mFullSlots = (NumSlots/2);
+}
+
+
+//*******************************************************************************
+RingBuffer::~RingBuffer()
+{
+ delete[] mRingBuffer; // Free memory
+ mRingBuffer = NULL; // Clear to prevent using invalid memory reference
+ delete[] mLastReadSlot;
+ mLastReadSlot = NULL;
+}
+
+
+//*******************************************************************************
+void RingBuffer::insertSlotBlocking(const int8_t* ptrToSlot)
+{
+ QMutexLocker locker(&mMutex); // lock the mutex
+
+ // Check if there is space available to write a slot
+ // If the Ringbuffer is full, it waits for the bufferIsNotFull condition
+ while (mFullSlots == mNumSlots) {
+ //std::cout << "OUPUT OVERFLOW BLOCKING" << std::endl;
+ mBufferIsNotFull.wait(&mMutex);
+ }
+
+ // Copy mSlotSize bytes to mRingBuffer
+ std::memcpy(mRingBuffer+mWritePosition, ptrToSlot, mSlotSize);
+ // Update write position
+ mWritePosition = (mWritePosition+mSlotSize) % mTotalSize;
+ mFullSlots++; //update full slots
+ // Wake threads waitng for bufferIsNotFull condition
+ mBufferIsNotEmpty.wakeAll();
+}
+
+
+//*******************************************************************************
+void RingBuffer::readSlotBlocking(int8_t* ptrToReadSlot)
+{
+ QMutexLocker locker(&mMutex); // lock the mutex
+
+ // Check if there are slots available to read
+ // If the Ringbuffer is empty, it waits for the bufferIsNotEmpty condition
+ while (mFullSlots == 0) {
+ //std::cerr << "READ UNDER-RUN BLOCKING before" << endl;
+ mBufferIsNotEmpty.wait(&mMutex);
+ }
+
+ // Copy mSlotSize bytes to ReadSlot
+ std::memcpy(ptrToReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+ // Always save memory of the last read slot
+ std::memcpy(mLastReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+ // Update write position
+ mReadPosition = (mReadPosition+mSlotSize) % mTotalSize;
+ mFullSlots--; //update full slots
+ // Wake threads waitng for bufferIsNotFull condition
+ mBufferIsNotFull.wakeAll();
+}
+
+
+//*******************************************************************************
+void RingBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot)
+{
+ QMutexLocker locker(&mMutex); // lock the mutex
+
+ // Check if there is space available to write a slot
+ // If the Ringbuffer is full, it returns without writing anything
+ // and resets the buffer
+ /// \todo It may be better here to insert the slot anyways,
+ /// instead of not writing anything
+ if (mFullSlots == mNumSlots) {
+ //std::cout << "OUPUT OVERFLOW NON BLOCKING = " << mNumSlots << std::endl;
+ overflowReset();
+ return;
+ }
+
+ // Copy mSlotSize bytes to mRingBuffer
+ std::memcpy(mRingBuffer+mWritePosition, ptrToSlot, mSlotSize);
+ // Update write position
+ mWritePosition = (mWritePosition+mSlotSize) % mTotalSize;
+ mFullSlots++; //update full slots
+ // Wake threads waitng for bufferIsNotFull condition
+ mBufferIsNotEmpty.wakeAll();
+}
+
+
+//*******************************************************************************
+void RingBuffer::readSlotNonBlocking(int8_t* ptrToReadSlot)
+{
+ QMutexLocker locker(&mMutex); // lock the mutex
+
+
+ // Check if there are slots available to read
+ // If the Ringbuffer is empty, it returns a buffer of zeros and rests the buffer
+ if (mFullSlots == 0) {
+ // Returns a buffer of zeros if there's nothing to read
+ //std::cerr << "READ UNDER-RUN NON BLOCKING = " << mNumSlots << endl;
+ //std::memset(ptrToReadSlot, 0, mSlotSize);
+ setUnderrunReadSlot(ptrToReadSlot);
+ underrunReset();
+ return;
+ }
+
+ // Copy mSlotSize bytes to ReadSlot
+ std::memcpy(ptrToReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+ // Always save memory of the last read slot
+ std::memcpy(mLastReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+ // Update write position
+ mReadPosition = (mReadPosition+mSlotSize) % mTotalSize;
+ mFullSlots--; //update full slots
+ // Wake threads waitng for bufferIsNotFull condition
+ mBufferIsNotFull.wakeAll();
+}
+
+
+//*******************************************************************************
+void RingBuffer::setUnderrunReadSlot(int8_t* ptrToReadSlot)
+{
+ std::memset(ptrToReadSlot, 0, mSlotSize);
+}
+
+
+//*******************************************************************************
+void RingBuffer::setMemoryInReadSlotWithLastReadSlot(int8_t* ptrToReadSlot)
+{
+ std::memcpy(ptrToReadSlot, mLastReadSlot, mSlotSize);
+}
+
+
+
+
+//*******************************************************************************
+// Under-run happens when there's nothing to read.
+void RingBuffer::underrunReset()
+{
+ // Advance the write pointer 1/2 the ring buffer
+ //mWritePosition = ( mReadPosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
+ //mWritePosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
+ //mFullSlots += mNumSlots/2;
+ // There's nothing new to read, so we clear the whole buffer (Set the entire buffer to 0)
+ std::memset(mRingBuffer, 0, mTotalSize);
+}
+
+
+//*******************************************************************************
+// Over-flow happens when there's no space to write more slots.
+void RingBuffer::overflowReset()
+{
+ // Advance the read pointer 1/2 the ring buffer
+ //mReadPosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
+ mReadPosition = ( mReadPosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
+ mFullSlots -= mNumSlots/2;
+}
+
+
+//*******************************************************************************
+void RingBuffer::debugDump() const
+{
+ cout << "mTotalSize = " << mTotalSize << endl;
+ cout << "mReadPosition = " << mReadPosition << endl;
+ cout << "mWritePosition = " << mWritePosition << endl;
+ cout << "mFullSlots = " << mFullSlots << endl;
+}
--- /dev/null
+//*****************************************************************
+/*
+ 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 RingBuffer.h
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+#ifndef __RINGBUFFER_H__
+#define __RINGBUFFER_H__
+
+#include <QWaitCondition>
+#include <QMutex>
+#include <QMutexLocker>
+
+#include "jacktrip_types.h"
+
+
+/** \brief Provides a ring-buffer (or circular-buffer) that can be written to and read from
+ * asynchronously (blocking) or synchronously (non-blocking).
+ *
+ * The RingBuffer is an array of \b NumSlots slots of memory
+ * each of which is of size \b SlotSize bytes (8-bits). Slots can be read and
+ * written asynchronously/synchronously by multiple threads.
+ */
+class RingBuffer
+{
+public:
+
+ /** \brief The class constructor
+ * \param SlotSize Size of one slot in bytes
+ * \param NumSlots Number of slots
+ */
+ RingBuffer(int SlotSize, int NumSlots);
+
+ /** \brief The class destructor
+ */
+ virtual ~RingBuffer();
+
+ /** \brief Insert a slot into the RingBuffer from ptrToSlot. This method will block until
+ * there's space in the buffer.
+ *
+ * The caller is responsible to make sure sizeof(WriteSlot) = SlotSize. This
+ * method should be use when the caller can block against its output, like
+ * sending/receiving UDP packets. It shouldn't be used by audio. For that, use the
+ * insertSlotNonBlocking.
+ * \param ptrToSlot Pointer to slot to insert into the RingBuffer
+ */
+ void insertSlotBlocking(const int8_t* ptrToSlot);
+
+ /** \brief Read a slot from the RingBuffer into ptrToReadSlot. This method will block until
+ * there's space in the buffer.
+ *
+ * The caller is responsible to make sure sizeof(ptrToReadSlot) = SlotSize. This
+ * method should be use when the caller can block against its input, like
+ * sending/receiving UDP packets. It shouldn't be used by audio. For that, use the
+ * readSlotNonBlocking.
+ * \param ptrToReadSlot Pointer to read slot from the RingBuffer
+ */
+ void readSlotBlocking(int8_t* ptrToReadSlot);
+
+ /** \brief Same as insertSlotBlocking but non-blocking (asynchronous)
+ * \param ptrToSlot Pointer to slot to insert into the RingBuffer
+ */
+ void insertSlotNonBlocking(const int8_t* ptrToSlot);
+
+ /** \brief Same as readSlotBlocking but non-blocking (asynchronous)
+ * \param ptrToReadSlot Pointer to read slot from the RingBuffer
+ */
+ void readSlotNonBlocking(int8_t* ptrToReadSlot);
+
+
+protected:
+
+ /** \brief Sets the memory in the Read Slot when uderrun occurs. By default,
+ * this sets it to 0. Override this method in a subclass for a different behavior.
+ * \param ptrToReadSlot Pointer to read slot from the RingBuffer
+ */
+ virtual void setUnderrunReadSlot(int8_t* ptrToReadSlot);
+
+ /** \brief Uses the last read slot to set the memory in the Read Slot.
+ *
+ * The last read slot is the last packet that arrived, so if no new packets are received,
+ * it keeps looping the same packet.
+ * \param ptrToReadSlot Pointer to read slot from the RingBuffer
+ */
+ virtual void setMemoryInReadSlotWithLastReadSlot(int8_t* ptrToReadSlot);
+
+private:
+
+ /// \brief Resets the ring buffer for reads under-runs non-blocking
+ void underrunReset();
+ /// \brief Resets the ring buffer for writes over-flows non-blocking
+ void overflowReset();
+ /// \brief Helper method to debug, prints member variables to terminal
+ void debugDump() const;
+
+ const int mSlotSize; ///< The size of one slot in byes
+ const int mNumSlots; ///< Number of Slots
+ const int mTotalSize; ///< Total size of the mRingBuffer = mSlotSize*mNumSlotss
+ int mReadPosition; ///< Read Positions in the RingBuffer (Tail)
+ int mWritePosition; ///< Write Position in the RingBuffer (Head)
+ int mFullSlots; ///< Number of used (full) slots, in slot-size
+ int8_t* mRingBuffer; ///< 8-bit array of data (1-byte)
+ int8_t* mLastReadSlot; ///< Last slot read
+
+ // Thread Synchronization Private Members
+ QMutex mMutex; ///< Mutex to protect read and write operations
+ QWaitCondition mBufferIsNotFull; ///< Buffer not full condition to monitor threads
+ QWaitCondition mBufferIsNotEmpty; ///< Buffer not empty condition to monitor threads
+};
+
+#endif
--- /dev/null
+//*****************************************************************
+/*
+ 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 RingBufferWavetable.h
+ * \author Juan-Pablo Caceres
+ * \date September 2008
+ */
+
+#ifndef __RINGBUFFERWAVETABLE_H__
+#define __RINGBUFFERWAVETABLE_H__
+
+
+/** \brief Same as RingBuffer, except that it uses the Wavetable mode for
+ * lost or late packets.
+ */
+class RingBufferWavetable : public RingBuffer
+{
+public:
+ /** \brief The class constructor
+ * \param SlotSize Size of one slot in bytes
+ * \param NumSlots Number of slots
+ */
+ RingBufferWavetable(int SlotSize, int NumSlots) : RingBuffer(SlotSize, NumSlots) {}
+
+ /** \brief The class destructor
+ */
+ virtual ~RingBufferWavetable() {}
+
+protected:
+ /** \brief Sets the memory in the Read Slot when uderrun occurs. This loops as a
+ * wavetable in the last received packet.
+ * \param ptrToReadSlot Pointer to read slot from the RingBuffer
+ */
+ virtual void setUnderrunReadSlot(int8_t* ptrToReadSlot)
+ {
+ setMemoryInReadSlotWithLastReadSlot(ptrToReadSlot);
+ }
+
+};
+
+
+#endif //__RINGBUFFERWAVETABLE_H__
--- /dev/null
+//*****************************************************************
+/*
+ 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 Settings.cpp
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+#include "Settings.h"
+#include "LoopBack.h"
+#include "NetKS.h"
+#include "UdpMasterListener.h"
+#include "JackTripWorker.h"
+#include "jacktrip_globals.h"
+
+#include <iostream>
+#include <getopt.h> // for command line parsing
+#include <cstdlib>
+
+#include "ThreadPoolTest.h"
+
+using std::cout; using std::endl;
+
+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)
+{}
+
+//*******************************************************************************
+Settings::~Settings()
+{
+ 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;
+ }
+
+ // 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;
+ }
+}
+
+
+//*******************************************************************************
+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;
+}
+
+
+//*******************************************************************************
+void Settings::startJackTrip()
+{
+
+ ///\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
+ QThreadPool::globalInstance()->start(thtest);
+
+ cout << "AFTER START" << endl;
+ sleep(2);
+ 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);
+ }
+
+ // Set in EmptyHeader Mode
+ if ( mEmptyHeader ) {
+ cout << "Running in EmptyHeader Mode..." << endl;
+ cout << gPrintSeparator << std::endl;
+ mJackTrip->setPacketHeaderType(DataProtocol::EMPTY);
+ }
+
+ // 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();
+
+ /*
+ sleep(10);
+ cout << "Stoping JackTrip..." << endl;
+ mJackTrip->stop();
+ */
+ }
+}
+
+
+//*******************************************************************************
+void Settings::stopJackTrip()
+{
+ mJackTrip->stop();
+}
--- /dev/null
+//*****************************************************************
+/*
+ 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 Settings.h
+ * \author Juan-Pablo Caceres
+ * \date July 2008
+ */
+
+
+#ifndef __SETTINGS_H__
+#define __SETTINGS_H__
+
+#include "DataProtocol.h"
+#include "JackAudioInterface.h"
+#include "JackTrip.h"
+
+/** \brief Class to set usage options and parse settings from input
+ */
+class Settings
+{
+public:
+ Settings();
+ virtual ~Settings();
+
+ /// \brief Parses command line input
+ void parseInput(int argc, char** argv);
+
+ void startJackTrip();
+ void stopJackTrip();
+
+ /// \brief Prints usage help
+ void printUsage();
+
+ bool getLoopBack() { return mLoopBack; };
+
+private:
+ JackTrip* mJackTrip; ///< JackTrip class
+ JackTrip::jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
+ JackTrip::dataProtocolT mDataProtocol; ///< Data Protocol
+ int mNumChans; ///< Number of Channels (inputs = outputs)
+ int mBufferQueueLength; ///< Audio Buffer from network queue length
+ JackAudioInterface::audioBitResolutionT mAudioBitResolution;
+ QString mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
+ int mPortNum; ///< Port Number
+ char* mClientName;
+ 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
+ unsigned int mRedundancy; ///< Redundancy factor for data in the network
+};
+
+#endif
--- /dev/null
+#ifndef __TESTRINGBUFFER__
+#define __TESTRINGBUFFER__
+
+#include "RingBuffer.h"
+#include <QThread>
+#include <iostream>
+
+static RingBuffer rb(2,100);
+
+class TestRingBufferWrite : public QThread
+{
+public:
+
+ void run()
+ {
+ int8_t* writeSlot;
+ writeSlot = new int8_t[2];
+ writeSlot[0] = *"a";
+ writeSlot[1] = *"b";
+ while (true) {
+ //std::cout << "writing BEFORE" << std::endl;
+ rb.insertSlotBlocking(writeSlot);
+ //std::cout << "writing AFTER" << std::endl;
+ }
+ }
+
+};
+
+
+class TestRingBufferRead : public QThread
+{
+public:
+
+ void run()
+ {
+ int8_t* readSlot;
+ readSlot = new int8_t[2];
+ while (true) {
+ //std::cout << "reading BEFORE" << std::endl;
+ rb.readSlotBlocking(readSlot);
+ //std::cout << "reading AFTER" << std::endl;
+ //std::cout << *(readSlot) << std::endl;
+ //std::cout << *(readSlot+1) << std::endl;
+ }
+ }
+};
+
+#endif
+
--- /dev/null
+/**
+ * \file ThreadPoolTest.h
+ * \author Juan-Pablo Caceres
+ * \date October 2008
+ */
+
+#ifndef __THREADPOOLTEST_H__
+#define __THREADPOOLTEST_H__
+
+#include <QThreadPool>
+#include <QEventLoop>
+#include <QThread>
+#include <QObject>
+
+#include <iostream>
+
+#include "NetKS.h"
+#include "JackTripWorkerMessages.h"
+
+
+class ThreadPoolTest : public QObject, public QRunnable
+//class ThreadPoolTest : public QThread
+{
+ Q_OBJECT;
+
+public:
+ ThreadPoolTest()
+ {
+ setAutoDelete(false);
+ }
+
+ void run()
+ {
+ JackTripWorkerMessages jtm;
+ QThread testThread;
+ //jtm.moveToThread(&testThread);
+
+ //QObject::connect(&jtm, SIGNAL(signalTest()), &jtm, SLOT(slotTest()), Qt::QueuedConnection);
+ testThread.start();
+ jtm.play();
+ //testThread.wait();
+
+ //std::cout << "--------------- BEFORE ---------------" << std::endl;
+ //NetKS netks;
+ //netks.play();
+ //std::cout << "--------------- AFTER ---------------" << std::endl;
+
+ QEventLoop loop;
+ //QObject::connect(this, SIGNAL(stopELoop()), &loop, SLOT(quit()), Qt::QueuedConnection);
+ loop.exec();
+ //std::cout << "--------------- EXITING QRUNNABLE---------------" << std::endl;
+ /*
+ while (true) {
+ std::cout << "Hello world from thread" << std::endl;
+ sleep(1);
+ }
+ */
+ }
+
+ void stop()
+ {
+ std::cout << "--------------- ELOOP STOP---------------" << std::endl;
+ emit stopELoop();
+ }
+
+signals:
+ void stopELoop();
+
+private slots:
+ void fromServer()
+ {
+ std::cout << "--------------- SIGNAL RECEIVED ---------------" << std::endl;
+ }
+
+};
+
+#endif //__THREADPOOLTEST_H__
--- /dev/null
+//*****************************************************************
+/*
+ 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 UdpDataProtocol.cpp
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+#include "UdpDataProtocol.h"
+#include "jacktrip_globals.h"
+#include "JackTrip.h"
+
+#include <cstring>
+#include <iostream>
+#include <cstdlib>
+#include <cerrno>
+#include <stdexcept>
+#include <sys/socket.h> // for POSIX Sockets
+
+using std::cout; using std::endl;
+
+// NOTE: It's better not to use
+// using namespace std;
+// because some functions (like exit()) get confused with QT functions
+
+// sJackMutex definition
+QMutex UdpDataProtocol::sUdpMutex;
+
+//*******************************************************************************
+UdpDataProtocol::UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode,
+ int bind_port, int peer_port,
+ unsigned int udp_redundancy_factor) :
+DataProtocol(jacktrip, runmode, bind_port, peer_port),
+mBindPort(bind_port), mPeerPort(peer_port),
+mRunMode(runmode),
+mAudioPacket(NULL), mFullPacket(NULL),
+mUdpRedundancyFactor(udp_redundancy_factor)
+{
+ if (mRunMode == RECEIVER) {
+ QObject::connect(this, SIGNAL(signalWatingTooLong(int)),
+ jacktrip, SLOT(slotUdpWatingTooLong(int)), Qt::QueuedConnection);
+ }
+}
+
+
+//*******************************************************************************
+UdpDataProtocol::~UdpDataProtocol()
+{
+ delete[] mAudioPacket;
+ delete[] mFullPacket;
+ wait();
+}
+
+
+//*******************************************************************************
+void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP)
+{
+ mPeerAddress.setAddress(peerHostOrIP);
+ // 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("");
+ }
+ /*
+ else {
+ std::cout << "Peer Address set to: "
+ << mPeerAddress.toString().toStdString() << std::endl;
+ cout << gPrintSeparator << endl;
+ usleep(100);
+ }
+ */
+}
+
+
+//*******************************************************************************
+void UdpDataProtocol::bindSocket(QUdpSocket& UdpSocket)
+{
+ QMutexLocker locker(&sUdpMutex);
+
+ // 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(mBindPort); //set local 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.
+ if (mRunMode == SENDER) {
+ // We use the sender as an unconnected UDP socket
+ UdpSocket.setSocketDescriptor(sock_fd, QUdpSocket::BoundState,
+ QUdpSocket::WriteOnly);
+ }
+ else if (mRunMode == RECEIVER) {
+ // Set peer IPv4 Address
+ struct sockaddr_in peer_addr;
+ bzero(&peer_addr, sizeof(peer_addr));
+ peer_addr.sin_family = AF_INET; //AF_INET: IPv4 Protocol
+ peer_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY: let the kernel decide the active address
+ peer_addr.sin_port = htons(mPeerPort); //set local port
+ // Connect the socket and issue a Write shutdown (to make it a
+ // reader socket only)
+ if ( (::inet_pton(AF_INET, mPeerAddress.toString().toLatin1().constData(),
+ &peer_addr.sin_addr)) < 1 )
+ { throw std::runtime_error("ERROR: Invalid address presentation format"); }
+ if ( (::connect(sock_fd, (struct sockaddr *) &peer_addr, sizeof(peer_addr))) < 0)
+ { throw std::runtime_error("ERROR: Could not connect UDP socket"); }
+ if ( (::shutdown(sock_fd,SHUT_WR)) < 0)
+ { throw std::runtime_error("ERROR: Could suntdown SHUT_WR UDP socket"); }
+
+ UdpSocket.setSocketDescriptor(sock_fd, QUdpSocket::ConnectedState,
+ QUdpSocket::ReadOnly);
+ cout << "UDP Socket Receiving in Port: " << mBindPort << endl;
+ cout << gPrintSeparator << endl;
+ }
+
+ // OLD CODE WITHOUT POSIX FIX--------------------------------------------------
+ /*
+ /// \todo if port is already used, try binding in a different port
+ QUdpSocket::BindMode bind_mode;
+ if (mRunMode == RECEIVER) {
+ bind_mode = QUdpSocket::DontShareAddress; }
+ else if (mRunMode == SENDER) { //Share sender socket
+ bind_mode = QUdpSocket::ShareAddress; }
+
+ // QHostAddress::Any : let the kernel decide the active address
+ if ( !UdpSocket.bind(QHostAddress::Any, mBindPort, bind_mode) ) {
+ throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
+ }
+ else {
+ if ( mRunMode == RECEIVER ) {
+ cout << "UDP Socket Receiving in Port: " << mBindPort << endl;
+ cout << gPrintSeparator << endl;
+ }
+ }
+ */
+ // ----------------------------------------------------------------------------
+}
+
+
+//*******************************************************************************
+int UdpDataProtocol::receivePacket(QUdpSocket& UdpSocket, char* buf, const size_t n)
+{
+ // Block until There's something to read
+ while ( (UdpSocket.pendingDatagramSize() < n) && !mStopped ) { QThread::usleep(100); }
+ int n_bytes = UdpSocket.readDatagram(buf, n);
+ return n_bytes;
+}
+
+
+//*******************************************************************************
+int UdpDataProtocol::sendPacket(QUdpSocket& UdpSocket, const QHostAddress& PeerAddress,
+ const char* buf, const size_t n)
+{
+ int n_bytes = UdpSocket.writeDatagram(buf, n, PeerAddress, mPeerPort);
+ return n_bytes;
+}
+
+
+//*******************************************************************************
+void UdpDataProtocol::getPeerAddressFromFirstPacket(QUdpSocket& UdpSocket,
+ QHostAddress& peerHostAddress,
+ uint16_t& port)
+{
+ while ( !UdpSocket.hasPendingDatagrams() ) {
+ msleep(100);
+ }
+ char buf[1];
+ UdpSocket.readDatagram(buf, 1, &peerHostAddress, &port);
+}
+
+
+//*******************************************************************************
+void UdpDataProtocol::run()
+{
+ mStopped = false;
+
+ // Creat and bind sockets
+ QUdpSocket UdpSocket;
+ bindSocket(UdpSocket); // Bind Socket
+ QHostAddress PeerAddress;
+ PeerAddress = mPeerAddress;
+
+ // Setup Audio Packet buffer
+ size_t audio_packet_size = getAudioPacketSizeInBites();
+ //cout << "audio_packet_size: " << audio_packet_size << endl;
+ mAudioPacket = new int8_t[audio_packet_size];
+ std::memset(mAudioPacket, 0, audio_packet_size); // set buffer to 0
+
+ // Setup Full Packet buffer
+ int full_packet_size = mJackTrip->getPacketSizeInBytes();
+ //cout << "full_packet_size: " << full_packet_size << endl;
+ mFullPacket = new int8_t[full_packet_size];
+ std::memset(mFullPacket, 0, full_packet_size); // set buffer to 0
+
+ bool timeout = false; // Time out flag for packets that arrive too late
+
+ // Put header in first packet
+ mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
+
+ // Redundancy Variables
+ // (Algorithm explained at the end of this file)
+ // ---------------------------------------------
+ int full_redundant_packet_size = full_packet_size * mUdpRedundancyFactor;
+ int8_t* full_redundant_packet;
+ full_redundant_packet = new int8_t[full_redundant_packet_size];
+ std::memset(full_redundant_packet, 0, full_redundant_packet_size); // Initialize to 0
+
+ // Set realtime priority (function in jacktrip_globals.h)
+ set_crossplatform_realtime_priority();
+
+ // 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 : {
+ //-----------------------------------------------------------------------------------
+ // 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); }
+ int first_packet_size = UdpSocket.pendingDatagramSize();
+ // The following line is the same as
+ // int8_t* first_packet = new int8_t[first_packet_size];
+ // 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);
+ // Check that peer has the same audio settings
+ mJackTrip->checkPeerSettings(first_packet.get());
+ mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
+ std::cout << "Received Connection for Peer!" << std::endl;
+
+ // Redundancy Variables
+ // --------------------
+ // NOTE: These types need to be the same unsigned integer as the sequence
+ // number in the header. That way, they wrap around in the "same place"
+ uint16_t current_seq_num = 0; // Store current sequence number
+ uint16_t last_seq_num = 0; // Store last package sequence number
+ uint16_t newer_seq_num = 0; // Store newer sequence number
+
+ while ( !mStopped )
+ {
+ // Timer to report packets arriving too late
+ // This QT method gave me a lot of trouble, so I replaced it with my own 'waitForReady'
+ // that uses signals and slots and can also report with packets have not
+ // arrive for a longer time
+ //timeout = UdpSocket.waitForReadyRead(30);
+ timeout = waitForReady(UdpSocket, 60000); //60 seconds
+
+ // OLD CODE WITHOUT REDUNDANCY----------------------------------------------------
+ /*
+ // This is blocking until we get a packet...
+ receivePacket( UdpSocket, reinterpret_cast<char*>(mFullPacket), full_packet_size);
+
+ mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
+
+ // ...so we want to send the packet to the buffer as soon as we get in from
+ // the socket, i.e., non-blocking
+ //mRingBuffer->insertSlotNonBlocking(mAudioPacket);
+ mJackTrip->writeAudioBuffer(mAudioPacket);
+ */
+ //----------------------------------------------------------------------------------
+ receivePacketRedundancy(UdpSocket,
+ full_redundant_packet,
+ full_redundant_packet_size,
+ full_packet_size,
+ current_seq_num,
+ last_seq_num,
+ newer_seq_num);
+ }
+ break; }
+
+ case SENDER : {
+ //-----------------------------------------------------------------------------------
+ while ( !mStopped )
+ {
+ // OLD CODE WITHOUT REDUNDANCY -----------------------------------------------------
+ /*
+ // We block until there's stuff available to read
+ mJackTrip->readAudioBuffer( mAudioPacket );
+ mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
+ // This will send the packet immediately
+ //int bytes_sent = sendPacket( reinterpret_cast<char*>(mFullPacket), full_packet_size);
+ sendPacket( UdpSocket, PeerAddress, reinterpret_cast<char*>(mFullPacket), full_packet_size);
+ */
+ //----------------------------------------------------------------------------------
+ sendPacketRedundancy(UdpSocket,
+ PeerAddress,
+ full_redundant_packet,
+ full_redundant_packet_size,
+ full_packet_size);
+ }
+ break; }
+ }
+}
+
+
+//*******************************************************************************
+bool UdpDataProtocol::waitForReady(QUdpSocket& UdpSocket, int timeout_msec)
+{
+ int loop_resolution_usec = 100; // usecs to wait on each loop
+ int emit_resolution_usec = 10000; // 10 milliseconds
+ int timeout_usec = timeout_msec * 1000;
+ int ellaped_time_usec = 0; // Ellapsed time in milliseconds
+
+ while ( ( !(UdpSocket.hasPendingDatagrams()) && (ellaped_time_usec <= timeout_usec) )
+ && !mStopped ){
+ //cout << mStopped << endl;
+ QThread::usleep(loop_resolution_usec);
+ ellaped_time_usec += loop_resolution_usec;
+
+ if ( !(ellaped_time_usec % emit_resolution_usec) ) {
+ emit signalWatingTooLong(static_cast<int>(ellaped_time_usec/1000));
+ }
+ }
+
+ if ( ellaped_time_usec >= timeout_usec )
+ {
+ emit signalWatingTooLong(ellaped_time_usec/1000);
+ return false;
+ }
+ return true;
+}
+
+
+//*******************************************************************************
+void UdpDataProtocol::printUdpWaitedTooLong(int wait_msec)
+{
+ int wait_time = 30; // msec
+ if ( !(wait_msec%wait_time) ) {
+ std::cerr << "UDP is waited too long (more than " << wait_time << "ms)..." << endl;
+ }
+}
+
+
+//*******************************************************************************
+void UdpDataProtocol::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)
+{
+ // This is blocking until we get a packet...
+ receivePacket( UdpSocket, reinterpret_cast<char*>(full_redundant_packet),
+ full_redundant_packet_size);
+
+ // Get Packet Sequence Number
+ newer_seq_num =
+ mJackTrip->getPeerSequenceNumber(full_redundant_packet);
+ current_seq_num = newer_seq_num;
+
+
+ //cout << current_seq_num << " ";
+ int redun_last_index = 0;
+ for (unsigned int i = 1; i<mUdpRedundancyFactor; i++) {
+ // Check if the package we receive is the next one expected, i.e.,
+ // current_seq_num == (last_seq_num+1)
+ if ( (current_seq_num == (last_seq_num+1))) { break; }
+
+ // if it's not, check the next one until it is the corresponding packet
+ // or there aren't more available packets
+ redun_last_index = i; // index of packet to use in the redundant packet
+ current_seq_num =
+ mJackTrip->getPeerSequenceNumber( full_redundant_packet + (i*full_packet_size) );
+ //cout << current_seq_num << " ";
+ }
+ //cout << endl;
+
+ last_seq_num = newer_seq_num; // Save last read packet
+
+ // Send to audio all available audio packets, in order
+ for (int i = redun_last_index; i>=0; i--) {
+ memcpy(mFullPacket,
+ full_redundant_packet + (i*full_packet_size),
+ full_packet_size);
+ mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
+ mJackTrip->writeAudioBuffer(mAudioPacket);
+ }
+}
+
+//*******************************************************************************
+void UdpDataProtocol::sendPacketRedundancy(QUdpSocket& UdpSocket,
+ QHostAddress& PeerAddress,
+ int8_t* full_redundant_packet,
+ int full_redundant_packet_size,
+ int full_packet_size)
+{
+ mJackTrip->readAudioBuffer( mAudioPacket );
+ mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
+
+ // Move older packets to end of array of redundant packets
+ std::memmove(full_redundant_packet+full_packet_size,
+ full_redundant_packet,
+ full_packet_size*(mUdpRedundancyFactor-1));
+ // Copy new packet to the begining of array
+ std::memcpy(full_redundant_packet,
+ mFullPacket, full_packet_size);
+
+ // 10% (or other number) packet lost simulation.
+ // Uncomment the if to activate
+ //---------------------------------------------------------------------------------
+ //int random_integer = rand();
+ //if ( random_integer > (RAND_MAX/10) )
+ //{
+ sendPacket( UdpSocket, PeerAddress, reinterpret_cast<char*>(full_redundant_packet),
+ full_redundant_packet_size);
+ //}
+ //---------------------------------------------------------------------------------
+
+ mJackTrip->increaseSequenceNumber();
+}
+
+
+/*
+ The Redundancy Algorythmn works as follows. We send a packet that contains
+ a mUdpRedundancyFactor number of packets (header+audio). This big packet looks
+ as follows
+
+ ---------- ------------ -----------------------------------
+ | UDP[n] | | UDP[n-1] | ... | UDP[n-(mUdpRedundancyFactor-1)] |
+ ---------- ------------ -----------------------------------
+
+ Then, for the new audio buffer, we shift everything to the right and send:
+
+ ---------- ------------ -------------------------------------
+ | UDP[n+1] | | UDP[n] | ... | UDP[n-(mUdpRedundancyFactor-1)+1] |
+ ---------- ------------ -------------------------------------
+
+ etc...
+
+ For a redundancy factor of 4, this will look as follows:
+ ---------- ---------- ---------- ----------
+ | UDP[4] | | UDP[3] | | UDP[2] | | UDP[1] |
+ ---------- ---------- ---------- ----------
+
+ ---------- ---------- ---------- ----------
+ | UDP[5] | | UDP[4] | | UDP[3] | | UDP[2] |
+ ---------- ---------- ---------- ----------
+
+ ---------- ---------- ---------- ----------
+ | UDP[6] | | UDP[5] | | UDP[4] | | UDP[3] |
+ ---------- ---------- ---------- ----------
+
+ etc...
+
+ Then, the receiving end checks if the firs packet in the list is the one it should use,
+ otherwise it continure reding the mUdpRedundancyFactor packets until it finds the one that
+ should come next (this can better perfected by just jumping until the correct packet).
+ If it has more than one packet that it hasn't yet received, it sends it to the soundcard
+ one by one.
+*/
--- /dev/null
+//*****************************************************************
+/*
+ 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 UdpDataProtocol.h
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+#ifndef __UDPDATAPROTOCOL_H__
+#define __UDPDATAPROTOCOL_H__
+
+#include <QThread>
+#include <QUdpSocket>
+#include <QHostAddress>
+
+#include "DataProtocol.h"
+#include "jacktrip_types.h"
+#include "jacktrip_globals.h"
+
+/** \brief UDP implementation of DataProtocol class
+ *
+ * The class has a <tt>bind port</tt> and a <tt>peer port</tt>. The meaning of these
+ * depends on the runModeT. If it's a SENDER, <tt>bind port</tt> is the source port and
+ * <tt>peer port</tt> is the destination port for each UDP packet. If it's a RECEIVER,
+ * the <tt>bind port</tt> destination port (for incoming packets) and the <tt>peer port</tt>
+ * is the source port.
+ *
+ * The SENDER and RECEIVER socket can share the same port/address pair (for compatibility
+ * with the JamLink boxes). This is achieved setting
+ * the resusable property in the socket for address and port. You have to
+ * externaly check if the port is already binded if you want to avoid re-binding to the
+ * same port.
+ */
+class UdpDataProtocol : public DataProtocol
+{
+ Q_OBJECT;
+
+public:
+
+ /** \brief The class constructor
+ * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
+ * \param runmode Sets the run mode, use either SENDER or RECEIVER
+ * \param bind_port Port number to bind for this socket (this is the receive or send port depending on the runmode)
+ * \param peer_port Peer port number (this is the receive or send port depending on the runmode)
+ * \param udp_redundancy_factor Number of redundant packets
+ */
+ UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode,
+ int bind_port, int peer_port,
+ unsigned int udp_redundancy_factor = 1);
+
+ /** \brief The class destructor
+ */
+ virtual ~UdpDataProtocol();
+
+ /** \brief Set the Peer address to connect to
+ * \param peerHostOrIP IPv4 number or host name
+ */
+ void setPeerAddress(const char* peerHostOrIP);
+
+ /** \brief Receives a packet. It blocks until a packet is received
+ *
+ * This function makes sure we recieve a complete packet
+ * of size n
+ * \param buf Buffer to store the recieved packet
+ * \param n size of packet to receive
+ * \return number of bytes read, -1 on error
+ */
+ //virtual int receivePacket(char* buf, const size_t n);
+ virtual int receivePacket(QUdpSocket& UdpSocket, char* buf, const size_t n);
+
+ /** \brief Sends a packet
+ *
+ * This function meakes sure we send a complete packet
+ * of size n
+ * \param buf Buffer to send
+ * \param n size of packet to receive
+ * \return number of bytes read, -1 on error
+ */
+ virtual int sendPacket(QUdpSocket& UdpSocket, const QHostAddress& PeerAddress,
+ const char* buf, const size_t n);
+
+ /** \brief Obtains the peer address from the first UDP packet received. This address
+ * is used by the SERVER mode to connect back to the client.
+ * \param peerHostAddress QHostAddress to store the peer address
+ * \param port Receiving port
+ */
+ virtual void getPeerAddressFromFirstPacket(QUdpSocket& UdpSocket,
+ QHostAddress& peerHostAddress,
+ uint16_t& port);
+
+ /** \brief Sets the bind port number
+ */
+ void setBindPort(int port)
+ { mBindPort = port; }
+
+ /** \brief Sets the peer port number
+ */
+ void setPeerPort(int port)
+ { mPeerPort = port; }
+
+ /** \brief Implements the Thread Loop. To start the thread, call start()
+ * ( DO NOT CALL run() )
+ *
+ * This function creats and binds all the socket and start the connection loop thread.
+ */
+ virtual void run();
+
+
+private slots:
+ void printUdpWaitedTooLong(int wait_msec);
+
+
+signals:
+
+ /// \brief Signals when waiting every 10 milliseconds, with the total wait on wait_msec
+ /// \param wait_msec Total wait in milliseconds
+ void signalWatingTooLong(int wait_msec);
+
+
+private:
+
+ /** \brief Binds the UDP socket to the available address and specified port
+ */
+ void bindSocket(QUdpSocket& UdpSocket);
+
+ /** \brief This function blocks until data is available for reading in the
+ * QUdpSocket. The function will timeout after timeout_msec microseconds.
+ *
+ * This function is intended to replace QAbstractSocket::waitForReadyRead which has
+ * some problems with multithreading.
+ *
+ * \return returns true if there is data available for reading;
+ * otherwise it returns false (if an error occurred or the operation timed out)
+ */
+ bool waitForReady(QUdpSocket& UdpSocket, int timeout_msec);
+
+ /** \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
+ */
+ void sendPacketRedundancy(QUdpSocket& UdpSocket,
+ QHostAddress& PeerAddress,
+ int8_t* full_redundant_packet,
+ int full_redundant_packet_size,
+ int full_packet_size);
+
+ int mBindPort; ///< Local Port number to Bind
+ int mPeerPort; ///< Peer Port number
+ const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
+
+ QHostAddress mPeerAddress; ///< The Peer Address
+
+ int8_t* mAudioPacket; ///< Buffer to store Audio Packets
+ int8_t* mFullPacket; ///< Buffer to store Full Packet (audio+header)
+
+ unsigned int mUdpRedundancyFactor; ///< Factor of redundancy
+ static QMutex sUdpMutex; ///< Mutex to make thread safe the binding process
+};
+
+#endif // __UDPDATAPROTOCOL_H__
--- /dev/null
+//*****************************************************************
+/*
+ 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 UdpDataProtocol.cpp
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+#include "UdpDataProtocol.h"
+
+#include <cstring>
+#include <iostream>
+#include <cstdlib>
+#include <cerrno>
+
+// NOTE: It's better not to use
+// using namespace std;
+// because some functions (like exit()) get confused with QT functions
+
+
+
+//*******************************************************************************
+UdpDataProtocol::UdpDataProtocol(const runModeT runmode, const char* peerHostOrIP)
+ : DataProtocol(runmode)
+{
+ setPeerIPv4Address(peerHostOrIP);
+ setBindSocket();
+}
+
+
+//*******************************************************************************
+void UdpDataProtocol::setBindSocket()
+{
+ // UDP socket creation
+ mSockFd = socket(AF_INET, SOCK_DGRAM, 0);
+ if ( mSockFd < 0 ) {
+ std::cerr << "ERROR: UDP Socket Error" << std::endl;
+ std::exit(0);
+ }
+
+ // Bind local address and port
+ /// \todo Bind to a different port in case this one is used by a different instance
+ /// of the program
+ struct sockaddr_in LocalIPv4Addr = getLocalIPv4AddressStruct();
+ int nBind = bind(mSockFd, (struct sockaddr *) &LocalIPv4Addr, sizeof(LocalIPv4Addr));
+ if ( nBind < 0 ) {
+ std::cerr << "ERROR: UDP Socket Bind Error" << std::endl;
+ std::exit(0);
+ }
+
+ std::cout << "Successful socket creation and port binding" << std::endl;
+
+ //Connected UDP
+ struct sockaddr_in PeerIPv4Addr = getPeerIPv4AddressStruct();
+ int nCon = ::connect(mSockFd, (struct sockaddr *) &PeerIPv4Addr, sizeof(PeerIPv4Addr));
+ if ( nCon < 0) {
+ std::cerr << "ERROR: UDP Socket Connect Error" << std::endl;
+ std::exit(0);
+ }
+}
+
+
+//*******************************************************************************
+// Adapted form Stevens' "Unix Network Programming", third edition
+// Page 88 (readn)
+size_t UdpDataProtocol::receivePacket(char* buff, size_t n)
+{
+ size_t nleft;
+ ssize_t nread;
+ char* ptr;
+
+ ptr = buff;
+ nleft = n;
+ while (nleft > 0) {
+ if ( (nread = ::read(mSockFd, ptr, nleft)) < 0) {
+ if (errno == EINTR)
+ nread = 0; // and call read() again
+ else
+ return(-1);
+ } else if (nread == 0)
+ break; // EOF
+
+ nleft -= nread;
+ ptr += nread;
+ }
+ return(n - nleft);
+}
+
+
+
+//*******************************************************************************
+// Adapted form Stevens' "Unix Network Programming", third edition
+// Page 88 (writen)
+// Write "n" bytes to a descriptor
+size_t UdpDataProtocol::sendPacket(const char* buff, size_t n)
+{
+ size_t nleft;
+ ssize_t nwritten;
+ const char* ptr;
+
+ ptr = buff;
+ nleft = n;
+ while (nleft > 0) {
+ if ( (nwritten = ::write(mSockFd, ptr, nleft)) <= 0) {
+ if (nwritten < 0 && errno == EINTR)
+ nwritten = 0; // and call write() again
+ else
+ return(-1); // error
+ }
+
+ nleft -= nwritten;
+ ptr += nwritten;
+ }
+ return(n);
+}
+
--- /dev/null
+//*****************************************************************
+/*
+ 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 UdpDataProtocol.h
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+#ifndef __UDPDATAPROTOCOL_H__
+#define __UDPDATAROTOCOL_H__
+
+#include "DataProtocol.h"
+
+/** \brief UDP implementation of DataProtocol class
+ *
+ *
+ *
+ */
+class UdpDataProtocol : public DataProtocol
+{
+public:
+
+ /** \brief The class constructor
+ * \param runmode Sets the run mode, use either SENDER or RECEIVER
+ * \param peerHostOrIP IPv4 number or host name
+ */
+ UdpDataProtocol(const runModeT runmode, const char* peerHostOrIP);
+
+ /** \brief The class destructor
+ */
+ virtual ~UdpDataProtocol() {};
+
+ /** \brief Receives a packet
+ *
+ * This function makes sure we recieve a complete packet
+ * of size n
+ * \param buf Buffer to store the recieved packet
+ * \param n size of packet to receive
+ * \return number of bytes read, -1 on error
+ */
+ virtual size_t receivePacket(char* buf, size_t n);
+
+ /** \brief Sends a packet
+ *
+ * This function meakes sure we send a complete packet
+ * of size n
+ * \param buff Buffer to send
+ * \param n size of packet to receive
+ * \return number of bytes read, -1 on error
+ */
+ virtual size_t sendPacket(const char* buff, size_t n);
+
+ //virtual void run();
+
+
+private:
+
+ void setBindSocket();
+
+ int mSockFd; ///< Socket file descriptor
+};
+
+#endif
--- /dev/null
+//*****************************************************************
+/*
+ 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 UdpMasterListener.cpp
+ * \author Juan-Pablo Caceres and Chris Chafe
+ * \date September 2008
+ */
+
+#include <iostream>
+#include <cstdlib>
+#include <stdexcept>
+
+#include "UdpMasterListener.h"
+#include "JackTripWorker.h"
+#include "jacktrip_globals.h"
+
+using std::cout; using std::endl;
+
+
+//*******************************************************************************
+UdpMasterListener::UdpMasterListener(int server_port) :
+ mJTWorker(NULL),
+ mServerPort(server_port),
+ mStopped(false),
+ mTotalRunningThreads(0)
+{
+ // Register JackTripWorker with the master listener
+ mJTWorker = new JackTripWorker(this);
+ mThreadPool.setExpiryTimeout(3000); // msec (-1) = forever
+ // Inizialize IP addresses
+ for (int i = 0; i<gMaxThreads; i++) {
+ mActiveAddress[i][0] = 0; // 32-bit ints
+ mActiveAddress[i][1] = 0; // 32-bit ints
+ }
+ // Set the base dynamic port
+ // The Dynamic and/or Private Ports are those from 49152 through 65535
+ mBasePort = ( random() % ( (65535 - gMaxThreads) - 49152 ) ) + 49152;
+}
+
+
+//*******************************************************************************
+UdpMasterListener::~UdpMasterListener()
+{
+ mThreadPool.waitForDone ();
+ delete mJTWorker;
+}
+
+
+//*******************************************************************************
+void UdpMasterListener::run()
+{
+ mStopped = false;
+
+ // Create objects on the stack
+ QUdpSocket MasterUdpSocket;
+ QHostAddress PeerAddress;
+ uint16_t peer_port; // Ougoing Peer port, in case they're not using the default
+
+ // Bind the socket to the well known port
+ bindUdpSocket(MasterUdpSocket, mServerPort);
+
+ char buf[1];
+ cout << "Server Listening in UDP Port: " << mServerPort << endl;
+ cout << "Waiting for client..." << endl;
+ cout << "=======================================================" << endl;
+ while ( !mStopped )
+ {
+ //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);
+ }
+}
+
+
+//*******************************************************************************
+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
+ mThreadPool.start(mJTWorker, QThread::TimeCriticalPriority); //send one thread to the pool
+}
+
+
+//*******************************************************************************
+void UdpMasterListener::bindUdpSocket(QUdpSocket& udpsocket, int port)
+{
+ // QHostAddress::Any : let the kernel decide the active address
+ if ( !udpsocket.bind(QHostAddress::Any,
+ port, QUdpSocket::DefaultForPlatform) ) {
+ //std::cerr << "ERROR: could not bind UDP socket" << endl;
+ //std::exit(1);
+ throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
+ }
+ else {
+ cout << "UDP Socket Receiving in Port: " << port << endl;
+ }
+}
+
+
+//*******************************************************************************
+// check by comparing 32-bit addresses
+int UdpMasterListener::isNewAddress(uint32_t address, uint16_t port)
+{
+ /// \todo Add the port number in the comparison, i.e., compart IP/port pair
+
+ 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 ) {
+ mActiveAddress[id][0] = address;
+ mActiveAddress[id][1] = port;
+ }
+ return ((busyAddress) ? -1 : id);
+}
+
+
+//*******************************************************************************
+int UdpMasterListener::releasePort(int id)
+{
+ mActiveAddress[id][0] = 0;
+ mActiveAddress[id][1] = 0;
+ return 0; /// \todo Check if we really need to return an argument here
+}
--- /dev/null
+//*****************************************************************
+/*
+ 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 UdpMasterListener.h
+ * \author Juan-Pablo Caceres and Chris Chafe
+ * \date September 2008
+ */
+
+#ifndef __UDPMASTERLISTENER_H__
+#define __UDPMASTERLISTENER_H__
+
+#include <iostream>
+
+#include <QThread>
+#include <QThreadPool>
+#include <QUdpSocket>
+#include <QHostAddress>
+
+#include "jacktrip_types.h"
+#include "jacktrip_globals.h"
+class JackTripWorker; // forward declaration
+
+
+/** \brief Master UDP listener on the Server.
+ *
+ * This creates a server that will listen on the well know port (the server port) and will
+ * spawn JackTrip threads into the Thread pool. Clients request a connection.
+ */
+class UdpMasterListener : public QThread
+{
+ Q_OBJECT;
+
+public:
+ UdpMasterListener(int server_port = gServerUdpPort);
+ virtual ~UdpMasterListener();
+
+ /** \brief Implements the Thread Loop. To start the thread, call start()
+ * ( DO NOT CALL run() )
+ */
+ void run();
+
+ /// \brief Stops the execution of the Thread
+ void stop() { mStopped = true; };
+
+ int releasePort(int id);
+
+private slots:
+ void testRecieve()
+ {
+ std::cout << "========= TEST RECEIVE SLOT ===========" << std::endl;
+ }
+
+signals:
+ void Listening();
+ void ClientAddressSet();
+
+
+private:
+ /** \brief Binds a QUdpSocket. It chooses the available (active) interface.
+ * \param udpsocket a QUdpSocket
+ * \param port Port number
+ */
+ static void bindUdpSocket(QUdpSocket& udpsocket, int port);
+
+ /* \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);
+
+ /** \brief Check if address is already handled, if not add to array
+ * \param IPv4 address as a number
+ * \return -1 if address is busy, id number if not
+ */
+ int isNewAddress(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
+ QThreadPool mThreadPool; ///< The Thread Pool
+
+ int mServerPort; //< Server known port number
+ int mBasePort;
+ uint32_t mActiveAddress[gMaxThreads][2]; ///< Active addresses pool numbers (32 bits IPv4 numbers)
+ QHash<uint32_t, uint16_t> mActiveAddresPortPair;
+
+ /// Boolean stop the execution of the thread
+ volatile bool mStopped;
+ int mTotalRunningThreads; ///< Number of Threads running in the pool
+};
+
+
+#endif //__UDPMASTERLISTENER_H__
--- /dev/null
+#!/bin/bash
+## Created by Juan-Pablo Caceres
+
+# Check for Platform
+platform='unknown'
+unamestr=`uname`
+if [[ "$unamestr" == 'Linux' ]]; then
+ echo "Building on Linux"
+ platform='linux'
+elif [[ "$unamestr" == 'Darwin' ]]; then
+ echo "Building on Mac OS X"
+ platform='macosx'
+fi
+
+# Set qmake command name
+if [[ $platform == 'linux' ]]; then
+ QCMD=qmake-qt4
+elif [[ $platform == 'macosx' ]]; then
+ QCMD=qmake
+fi
+
+# Build
+$QCMD jacktrip.pro
+make clean
+make release
--- /dev/null
+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__
--- /dev/null
+#******************************
+# Created by Juan-Pablo Caceres
+#******************************
+
+CONFIG += qt thread debug_and_release build_all
+CONFIG(debug, debug|release) {
+ TARGET = jacktrip_debug
+ } else {
+ TARGET = jacktrip
+ }
+QT -= gui
+QT += network
+INCLUDEPATH+=/usr/local/include
+LIBS += -ljack -lm
+macx {
+ message(MAC OS X)
+ CONFIG -= app_bundle
+ CONFIG += x86 #ppc
+ LIBS += -framework CoreAudio
+ DEFINES += __MAC_OSX__
+ }
+linux-g++ {
+ message(Linux)
+ QMAKE_CXXFLAGS += -g -O2
+ DEFINES += __LINUX__
+ }
+DESTDIR = .
+QMAKE_CLEAN += ./jacktrip ./jacktrip_debug
+target.path = /usr/bin
+INSTALLS += target
+
+# Input
+HEADERS += DataProtocol.h \
+ JackAudioInterface.h \
+ JackTrip.h \
+ jacktrip_globals.h \
+ jacktrip_types.h \
+ JackTripThread.h \
+ JackTripWorker.h \
+ JackTripWorkerMessages.h \
+ LoopBack.h \
+ NetKS.h \
+ PacketHeader.h \
+ ProcessPlugin.h \
+ RingBuffer.h \
+ RingBufferWavetable.h \
+ Settings.h \
+ TestRingBuffer.h \
+ ThreadPoolTest.h \
+ UdpDataProtocol.h \
+ UdpMasterListener.h \
+ jacktrip_tests.cpp
+SOURCES += DataProtocol.cpp \
+ JackAudioInterface.cpp \
+ JackTrip.cpp \
+ jacktrip_globals.cpp \
+ jacktrip_main.cpp \
+ jacktrip_tests.cpp \
+ JackTripThread.cpp \
+ JackTripWorker.cpp \
+ LoopBack.cpp \
+ PacketHeader.cpp \
+ ProcessPlugin.cpp \
+ RingBuffer.cpp \
+ Settings.cpp \
+ tests.cpp \
+ UdpDataProtocol.cpp \
+ UdpMasterListener.cpp
--- /dev/null
+//*****************************************************************
+/*
+ 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 globals.cpp
+ * \author Juan-Pablo Caceres
+ * \date August 2008
+ */
+
+#include "jacktrip_globals.h"
+#include "jacktrip_types.h"
+
+#include <stdio.h>
+
+#if defined ( __LINUX__ )
+#include <sched.h>
+#endif //__LINUX__
+
+#if defined ( __MAC_OSX__ )
+#include <mach/mach.h>
+#include <mach/thread_policy.h>
+
+//#include <mach/processor.h>
+
+//#include <mach/clock.h>
+//#include <sys/kernel.h>
+//#include <mach/kern/clock.h>
+
+//#include <Kernel/kern/clock.h>
+//#include <kern/kern_types.h>
+//m#include <kern/kern_types.h>
+//#include <Kernel/kern/clock.h>
+//#include <kern/clock.h>
+
+
+//#include <assert.h>
+//#include <CoreServices/CoreServices.h>
+//#include <mach/mach.h>
+//#include <mach/mach_time.h>
+//#include <unistd.h>
+
+
+
+
+//#include <mach/machine.h>
+//#include <mach/mach_time.h>
+//#include <mach/thread_call.h>
+//#include <mach/processor.h>
+//#include <mach/macro_help.h>
+
+#endif //__MAC_OSX__
+
+
+#if defined ( __MAC_OSX__ )
+//*******************************************************************************
+//http://developer.apple.com/DOCUMENTATION/Darwin/Conceptual/KernelProgramming/scheduler/chapter_8_section_4.html
+//http://lists.apple.com/archives/darwin-dev/2007/Sep/msg00035.html
+int set_realtime(int period, int computation, int constraint)
+{
+ //AbsoluteTime time;
+ //clock_get_uptime((uint64_t *)&time);
+
+ //uint64_t result;
+ //clock_get_uptime(&result);
+ //clock_get_system_microtime(&result,&result);
+
+ struct thread_time_constraint_policy ttcpolicy;
+ int ret;
+
+ ttcpolicy.period=period; // HZ/160
+ ttcpolicy.computation=computation; // HZ/3300;
+ ttcpolicy.constraint=constraint; // HZ/2200;
+ ttcpolicy.preemptible=1;
+
+ if ((ret=thread_policy_set(mach_thread_self(),
+ THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&ttcpolicy,
+ THREAD_TIME_CONSTRAINT_POLICY_COUNT)) != KERN_SUCCESS) {
+ fprintf(stderr, "set_realtime() failed.\n");
+ return 0;
+ }
+ return 1;
+}
+#endif //__MAC_OSX__
+
+
+#if defined ( __LINUX__ )
+//*******************************************************************************
+int get_fifo_priority (bool half)
+{
+ int min, max, priority;
+ min = sched_get_priority_min (SCHED_FIFO);
+ max = sched_get_priority_max (SCHED_FIFO);
+ if (half) {
+ priority = (max - (max - min) / 2); }
+ else {
+ priority = max; }
+
+ //priority=min;
+ return priority;
+}
+#endif //__LINUX__
+
+
+#if defined ( __LINUX__ )
+//*******************************************************************************
+int set_fifo_priority (bool half)
+{
+ struct sched_param p;
+ int priority;
+ // scheduling priority
+
+
+ if (true) // (!getuid () || !geteuid ())
+ {
+ priority = get_fifo_priority (half);
+ p.sched_priority = priority;
+
+ if (sched_setscheduler (0, SCHED_FIFO, &p) == -1)
+ {
+ fprintf (stderr,
+ "\ncould not activate scheduling with priority %d\n",
+ priority);
+ return -1;
+ }
+ seteuid (getuid ());
+ //fprintf (stderr,
+ // "\nset scheduling priority to %d (SCHED_FIFO)\n",
+ // priority);
+ }
+ else
+ {
+ fprintf (stderr,
+ "\ninsufficient privileges to set scheduling priority\n");
+ priority = 0;
+ }
+ return priority;
+}
+#endif //__LINUX__
+
+
+#if defined ( __LINUX__ )
+//*******************************************************************************
+int set_realtime_priority (void)
+{
+ struct sched_param schp;
+
+ memset (&schp, 0, sizeof (schp));
+ schp.sched_priority = sched_get_priority_max (SCHED_FIFO);
+ if (sched_setscheduler (0, SCHED_FIFO, &schp) != 0)
+ {
+ perror ("set_scheduler");
+ return -1;
+ }
+ return 0;
+}
+#endif //__LINUX__
+
+void set_crossplatform_realtime_priority()
+{
+#if defined ( __LINUX__ )
+ set_fifo_priority (false);
+#endif //__LINUX__
+#if defined ( __MAC_OSX__ )
+ set_realtime(1250000,60000,90000);
+#endif //__MAC_OSX__
+}
+
+
--- /dev/null
+//*****************************************************************
+/*
+ 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 globals.cpp
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+#ifndef __JACKTRIP_GLOBALS_H__
+#define __JACKTRIP_GLOBALS_H__
+
+#include "JackAudioInterface.h"
+
+
+//namespace JackTrip/// \todo Add this namespace
+
+const char* const gVersion = "1.0.5"; ///< JackTrip version
+
+//*******************************************************************************
+/// \name Default Values
+//@{
+const int gDefaultNumInChannels = 2;
+const int gDefaultNumOutChannels = 2;
+const JackAudioInterface::audioBitResolutionT gDefaultBitResolutionMode =
+ JackAudioInterface::BIT16;
+const int gDefaultQueueLength = 4;
+const int gDefaultOutputQueueLength = 4;
+//@}
+
+
+//*******************************************************************************
+/// \name Network related ports
+//@{
+const int gDefaultPort = 4464; ///< Default JackTrip Port
+//const int gInputPort_0 = 4464; ///< Input base port
+//const int gOutputPort_0 = 4465; ///< Output base port
+//const int gDefaultSendPort = 4464; ///< Default for to use to send packet
+//@}
+
+
+//*******************************************************************************
+/// \name Separator for terminal printing
+//@{
+const char* const gPrintSeparator = "---------------------------------------------------------";
+//@}
+
+
+//*******************************************************************************
+/// \name Global flags
+//@{
+extern int gVerboseFlag; ///< Verbose mode flag declaration
+//@}
+
+
+//*******************************************************************************
+/// \name JackAudio
+//@{
+const int gJackBitResolution = 32; ///< Audio Bit Resolution of the Jack Server
+//@}
+
+
+//*******************************************************************************
+/// \name Global Functions
+
+void set_crossplatform_realtime_priority();
+
+//@{
+// Linux Specific Functions
+#if defined ( __LINUX__ )
+/// \brief Returns fifo priority
+int get_fifo_priority (bool half);
+/// \brief Set fifo priority (if user has sufficient privileges).
+int set_fifo_priority (bool half);
+int set_realtime_priority (void);
+#endif //__LINUX__
+//@}
+
+//@{
+// Mac OS X Specific Functions
+#if defined ( __MAC_OSX__ )
+int set_realtime(int period, int computation, int constraint);
+#endif //__MAC_OSX__
+//@}
+
+
+//*******************************************************************************
+/// \name JackTrip Server parameters
+//@{
+/// Maximum Threads that can be run at the same time
+const int gMaxThreads = 290; // some pthread limit around 297?
+
+/// Public well-known UDP port to where the clients will connect
+const int gServerUdpPort = 4464;
+//@}
+
+
+#endif
--- /dev/null
+//*****************************************************************
+/*
+ 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 main.cpp
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+#include <iostream>
+
+#include <QCoreApplication>
+
+#include "JackAudioInterface.h"
+#include "UdpDataProtocol.h"
+#include "RingBuffer.h"
+#include "JackTrip.h"
+#include "Settings.h"
+//#include "TestRingBuffer.h"
+#include "LoopBack.h"
+#include "PacketHeader.h"
+#include "JackTripThread.h"
+#include "jacktrip_tests.cpp"
+
+#include "jacktrip_globals.h"
+
+using std::cout; using std::endl;
+
+
+int main(int argc, char** argv)
+{
+ QCoreApplication app(argc, argv);
+
+ //--------TESTS--------------------------
+ //main_tests(argc, argv); // test functions
+ //while (true) sleep(9999);
+ //---------------------------------------
+
+ // Get Settings from user
+ // ----------------------
+ try
+ {
+ // Get Settings from user
+ // ----------------------
+ Settings* settings = new Settings;
+ settings->parseInput(argc, argv);
+ settings->startJackTrip();
+ }
+ catch ( const std::exception & e )
+ {
+ std::cerr << "ERROR:" << endl;
+ std::cerr << e.what() << endl;
+ std::cerr << "Exiting JackTrip..." << endl;
+ std::cerr << gPrintSeparator << endl;
+ return -1;
+ }
+ return app.exec();
+}
--- /dev/null
+//*****************************************************************
+/*
+ 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 jacktrip_tests.cpp
+ * \author Juan-Pablo Caceres
+ * \date September 2008
+ */
+
+#include <iostream>
+
+#include <QVector>
+
+#include "JackTripThread.h"
+
+using std::cout; using std::endl;
+
+const int num_jacktrips = 5;
+const int base_port = 4464;
+
+
+void main_tests(int argc, char** argv);
+void test_threads_server();
+void test_threads_client(const char* peer_address);
+
+
+void main_tests(int /*argc*/, char** argv)
+{
+ if (argv[1][0] == 's' )
+ {
+ test_threads_server();
+ }
+ else if (argv[1][0] == 'c' )
+ {
+ test_threads_client("171.64.197.209");
+ }
+}
+
+
+// Test many servers running at the same time
+void test_threads_server()
+{
+ QVector<JackTripThread*> jacktrips;
+ jacktrips.resize(num_jacktrips);
+ int port_num;
+ for (int i = 0; i < num_jacktrips; i++)
+ {
+ port_num = base_port + i*10;
+ cout << "Port Number: " << port_num << endl;
+ jacktrips[i] = new JackTripThread(JackTrip::SERVER);
+ jacktrips[i]->setPort(port_num);
+ jacktrips[i]->start(QThread::NormalPriority);
+ //sleep(1);
+ }
+}
+
+
+// Test many servers running at the same time
+void test_threads_client(const char* peer_address)
+{
+ QVector<JackTripThread*> jacktrips;
+ jacktrips.resize(num_jacktrips);
+ int port_num;
+ for (int i = 0; i < num_jacktrips; i++)
+ {
+ port_num = base_port + i*10;
+ cout << "Port Number: " << port_num << endl;
+ jacktrips[i] = new JackTripThread(JackTrip::CLIENT);
+ jacktrips[i]->setPort(port_num);
+ jacktrips[i]->setPeerAddress(peer_address);
+ //sleep(1);
+ jacktrips[i]->start(QThread::NormalPriority);
+ //sleep(1);
+ }
+}
--- /dev/null
+//*****************************************************************
+/*
+ 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 jacktrip_types_jacktrip.h
+ * \author Juan-Pablo Caceres
+ * \date June 2008
+ */
+
+
+#ifndef __JACKTRIP_TYPES_H__
+#define __JACKTRIP_TYPES_H__
+
+#include <jack/types.h>
+#include <QtGlobal> //For QT4 types
+
+//-------------------------------------------------------------------------------
+/** \name Audio typedefs
+ *
+ */
+//-------------------------------------------------------------------------------
+//@{
+/// Audio sample type
+typedef jack_default_audio_sample_t sample_t;
+//@}
+
+
+//-------------------------------------------------------------------------------
+/** \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;
+//@}
+
+
+#endif
--- /dev/null
+//*****************************************************************
+/*
+ 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);
+ }
+
+}