summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2013-07-15 12:46:35 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2013-07-15 12:46:35 -0400
commita8647faca7d60ba6404239f2ebcff1631028fbad (patch)
tree42566c99cc1bdd360d1bb4daf76e50ded18de85a
parent3e1c66f946fe90033277cbab2681a705fb987acb (diff)
Add JACK utility functions in libardour and test
This contains much of the code present in the GUI EngineDialog class but refactored with some added windows bits.
-rw-r--r--libs/ardour/ardour/jack_utils.h261
-rw-r--r--libs/ardour/jack_utils.cc947
-rw-r--r--libs/ardour/test/jack_utils_test.cc315
-rw-r--r--libs/ardour/test/jack_utils_test.h33
-rw-r--r--libs/ardour/wscript14
5 files changed, 1568 insertions, 2 deletions
diff --git a/libs/ardour/ardour/jack_utils.h b/libs/ardour/ardour/jack_utils.h
new file mode 100644
index 0000000000..353724f079
--- /dev/null
+++ b/libs/ardour/ardour/jack_utils.h
@@ -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
index 0000000000..29f7ca4f3e
--- /dev/null
+++ b/libs/ardour/jack_utils.cc
@@ -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
index 0000000000..ed80237f78
--- /dev/null
+++ b/libs/ardour/test/jack_utils_test.cc
@@ -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
index 0000000000..6a42d1d015
--- /dev/null
+++ b/libs/ardour/test/jack_utils_test.h
@@ -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 ();
+};
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index 256ff1c6c0..3afd4ce552 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -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