Add JACK utility functions in libardour and test
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 15 Jul 2013 16:46:35 +0000 (12:46 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 15 Jul 2013 16:46:35 +0000 (12:46 -0400)
This contains much of the code present in the GUI EngineDialog class
but refactored with some added windows bits.

libs/ardour/ardour/jack_utils.h [new file with mode: 0644]
libs/ardour/jack_utils.cc [new file with mode: 0644]
libs/ardour/test/jack_utils_test.cc [new file with mode: 0644]
libs/ardour/test/jack_utils_test.h [new file with mode: 0644]
libs/ardour/wscript

diff --git a/libs/ardour/ardour/jack_utils.h b/libs/ardour/ardour/jack_utils.h
new file mode 100644 (file)
index 0000000..353724f
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+    Copyright (C) 2011 Tim Mayberry
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <stdint.h>
+
+#include <vector>
+#include <map>
+#include <string>
+
+namespace ARDOUR {
+
+       // Names for the drivers on all possible systems
+       extern const char * const portaudio_driver_name;
+       extern const char * const coreaudio_driver_name;
+       extern const char * const alsa_driver_name;
+       extern const char * const oss_driver_name;
+       extern const char * const freebob_driver_name;
+       extern const char * const ffado_driver_name;
+       extern const char * const netjack_driver_name;
+       extern const char * const dummy_driver_name;
+
+       /**
+        * Get a list of possible JACK audio driver names based on platform
+        */
+       void get_jack_audio_driver_names (std::vector<std::string>& driver_names);
+
+       /**
+        * Get the default JACK audio driver based on platform
+        */
+       void get_jack_default_audio_driver_name (std::string& driver_name);
+
+       /**
+        * Get a list of possible JACK midi driver names based on platform
+        */
+       void get_jack_midi_system_names (const std::string& driver, std::vector<std::string>& driver_names);
+
+       /**
+        * Get the default JACK midi driver based on platform
+        */
+       void get_jack_default_midi_system_name (const std::string& driver_name, std::string& midi_system);
+
+       /**
+        * Get a list of possible samplerates supported be JACK
+        */
+       void get_jack_sample_rate_strings (std::vector<std::string>& sample_rates);
+
+       /**
+        * @return The default samplerate
+        */
+       std::string get_jack_default_sample_rate ();
+
+       /**
+        * @return true if sample rate string was able to be converted
+        */
+       bool get_jack_sample_rate_value_from_string (const std::string& srs, uint32_t& srv);
+
+       /**
+        * Get a list of possible period sizes supported be JACK
+        */
+       void get_jack_period_size_strings (std::vector<std::string>& samplerates);
+
+       /**
+        * @return The default period size
+        */
+       std::string get_jack_default_period_size ();
+
+       /**
+        * @return true if period size string was able to be converted
+        */
+       bool get_jack_period_size_value_from_string (const std::string& pss, uint32_t& psv);
+
+       /**
+        * These are driver specific I think, so it may require a driver arg
+        * in future
+        */
+       void get_jack_dither_mode_strings (const std::string& driver, std::vector<std::string>& dither_modes);
+
+       /**
+        * @return The default dither mode
+        */
+       std::string get_jack_default_dither_mode (const std::string& driver);
+
+       /**
+        * @return Estimate of latency
+        *
+        * API matches current use in GUI
+        */
+       std::string get_jack_latency_string (std::string samplerate, float periods, std::string period_size);
+
+       /**
+        * @return true if a JACK server is running
+        */
+       bool jack_server_running ();
+
+       /**
+        * Key being a readable name to display in a GUI
+        * Value being name used in a jack commandline
+        */
+       typedef std::map<std::string, std::string> device_map_t;
+
+       /**
+        * Use library specific code to find out what what devices exist for a given
+        * driver that might work in JACK. There is no easy way to find out what
+        * modules the JACK server supports so guess based on platform. For instance
+        * portaudio is cross-platform but we only return devices if built for
+        * windows etc
+        */
+       void get_jack_alsa_device_names (device_map_t& devices);
+       void get_jack_portaudio_device_names (device_map_t& devices);
+       void get_jack_coreaudio_device_names (device_map_t& devices);
+       void get_jack_oss_device_names (device_map_t& devices);
+       void get_jack_freebob_device_names (device_map_t& devices);
+       void get_jack_ffado_device_names (device_map_t& devices);
+       void get_jack_netjack_device_names (device_map_t& devices);
+       void get_jack_dummy_device_names (device_map_t& devices);
+
+       /*
+        * @return true if there were devices found for the driver
+        *
+        * @param driver The driver name returned by get_jack_audio_driver_names
+        * @param devices The map used to insert the drivers into, devices will be cleared before
+        * adding the available drivers
+        */
+       bool get_jack_device_names_for_audio_driver (const std::string& driver, device_map_t& devices);
+
+       /*
+        * @return a list of readable device names for a specific driver.
+        */
+       std::vector<std::string> get_jack_device_names_for_audio_driver (const std::string& driver);
+
+       /**
+        * @return true if the driver supports playback and recording
+        * on separate devices
+        */
+       bool get_jack_audio_driver_supports_two_devices (const std::string& driver);
+
+       bool get_jack_audio_driver_supports_latency_adjustment (const std::string& driver);
+
+       bool get_jack_audio_driver_supports_setting_period_count (const std::string& driver);
+
+       /**
+        * The possible names to use to try and find servers, this includes
+        * any file extensions like .exe on Windows
+        *
+        * @return true if the JACK application names for this platform could be guessed
+        */
+       bool get_jack_server_application_names (std::vector<std::string>& server_names);
+
+       /**
+        * Sets the PATH environment variable to contain directories likely to contain
+        * JACK servers so that if the JACK server is auto-started it can find the server
+        * executable.
+        *
+        * This is only modifies PATH on the mac at the moment.
+        */
+       void set_path_env_for_jack_autostart (const std::vector<std::string>&);
+
+       /**
+        * Get absolute paths to directories that might contain JACK servers on the system
+        *
+        * @return true if !server_paths.empty()
+        */
+       bool get_jack_server_dir_paths (std::vector<std::string>& server_dir_paths);
+
+       /**
+        * Get absolute paths to JACK servers on the system
+        *
+        * @return true if a server was found
+        */
+       bool get_jack_server_paths (const std::vector<std::string>& server_dir_paths,
+                       const std::vector<std::string>& server_names,
+                       std::vector<std::string>& server_paths);
+
+
+       bool get_jack_server_paths (std::vector<std::string>& server_paths);
+
+       /**
+        * Get absolute path to default JACK server
+        */
+       bool get_jack_default_server_path (std::string& server_path);
+
+       /**
+        * @return The name of the jack server config file
+        */
+       std::string get_jack_server_config_file_name ();
+
+       std::string get_jack_server_user_config_dir_path ();
+
+       std::string get_jack_server_user_config_file_path ();
+
+       bool write_jack_config_file (const std::string& config_file_path, const std::string& command_line);
+
+       struct JackCommandLineOptions {
+
+               // see implementation for defaults
+               JackCommandLineOptions ();
+
+               //operator bool
+               //operator ostream
+
+               std::string      server_path;
+               uint32_t         timeout;
+               bool             no_mlock;
+               uint32_t         ports_max;
+               bool             realtime;
+               uint32_t         priority;
+               bool             unlock_gui_libs;
+               bool             verbose;
+               bool             temporary;
+               bool             playback_only;
+               bool             capture_only;
+               std::string      driver;
+               std::string      input_device;
+               std::string      output_device;
+               uint32_t         num_periods;
+               uint32_t         period_size;
+               uint32_t         samplerate;
+               uint32_t         input_latency;
+               uint32_t         output_latency;
+               bool             hardware_metering;
+               bool             hardware_monitoring;
+               std::string      dither_mode;
+               bool             force16_bit;
+               bool             soft_mode;
+               std::string      midi_driver;
+       };
+
+       /**
+        * @return true if able to build a valid command line based on options
+        */
+       bool get_jack_command_line_string (const JackCommandLineOptions& options, std::string& command_line);
+
+       /**
+        * We don't need this at the moment because the gui stores all its settings
+        */
+       //std::string get_jack_command_line_from_config_file (const std::string& config_file_path);
+
+       /**
+        * Temporary for WIN32 only as jack_client_open doesn't start the server on that platform
+        *
+        * @return true if server was able to be started
+        */
+       bool start_jack_server (const std::string& command_line);
+
+}
diff --git a/libs/ardour/jack_utils.cc b/libs/ardour/jack_utils.cc
new file mode 100644 (file)
index 0000000..29f7ca4
--- /dev/null
@@ -0,0 +1,947 @@
+/*
+    Copyright (C) 2010 Paul Davis
+    Copyright (C) 2011 Tim Mayberry
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef WAF_BUILD
+#include "libardour-config.h"
+#endif
+
+#ifdef HAVE_ALSA
+#include <alsa/asoundlib.h>
+#endif
+
+#ifdef __APPLE__
+#include <CoreAudio/CoreAudio.h>
+#include <CoreFoundation/CFString.h>
+#include <sys/param.h>
+#include <mach-o/dyld.h>
+#endif
+
+#ifdef HAVE_PORTAUDIO
+#include <portaudio.h>
+#endif
+
+#include <jack/jack.h>
+
+#include <fstream>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <glibmm/miscutils.h>
+
+#include "pbd/epa.h"
+#include "pbd/error.h"
+#include "pbd/convert.h"
+#include "pbd/file_utils.h"
+#include "pbd/search_path.h"
+
+#include "ardour/jack_utils.h"
+
+#ifdef __APPLE
+#include <CFBundle.h>
+#endif
+
+#include "i18n.h"
+
+using namespace std;
+using namespace PBD;
+
+namespace ARDOUR {
+       // The pretty driver names
+       const char * const portaudio_driver_name = X_("Portaudio");
+       const char * const coreaudio_driver_name = X_("CoreAudio");
+       const char * const alsa_driver_name = X_("ALSA");
+       const char * const oss_driver_name = X_("OSS");
+       const char * const freebob_driver_name = X_("FreeBoB");
+       const char * const ffado_driver_name = X_("FFADO");
+       const char * const netjack_driver_name = X_("NetJACK");
+       const char * const dummy_driver_name = X_("Dummy");
+}
+
+namespace {
+
+       // The real driver names
+       const char * const portaudio_driver_command_line_name = X_("portaudio");
+       const char * const coreaudio_driver_command_line_name = X_("coreaudio");
+       const char * const alsa_driver_command_line_name = X_("alsa");
+       const char * const oss_driver_command_line_name = X_("oss");
+       const char * const freebob_driver_command_line_name = X_("freebob");
+       const char * const ffado_driver_command_line_name = X_("firewire");
+       const char * const netjack_driver_command_line_name = X_("netjack");
+       const char * const dummy_driver_command_line_name = X_("dummy");
+
+       // should we provide more "pretty" names like above?
+       const char * const alsaseq_midi_driver_name = X_("seq");
+       const char * const alsaraw_midi_driver_name = X_("raw");
+       const char * const winmme_midi_driver_name = X_("winmme");
+       const char * const coremidi_midi_driver_name = X_("coremidi");
+
+       // this should probably be translated
+       const char * const default_device_name = X_("Default");
+}
+
+std::string
+get_none_string ()
+{
+       return _("None");
+}
+
+void
+ARDOUR::get_jack_audio_driver_names (vector<string>& audio_driver_names)
+{
+#ifdef WIN32
+       audio_driver_names.push_back (portaudio_driver_name);
+#elif __APPLE__
+       audio_driver_names.push_back (coreaudio_driver_name);
+#else
+#ifdef HAVE_ALSA
+       audio_driver_names.push_back (alsa_driver_name);
+#endif
+       audio_driver_names.push_back (oss_driver_name);
+       audio_driver_names.push_back (freebob_driver_name);
+       audio_driver_names.push_back (ffado_driver_name);
+#endif
+       audio_driver_names.push_back (netjack_driver_name);
+       audio_driver_names.push_back (dummy_driver_name);
+}
+
+void
+ARDOUR::get_jack_default_audio_driver_name (string& audio_driver_name)
+{
+       vector<string> drivers;
+       get_jack_audio_driver_names (drivers);
+       audio_driver_name = drivers.front ();
+}
+
+void
+ARDOUR::get_jack_midi_system_names (const string& driver, vector<string>& midi_system_names)
+{
+       midi_system_names.push_back (get_none_string ());
+#ifdef WIN32
+       midi_system_names.push_back (winmme_midi_driver_name);
+#elif __APPLE__
+       midi_system_names.push_back (coreaudio_midi_driver_name);
+#else
+#ifdef HAVE_ALSA
+       if (driver == alsa_driver_name) {
+               midi_system_names.push_back (alsaseq_midi_driver_name);
+               midi_system_names.push_back (alsaraw_midi_driver_name);
+       }
+#endif
+#endif
+}
+
+void
+ARDOUR::get_jack_default_midi_system_name (const string& driver, string& midi_system_name)
+{
+       vector<string> drivers;
+       get_jack_midi_system_names (driver, drivers);
+       midi_system_name = drivers.front ();
+}
+
+void
+ARDOUR::get_jack_sample_rate_strings (vector<string>& samplerates)
+{
+       // do these really need to be translated?
+       samplerates.push_back (_("8000Hz"));
+       samplerates.push_back (_("22050Hz"));
+       samplerates.push_back (_("44100Hz"));
+       samplerates.push_back (_("48000Hz"));
+       samplerates.push_back (_("88200Hz"));
+       samplerates.push_back (_("96000Hz"));
+       samplerates.push_back (_("192000Hz"));
+}
+
+string
+ARDOUR::get_jack_default_sample_rate ()
+{
+       return _("48000Hz");
+}
+
+void
+ARDOUR::get_jack_period_size_strings (std::vector<std::string>& period_sizes)
+{
+       period_sizes.push_back ("32");
+       period_sizes.push_back ("64");
+       period_sizes.push_back ("128");
+       period_sizes.push_back ("256");
+       period_sizes.push_back ("512");
+       period_sizes.push_back ("1024");
+       period_sizes.push_back ("2048");
+       period_sizes.push_back ("4096");
+       period_sizes.push_back ("8192");
+}
+
+string
+ARDOUR::get_jack_default_period_size ()
+{
+       return "1024";
+}
+
+void
+ARDOUR::get_jack_dither_mode_strings (const string& driver, vector<string>& dither_modes)
+{
+       dither_modes.push_back (get_none_string ());
+
+       if (driver == alsa_driver_name ) {
+               dither_modes.push_back (_("Triangular"));
+               dither_modes.push_back (_("Rectangular"));
+               dither_modes.push_back (_("Shaped"));
+       }
+}
+
+string
+ARDOUR::get_jack_default_dither_mode (const string& driver)
+{
+       return get_none_string ();
+}
+
+string
+ARDOUR::get_jack_latency_string (string samplerate, float periods, string period_size)
+{
+       uint32_t rate = atoi (samplerate);
+       float psize = atof (period_size);
+
+       char buf[32];
+       snprintf (buf, sizeof(buf), "%.1fmsec", (periods * psize) / (rate/1000.0));
+
+       return buf;
+}
+
+bool
+get_jack_command_line_audio_driver_name (const string& driver_name, string& command_line_name)
+{
+       using namespace ARDOUR;
+       if (driver_name == portaudio_driver_name) {
+               command_line_name = portaudio_driver_command_line_name;
+               return true;
+       } else if (driver_name == coreaudio_driver_name) {
+               command_line_name = coreaudio_driver_command_line_name;
+               return true;
+       } else if (driver_name == alsa_driver_name) {
+               command_line_name = alsa_driver_command_line_name;
+               return true;
+       } else if (driver_name == oss_driver_name) {
+               command_line_name = oss_driver_command_line_name;
+               return true;
+       } else if (driver_name == freebob_driver_name) {
+               command_line_name = freebob_driver_command_line_name;
+               return true;
+       } else if (driver_name == ffado_driver_name) {
+               command_line_name = ffado_driver_command_line_name;
+               return true;
+       } else if (driver_name == netjack_driver_name) {
+               command_line_name = netjack_driver_command_line_name;
+               return true;
+       } else if (driver_name == dummy_driver_name) {
+               command_line_name = dummy_driver_command_line_name;
+               return true;
+       }
+       return false;
+}
+
+bool
+get_jack_command_line_audio_device_name (const string& driver_name,
+               const string& device_name, string& command_line_device_name)
+{
+       using namespace ARDOUR;
+       device_map_t devices;
+
+       get_jack_device_names_for_audio_driver (driver_name, devices);
+
+       for (device_map_t::const_iterator i = devices.begin (); i != devices.end(); ++i) {
+               if (i->first == device_name) {
+                       command_line_device_name = i->second;
+                       return true;
+               }
+       }
+       return false;
+}
+
+bool
+get_jack_command_line_dither_mode (const string& dither_mode, string& command_line_dither_mode)
+{
+       using namespace ARDOUR;
+
+       if (dither_mode == _("Triangular")) {
+               command_line_dither_mode = "triangular";
+               return true;
+       } else if (dither_mode == _("Rectangular")) {
+               command_line_dither_mode = "rectangular";
+               return true;
+       } else if (dither_mode == _("Shaped")) {
+               command_line_dither_mode = "shaped";
+               return true;
+       }
+
+       return false;
+}
+
+bool
+ARDOUR::jack_server_running ()
+{
+        EnvironmentalProtectionAgency* global_epa = EnvironmentalProtectionAgency::get_global_epa ();
+        boost::scoped_ptr<EnvironmentalProtectionAgency> current_epa;
+
+        /* revert all environment settings back to whatever they were when ardour started
+         */
+
+        if (global_epa) {
+                current_epa.reset (new EnvironmentalProtectionAgency(true)); /* will restore settings when we leave scope */
+                global_epa->restore ();
+        }
+
+       jack_status_t status;
+       jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status);
+
+       if (status == 0) {
+               jack_client_close (c);
+               return true;
+       }
+       return false;
+
+}
+
+void
+ARDOUR::get_jack_alsa_device_names (device_map_t& devices)
+{
+#ifdef HAVE_ALSA
+       snd_ctl_t *handle;
+       snd_ctl_card_info_t *info;
+       snd_pcm_info_t *pcminfo;
+       snd_ctl_card_info_alloca(&info);
+       snd_pcm_info_alloca(&pcminfo);
+       string devname;
+       int cardnum = -1;
+       int device = -1;
+
+       while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
+
+               devname = "hw:";
+               devname += PBD::to_string (cardnum, std::dec);
+
+               if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) {
+
+                       while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
+
+                               snd_pcm_info_set_device (pcminfo, device);
+                               snd_pcm_info_set_subdevice (pcminfo, 0);
+                               snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK);
+
+                               if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
+                                       devname += ',';
+                                       devname += PBD::to_string (device, std::dec);
+                                       devices.insert (std::make_pair (snd_pcm_info_get_name (pcminfo), devname));
+                               }
+                       }
+
+                       snd_ctl_close(handle);
+               }
+       }
+#endif
+}
+
+#ifdef __APPLE__
+static OSStatus
+getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
+{
+       UInt32 size = sizeof(CFStringRef);
+       CFStringRef UI;
+       OSStatus res = AudioDeviceGetProperty(id, 0, false,
+               kAudioDevicePropertyDeviceUID, &size, &UI);
+       if (res == noErr)
+               CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
+       CFRelease(UI);
+       return res;
+}
+#endif
+
+void
+ARDOUR::get_jack_coreaudio_device_names (device_map_t& devices)
+{
+#ifdef __APPLE__
+       // Find out how many Core Audio devices are there, if any...
+       // (code snippet gently "borrowed" from St?hane Letz jackdmp;)
+       OSStatus err;
+       Boolean isWritable;
+       UInt32 outSize = sizeof(isWritable);
+
+       err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
+                                          &outSize, &isWritable);
+       if (err == noErr) {
+               // Calculate the number of device available...
+               int numCoreDevices = outSize / sizeof(AudioDeviceID);
+               // Make space for the devices we are about to get...
+               AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
+               err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
+                                              &outSize, (void *) coreDeviceIDs);
+               if (err == noErr) {
+                       // Look for the CoreAudio device name...
+                       char coreDeviceName[256];
+                       UInt32 nameSize;
+
+                       for (int i = 0; i < numCoreDevices; i++) {
+
+                               nameSize = sizeof (coreDeviceName);
+
+                               /* enforce duplex devices only */
+
+                               err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
+                                                                0, true, kAudioDevicePropertyStreams,
+                                                                &outSize, &isWritable);
+
+                               if (err != noErr || outSize == 0) {
+                                       continue;
+                               }
+
+                               err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
+                                                                0, false, kAudioDevicePropertyStreams,
+                                                                &outSize, &isWritable);
+
+                               if (err != noErr || outSize == 0) {
+                                       continue;
+                               }
+
+                               err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
+                                                                0, true, kAudioDevicePropertyDeviceName,
+                                                                &outSize, &isWritable);
+                               if (err == noErr) {
+                                       err = AudioDeviceGetProperty(coreDeviceIDs[i],
+                                                                    0, true, kAudioDevicePropertyDeviceName,
+                                                                    &nameSize, (void *) coreDeviceName);
+                                       if (err == noErr) {
+                                               char drivername[128];
+
+                                               // this returns the unique id for the device
+                                               // that must be used on the commandline for jack
+
+                                               if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
+                                                       devices.insert (make_pair (coreDeviceName, drivername));
+                                               }
+                                       }
+                               }
+                       }
+               }
+               delete [] coreDeviceIDs;
+       }
+#endif
+}
+
+void
+ARDOUR::get_jack_portaudio_device_names (device_map_t& devices)
+{
+#ifdef HAVE_PORTAUDIO
+       if (Pa_Initialize() != paNoError) {
+               return;
+       }
+
+       for (PaDeviceIndex i = 0; i < Pa_GetDeviceCount (); ++i) {
+               string api_name;
+               string readable_name;
+               string jack_device_name;
+               const PaDeviceInfo* device_info = Pa_GetDeviceInfo(i);
+
+               if (device_info != NULL) { // it should never be ?
+                       api_name = Pa_GetHostApiInfo (device_info->hostApi)->name;
+                       readable_name = api_name + " " + device_info->name;
+                       jack_device_name = api_name + "::" + device_info->name;
+                       devices.insert (make_pair (readable_name, jack_device_name));
+               }
+       }
+       Pa_Terminate();
+#endif
+}
+
+void
+ARDOUR::get_jack_oss_device_names (device_map_t& devices)
+{
+       devices.insert (make_pair (default_device_name, default_device_name));
+}
+
+void
+ARDOUR::get_jack_freebob_device_names (device_map_t& devices)
+{
+       devices.insert (make_pair (default_device_name, default_device_name));
+}
+
+void
+ARDOUR::get_jack_ffado_device_names (device_map_t& devices)
+{
+       devices.insert (make_pair (default_device_name, default_device_name));
+}
+
+void
+ARDOUR::get_jack_netjack_device_names (device_map_t& devices)
+{
+       devices.insert (make_pair (default_device_name, default_device_name));
+}
+
+void
+ARDOUR::get_jack_dummy_device_names (device_map_t& devices)
+{
+       devices.insert (make_pair (default_device_name, default_device_name));
+}
+
+bool
+ARDOUR::get_jack_device_names_for_audio_driver (const string& driver_name, device_map_t& devices)
+{
+       devices.clear();
+
+       if (driver_name == portaudio_driver_name) {
+               get_jack_portaudio_device_names (devices);
+       } else if (driver_name == coreaudio_driver_name) {
+               get_jack_coreaudio_device_names (devices);
+       } else if (driver_name == alsa_driver_name) {
+               get_jack_alsa_device_names (devices);
+       } else if (driver_name == oss_driver_name) {
+               get_jack_oss_device_names (devices);
+       } else if (driver_name == freebob_driver_name) {
+               get_jack_freebob_device_names (devices);
+       } else if (driver_name == ffado_driver_name) {
+               get_jack_ffado_device_names (devices);
+       } else if (driver_name == netjack_driver_name) {
+               get_jack_netjack_device_names (devices);
+       } else if (driver_name == dummy_driver_name) {
+               get_jack_dummy_device_names (devices);
+       }
+
+       return !devices.empty();
+}
+
+
+std::vector<std::string>
+ARDOUR::get_jack_device_names_for_audio_driver (const string& driver_name)
+{
+       std::vector<std::string> readable_names;
+       device_map_t devices;
+
+       get_jack_device_names_for_audio_driver (driver_name, devices);
+
+       for (device_map_t::const_iterator i = devices.begin (); i != devices.end(); ++i) {
+               readable_names.push_back (i->first);
+       }
+
+       return readable_names;
+}
+
+bool
+ARDOUR::get_jack_audio_driver_supports_two_devices (const string& driver)
+{
+       return (driver == alsa_driver_name || driver == oss_driver_name);
+}
+
+bool
+ARDOUR::get_jack_audio_driver_supports_latency_adjustment (const string& driver)
+{
+       return (driver == alsa_driver_name || driver == coreaudio_driver_name ||
+                       driver == ffado_driver_name || driver == portaudio_driver_name);
+}
+
+bool
+ARDOUR::get_jack_audio_driver_supports_setting_period_count (const string& driver)
+{
+       return !(driver == dummy_driver_name || driver == coreaudio_driver_name ||
+                       driver == portaudio_driver_name);
+}
+
+bool
+ARDOUR::get_jack_server_application_names (std::vector<std::string>& server_names)
+{
+#ifdef WIN32
+       server_names.push_back ("jackd.exe");
+#else
+       server_names.push_back ("jackd");
+       server_names.push_back ("jackdmp");
+#endif
+       return !server_names.empty();
+}
+
+void
+ARDOUR::set_path_env_for_jack_autostart (const vector<std::string>& dirs)
+{
+#ifdef __APPLE__
+       // push it back into the environment so that auto-started JACK can find it.
+       // XXX why can't we just expect OS X users to have PATH set correctly? we can't ...
+       setenv ("PATH", SearchPath(dirs).to_string(), 1);
+#endif
+}
+
+bool
+ARDOUR::get_jack_server_dir_paths (vector<std::string>& server_dir_paths)
+{
+#ifdef __APPLE__
+       /* this magic lets us finds the path to the OSX bundle, and then
+          we infer JACK's location from there
+       */
+
+       char execpath[MAXPATHLEN+1];
+       uint32_t pathsz = sizeof (execpath);
+
+       _NSGetExecutablePath (execpath, &pathsz);
+
+       server_dir_paths.push_back (Glib::path_get_dirname (execpath));
+#endif
+
+       SearchPath sp(string(g_getenv("PATH")));
+
+#ifdef WIN32
+       gchar *install_dir = g_win32_get_package_installation_directory_of_module (NULL);
+       if (install_dir) {
+               sp.push_back (install_dir);
+               g_free (install_dir);
+       }
+       // don't try and use a system wide JACK install yet.
+#else
+       if (sp.empty()) {
+               sp.push_back ("/usr/bin");
+               sp.push_back ("/bin");
+               sp.push_back ("/usr/local/bin");
+               sp.push_back ("/opt/local/bin");
+       }
+#endif
+
+       std::copy (sp.begin(), sp.end(), std::back_inserter(server_dir_paths));
+
+       return !server_dir_paths.empty();
+}
+
+bool
+ARDOUR::get_jack_server_paths (const vector<std::string>& server_dir_paths,
+               const vector<string>& server_names,
+               vector<std::string>& server_paths)
+{
+       for (vector<string>::const_iterator i = server_names.begin(); i != server_names.end(); ++i) {
+               find_matching_files_in_directories (server_dir_paths, Glib::PatternSpec(*i), server_paths);
+       }
+       return !server_paths.empty();
+}
+
+bool
+ARDOUR::get_jack_server_paths (vector<std::string>& server_paths)
+{
+       vector<std::string> server_dirs;
+
+       if (!get_jack_server_dir_paths (server_dirs)) {
+               return false;
+       }
+
+       vector<string> server_names;
+
+       if (!get_jack_server_application_names (server_names)) {
+               return false;
+       }
+
+       if (!get_jack_server_paths (server_dirs, server_names, server_paths)) {
+               return false;
+       }
+
+       return !server_paths.empty();
+}
+
+bool
+ARDOUR::get_jack_default_server_path (std::string& server_path)
+{
+       vector<std::string> server_paths;
+
+       if (!get_jack_server_paths (server_paths)) {
+               return false;
+       }
+
+       server_path = server_paths.front ();
+       return true;
+}
+
+string
+quote_string (const string& str)
+{
+       return "\"" + str + "\"";
+}
+
+ARDOUR::JackCommandLineOptions::JackCommandLineOptions ()
+       : server_path ()
+       , timeout(0)
+       , no_mlock(false)
+       , ports_max(128)
+       , realtime(true)
+       , priority(0)
+       , unlock_gui_libs(false)
+       , verbose(false)
+       , temporary(true)
+       , driver()
+       , input_device()
+       , output_device()
+       , num_periods(2)
+       , period_size(1024)
+       , samplerate(48000)
+       , input_latency(0)
+       , output_latency(0)
+       , hardware_metering(false)
+       , hardware_monitoring(false)
+       , dither_mode()
+       , force16_bit(false)
+       , soft_mode(false)
+       , midi_driver()
+{
+
+}
+
+bool
+ARDOUR::get_jack_command_line_string (const JackCommandLineOptions& options, string& command_line)
+{
+       vector<string> args;
+
+       args.push_back (options.server_path);
+
+#ifdef WIN32
+       // must use sync mode on windows
+       args.push_back ("-S");
+
+       // this needs to be added now on windows
+       if (!options.midi_driver.empty () && options.midi_driver != get_none_string ()) {
+               args.push_back ("-X");
+               args.push_back (options.midi_driver);
+       }
+#endif
+
+       if (options.timeout) {
+               args.push_back ("-t");
+               args.push_back (to_string (options.timeout, std::dec));
+       }
+
+       if (options.no_mlock) {
+               args.push_back ("-m");
+       }
+
+       args.push_back ("-p");
+       args.push_back (to_string(options.ports_max, std::dec));
+
+       if (options.realtime) {
+               args.push_back ("-R");
+               if (options.priority != 0) {
+                       args.push_back ("-P");
+                       args.push_back (to_string(options.priority, std::dec));
+               }
+       } else {
+               args.push_back ("-r");
+       }
+
+       if (options.unlock_gui_libs) {
+               args.push_back ("-u");
+       }
+
+       if (options.verbose) {
+               args.push_back ("-v");
+       }
+
+#ifndef WIN32
+       if (options.temporary) {
+               args.push_back ("-T");
+       }
+#endif
+
+       string command_line_driver_name;
+
+       if (!get_jack_command_line_audio_driver_name (options.driver, command_line_driver_name)) {
+               return false;
+       }
+
+       args.push_back ("-d");
+       args.push_back (command_line_driver_name);
+
+       if (options.output_device.empty() && options.input_device.empty()) {
+               return false;
+       }
+
+       string command_line_input_device_name;
+       string command_line_output_device_name;
+
+       if (!get_jack_command_line_audio_device_name (options.driver,
+               options.input_device, command_line_input_device_name))
+       {
+               return false;
+       }
+
+       if (!get_jack_command_line_audio_device_name (options.driver,
+               options.output_device, command_line_output_device_name))
+       {
+               return false;
+       }
+
+       if (options.input_device.empty()) {
+               // playback only
+               if (options.output_device.empty()) {
+                       return false;
+               }
+               args.push_back ("-P");
+       } else if (options.output_device.empty()) {
+               // capture only
+               if (options.input_device.empty()) {
+                       return false;
+               }
+               args.push_back ("-C");
+       } else if (options.input_device != options.output_device) {
+               // capture and playback on two devices if supported
+               if (get_jack_audio_driver_supports_two_devices (options.driver)) {
+                       args.push_back ("-C");
+                       args.push_back (command_line_input_device_name);
+                       args.push_back ("-P");
+                       args.push_back (command_line_output_device_name);
+               } else {
+                       return false;
+               }
+       }
+
+       if (get_jack_audio_driver_supports_setting_period_count (options.driver)) {
+               args.push_back ("-n");
+               args.push_back (to_string (options.num_periods, std::dec));
+       }
+
+       args.push_back ("-r");
+       args.push_back (to_string (options.samplerate, std::dec));
+
+       args.push_back ("-p");
+       args.push_back (to_string (options.period_size, std::dec));
+
+       if (get_jack_audio_driver_supports_latency_adjustment (options.driver)) {
+               if (options.input_latency) {
+                       args.push_back ("-I");
+                       args.push_back (to_string (options.input_latency, std::dec));
+               }
+               if (options.output_latency) {
+                       args.push_back ("-0");
+                       args.push_back (to_string (options.output_latency, std::dec));
+               }
+       }
+
+       if (options.input_device == options.output_device && options.input_device != default_device_name) {
+               args.push_back ("-d");
+               args.push_back (command_line_input_device_name);
+       }
+
+       if (options.driver == alsa_driver_name) {
+               if (options.hardware_metering) {
+                       args.push_back ("-M");
+               }
+               if (options.hardware_monitoring) {
+                       args.push_back ("-H");
+               }
+
+               string command_line_dither_mode;
+               if (get_jack_command_line_dither_mode (options.dither_mode, command_line_dither_mode)) {
+                       args.push_back ("-z");
+                       args.push_back (command_line_dither_mode);
+               }
+               if (options.force16_bit) {
+                       args.push_back ("-S");
+               }
+               if (options.soft_mode) {
+                       args.push_back ("-s");
+               }
+
+               if (!options.midi_driver.empty() && options.midi_driver != get_none_string ()) {
+                       args.push_back ("-X");
+                       args.push_back (options.midi_driver);
+               }
+       }
+
+       ostringstream oss;
+
+       for (vector<string>::const_iterator i = args.begin(); i != args.end();) {
+#ifdef WIN32
+               oss << quote_string (*i);
+#else
+               oss << *i;
+#endif
+               if (++i != args.end()) oss << ' ';
+       }
+
+       command_line = oss.str();
+       return true;
+}
+
+string
+ARDOUR::get_jack_server_config_file_name ()
+{
+       return ".jackdrc";
+}
+
+std::string
+ARDOUR::get_jack_server_user_config_dir_path ()
+{
+       return Glib::get_home_dir ();
+}
+
+std::string
+ARDOUR::get_jack_server_user_config_file_path ()
+{
+       return Glib::build_filename (get_jack_server_user_config_dir_path (), get_jack_server_config_file_name ());
+}
+
+bool
+ARDOUR::write_jack_config_file (const std::string& config_file_path, const string& command_line)
+{
+       ofstream jackdrc (config_file_path.c_str());
+
+       if (!jackdrc) {
+               error << string_compose (_("cannot open JACK rc file %1 to store parameters"), config_file_path) << endmsg;
+               return false;
+       }
+
+       jackdrc << command_line << endl;
+       jackdrc.close ();
+       return true;
+}
+
+bool
+ARDOUR::start_jack_server (const string& command_line)
+{
+#ifdef WIN32
+       STARTUPINFO si;
+       PROCESS_INFORMATION pi;
+       char * cmdline = g_strdup (command_line.c_str());
+
+       memset (&si, 0, sizeof (si));
+       si.cb = sizeof (&si);
+       memset (&pi, 0, sizeof (pi));
+
+       if (!CreateProcess (
+                       NULL,                  // No module name, use command line
+                       cmdline,
+                       NULL,                  // Process handle not inheritable
+                       NULL,                  // Thread handle not inheritable
+                       FALSE,                 // set handle inheritance to false
+                       0,                     // No creation flags
+                       NULL,                  // Use parents environment block
+                       NULL,                  // Use parents starting directory
+                       &si,
+                       &pi))
+       {
+               error << string_compose ("cannot start JACK server: %s", g_win32_error_message (GetLastError ())) << endmsg;
+       }
+
+       g_free (cmdline);
+
+       // wait for 2 seconds for server to start
+       for (int i = 0; i < 8; ++i) {
+               Sleep (250); // 1/4 second
+               if (jack_server_running ()) return true;
+       }
+#endif
+       return false;
+}
diff --git a/libs/ardour/test/jack_utils_test.cc b/libs/ardour/test/jack_utils_test.cc
new file mode 100644 (file)
index 0000000..ed80237
--- /dev/null
@@ -0,0 +1,315 @@
+
+#include <stdexcept>
+
+#ifdef WIN32
+#include <windows.h> // only for Sleep
+#endif
+
+#include <glibmm/miscutils.h>
+
+#include "ardour/jack_utils.h"
+
+#include "jack_utils_test.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION (JackUtilsTest);
+
+using namespace std;
+using namespace ARDOUR;
+
+void
+JackUtilsTest::test_driver_names ()
+{
+       vector<string> driver_names;
+
+       get_jack_audio_driver_names (driver_names);
+
+       CPPUNIT_ASSERT(!driver_names.empty());
+
+       cout << endl;
+       cout << "Number of possible JACK Audio drivers found on this system: " << driver_names.size () << endl;
+
+       for (vector<string>::const_iterator i = driver_names.begin(); i != driver_names.end(); ++i) {
+               cout << "JACK Audio driver found: " << *i << endl;
+       }
+
+       string default_audio_driver;
+       get_jack_default_audio_driver_name (default_audio_driver);
+
+       cout << "The default audio driver on this system is: " << default_audio_driver << endl;
+
+       driver_names.clear();
+
+       get_jack_midi_system_names (default_audio_driver, driver_names);
+
+       CPPUNIT_ASSERT(!driver_names.empty());
+
+       cout << "Number of possible JACK MIDI drivers found on this system for default audio driver: " << driver_names.size () << endl;
+
+       for (vector<string>::const_iterator i = driver_names.begin(); i != driver_names.end(); ++i) {
+               cout << "JACK MIDI driver found: " << *i << endl;
+       }
+
+       string default_midi_driver;
+       get_jack_default_midi_system_name (default_audio_driver, default_midi_driver);
+
+       cout << "The default midi driver on this system is: " << default_midi_driver << endl;
+}
+
+string
+devices_string (const vector<string>& devices)
+{
+       std::string str;
+       for (vector<string>::const_iterator i = devices.begin(); i != devices.end();) {
+               str += *i;
+               if (++i != devices.end()) str += ", ";
+       }
+       return str;
+}
+
+void
+JackUtilsTest::test_device_names ()
+{
+       vector<string> driver_names;
+
+       get_jack_audio_driver_names (driver_names);
+
+       CPPUNIT_ASSERT(!driver_names.empty());
+
+       cout << endl;
+
+       for (vector<string>::const_iterator i = driver_names.begin(); i != driver_names.end(); ++i) {
+               string devices = devices_string (get_jack_device_names_for_audio_driver (*i));
+               cout << "JACK Audio driver found: " << *i << " with devices: " << devices << endl;
+       }
+}
+
+void
+JackUtilsTest::test_samplerates ()
+{
+       vector<string> samplerates;
+
+       get_jack_sample_rate_strings (samplerates);
+       cout << endl;
+       cout << "Number of possible Samplerates supported by JACK: " << samplerates.size () << endl;
+
+       for (vector<string>::const_iterator i = samplerates.begin(); i != samplerates.end(); ++i) {
+               cout << "Samplerate: " << *i << endl;
+       }
+}
+
+void
+JackUtilsTest::test_period_sizes ()
+{
+       vector<string> period_sizes;
+
+       get_jack_period_size_strings (period_sizes);
+       cout << endl;
+       cout << "Number of possible Period sizes supported by JACK: " << period_sizes.size () << endl;
+
+       for (vector<string>::const_iterator i = period_sizes.begin(); i != period_sizes.end(); ++i) {
+               cout << "Period size: " << *i << endl;
+       }
+}
+
+void
+JackUtilsTest::test_dither_modes ()
+{
+       vector<string> driver_names;
+
+       get_jack_audio_driver_names (driver_names);
+
+       CPPUNIT_ASSERT(!driver_names.empty());
+
+       cout << endl;
+
+       for (vector<string>::const_iterator i = driver_names.begin(); i != driver_names.end(); ++i) {
+               vector<string> dither_modes;
+
+               get_jack_dither_mode_strings (*i, dither_modes);
+               cout << "Number of possible Dither Modes supported by JACK driver " << *i <<
+                       ": " << dither_modes.size () << endl;
+               for (vector<string>::const_iterator j = dither_modes.begin(); j != dither_modes.end(); ++j) {
+                       cout << "Dither Mode: " << *j << endl;
+               }
+               cout << endl;
+       }
+
+}
+
+void
+JackUtilsTest::test_connect_server ()
+{
+       cout << endl;
+       if (jack_server_running ()) {
+               cout << "Jack server running " << endl;
+       } else {
+               cout << "Jack server not running " << endl;
+       }
+}
+
+void
+JackUtilsTest::test_set_jack_path_env ()
+{
+       cout << endl;
+
+       bool path_env_set = false;
+
+       string path_env = Glib::getenv ("PATH", path_env_set);
+
+       if (path_env_set) {
+               cout << "PATH env set to: " << path_env << endl;
+       } else {
+               cout << "PATH env not set" << endl;
+       }
+       vector<string> server_dirs;
+       get_jack_server_dir_paths (server_dirs);
+       set_path_env_for_jack_autostart (server_dirs);
+
+       path_env_set = false;
+
+       path_env = Glib::getenv ("PATH", path_env_set);
+
+       CPPUNIT_ASSERT (path_env_set);
+
+       cout << "After set_jack_path_env PATH env set to: " << path_env << endl;
+}
+
+void
+JackUtilsTest::test_server_paths ()
+{
+       cout << endl;
+
+       vector<std::string> server_dirs;
+
+       CPPUNIT_ASSERT (get_jack_server_dir_paths (server_dirs));
+
+       cout << "Number of Directories that may contain JACK servers: " << server_dirs.size () << endl;
+
+       for (vector<std::string>::const_iterator i = server_dirs.begin(); i != server_dirs.end(); ++i) {
+               cout << "JACK server directory path: " << *i << endl;
+       }
+
+       vector<string> server_names;
+
+       CPPUNIT_ASSERT (get_jack_server_application_names (server_names));
+
+       cout << "Number of possible JACK server names on this system: " << server_names.size () << endl;
+
+       for (vector<string>::const_iterator i = server_names.begin(); i != server_names.end(); ++i) {
+               cout << "JACK server name: " << *i << endl;
+       }
+
+       vector<std::string> server_paths;
+
+       CPPUNIT_ASSERT (get_jack_server_paths (server_dirs, server_names, server_paths));
+
+       cout << "Number of JACK servers on this system: " << server_paths.size () << endl;
+
+       for (vector<std::string>::const_iterator i = server_paths.begin(); i != server_paths.end(); ++i) {
+               cout << "JACK server path: " << *i << endl;
+       }
+
+       vector<std::string> server_paths2;
+
+       CPPUNIT_ASSERT (get_jack_server_paths (server_paths2));
+
+       CPPUNIT_ASSERT (server_paths.size () == server_paths2.size ());
+
+       std::string default_server_path;
+
+       CPPUNIT_ASSERT (get_jack_default_server_path (default_server_path));
+
+       cout << "The default JACK server on this system: " << default_server_path << endl;
+}
+
+void
+JackUtilsTest::test_config ()
+{
+
+}
+
+void
+JackUtilsTest::test_command_line ()
+{
+       cout << endl;
+
+       JackCommandLineOptions options;
+
+       CPPUNIT_ASSERT (get_jack_default_server_path (options.server_path));
+
+       get_jack_default_audio_driver_name (options.driver);
+
+       string command_line;
+
+       // should fail, haven't set any device yet
+       CPPUNIT_ASSERT (!get_jack_command_line_string (options, command_line));
+
+       vector<string> devices = get_jack_device_names_for_audio_driver (options.driver);
+
+       if (!devices.empty()) {
+               options.input_device = devices.front ();
+               options.output_device = devices.front ();
+       } else {
+               cout << "No audio devices available using default JACK driver using Dummy driver" << endl;
+               options.driver = dummy_driver_name;
+               devices = get_jack_device_names_for_audio_driver (options.driver);
+               CPPUNIT_ASSERT (!devices.empty ());
+               options.input_device = devices.front ();
+               options.output_device = devices.front ();
+       }
+
+       options.input_device = devices.front ();
+       options.output_device = devices.front ();
+
+       string midi_driver;
+
+       get_jack_default_midi_system_name (options.driver, options.midi_driver);
+
+       // this at least should create a valid jack command line
+       CPPUNIT_ASSERT (get_jack_command_line_string (options, command_line));
+
+       cout << "Default JACK command line: " << command_line << endl;
+}
+
+void
+JackUtilsTest::test_start_server ()
+{
+#ifdef WIN32
+       cout << endl;
+
+       JackCommandLineOptions options;
+
+       CPPUNIT_ASSERT (get_jack_default_server_path (options.server_path));
+
+       cout << "Starting JACK server at path: " << options.server_path << endl;
+
+       get_jack_default_audio_driver_name (options.driver);
+
+       vector<string> devices = get_jack_device_names_for_audio_driver (options.driver);
+
+       if (!devices.empty()) {
+               options.input_device = devices.front ();
+               options.output_device = devices.front ();
+       } else {
+               cout << "No audio devices available using default JACK driver using Dummy driver" << endl;
+               options.driver = dummy_driver_name;
+               devices = get_jack_device_names_for_audio_driver (options.driver);
+               CPPUNIT_ASSERT (!devices.empty ());
+               options.input_device = devices.front ();
+               options.output_device = devices.front ();
+       }
+
+       string command_line;
+       // this at least should create a valid jack command line
+       CPPUNIT_ASSERT (get_jack_command_line_string (options, command_line));
+
+       cout << "Calling start_jack_server with command line: " << command_line << endl;
+
+       CPPUNIT_ASSERT (start_jack_server (command_line));
+
+       // sleep for 10 seconds
+       Sleep (10*1000);
+
+       CPPUNIT_ASSERT (jack_server_running ());
+#endif
+}
diff --git a/libs/ardour/test/jack_utils_test.h b/libs/ardour/test/jack_utils_test.h
new file mode 100644 (file)
index 0000000..6a42d1d
--- /dev/null
@@ -0,0 +1,33 @@
+
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class JackUtilsTest : public CppUnit::TestFixture
+{
+       CPPUNIT_TEST_SUITE (JackUtilsTest);
+       CPPUNIT_TEST (test_driver_names);
+       CPPUNIT_TEST (test_device_names);
+       CPPUNIT_TEST (test_samplerates);
+       CPPUNIT_TEST (test_period_sizes);
+       CPPUNIT_TEST (test_dither_modes);
+       CPPUNIT_TEST (test_connect_server);
+       CPPUNIT_TEST (test_set_jack_path_env);
+       CPPUNIT_TEST (test_server_paths);
+       CPPUNIT_TEST (test_config);
+       CPPUNIT_TEST (test_command_line);
+       CPPUNIT_TEST (test_start_server);
+       CPPUNIT_TEST_SUITE_END ();
+
+public:
+       void test_driver_names ();
+       void test_device_names ();
+       void test_samplerates ();
+       void test_period_sizes ();
+       void test_dither_modes ();
+       void test_connect_server ();
+       void test_set_jack_path_env ();
+       void test_server_paths ();
+       void test_config ();
+       void test_command_line ();
+       void test_start_server ();
+};
index 256ff1c6c0b0ce04afdf651aaf1ed600d361a965..3afd4ce552eef8f74cdfc25d7b3ff7152968cde9 100644 (file)
@@ -2,6 +2,7 @@
 from waflib.extras import autowaf as autowaf
 from waflib import Options
 import os
+import sys
 import re
 import subprocess
 
@@ -99,6 +100,7 @@ libardour_sources = [
         'io.cc',
         'io_processor.cc',
         'jack_slave.cc',
+        'jack_utils.cc',
         'kmeterdsp.cc',
         'ladspa_plugin.cc',
         'ladspa_search_path.cc',
@@ -240,6 +242,12 @@ def configure(conf):
                       atleast_version='0.3.2')
     autowaf.check_pkg(conf, 'jack', uselib_store='JACK',
                       atleast_version='0.118.2')
+    if Options.options.dist_target == 'auto':
+        if re.search ("linux", sys.platform) != None:
+            autowaf.check_pkg(conf, 'alsa', uselib_store='ALSA')
+    if Options.options.dist_target == 'mingw':
+        autowaf.check_pkg(conf, 'portaudio-2.0', uselib_store='PORTAUDIO',
+                          atleast_version='19')
     autowaf.check_pkg(conf, 'libxml-2.0', uselib_store='XML')
     autowaf.check_pkg(conf, 'lrdf', uselib_store='LRDF',
                       atleast_version='0.4.0')
@@ -379,8 +387,8 @@ def build(bld):
     obj.name         = 'ardour'
     obj.target       = 'ardour'
     obj.uselib       = ['GLIBMM','GTHREAD','AUBIO','SIGCPP','XML','UUID',
-                        'JACK','SNDFILE','SAMPLERATE','LRDF','AUDIOUNITS',
-                        'OSX','BOOST','CURL','DL']
+                        'JACK', 'ALSA', 'PORTAUDIO', 'SNDFILE','SAMPLERATE','LRDF',
+                        'AUDIOUNITS', 'OSX','BOOST','CURL','DL']
     obj.use          = ['libpbd','libmidipp','libevoral','libvamphost',
                         'libvampplugin','libtaglib','librubberband',
                         'libaudiographer','libltc']
@@ -479,6 +487,7 @@ def build(bld):
             create_ardour_test_program(bld, obj.includes, 'framewalk_to_beats', 'test_framewalk_to_beats', ['test/framewalk_to_beats_test.cc'])
             create_ardour_test_program(bld, obj.includes, 'framepos_plus_beats', 'test_framepos_plus_beats', ['test/framepos_plus_beats_test.cc'])
             create_ardour_test_program(bld, obj.includes, 'framepos_minus_beats', 'test_framepos_minus_beats', ['test/framepos_minus_beats_test.cc'])
+            create_ardour_test_program(bld, obj.includes, 'jack_utils', 'test_jack_utils', ['test/jack_utils_test.cc'])
             create_ardour_test_program(bld, obj.includes, 'playlist_equivalent_regions', 'test_playlist_equivalent_regions', ['test/playlist_equivalent_regions_test.cc'])
             create_ardour_test_program(bld, obj.includes, 'playlist_layering', 'test_playlist_layering', ['test/playlist_layering_test.cc'])
             create_ardour_test_program(bld, obj.includes, 'plugins_test', 'test_plugins', ['test/plugins_test.cc'])
@@ -497,6 +506,7 @@ def build(bld):
             test/framewalk_to_beats_test.cc
             test/framepos_plus_beats_test.cc
             test/framepos_minus_beats_test.cc
+            test/jack_utils_test.cc
             test/playlist_equivalent_regions_test.cc
             test/playlist_layering_test.cc
             test/plugins_test.cc