1 /*
2  * Copyright (C) 2013-2016 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2013-2016 Tim Mayberry <mojofunk@gmail.com>
4  * Copyright (C) 2013 Colin Fletcher <colin.m.fletcher@googlemail.com>
5  * Copyright (C) 2014-2015 Robin Gareus <robin@gareus.org>
6  * Copyright (C) 2014 John Emmas <john@creativepost.co.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #ifdef HAVE_ALSA
24 #include "ardouralsautil/devicelist.h"
25 #endif
26 
27 #ifdef __APPLE__
28 #include <CoreAudio/CoreAudio.h>
29 #include <CoreFoundation/CFString.h>
30 #include <sys/param.h>
31 #include <mach-o/dyld.h>
32 #undef nil
33 #endif
34 
35 #ifdef PLATFORM_WINDOWS
36 #include <shobjidl.h>  //  Needed for
37 #include <shlguid.h>   // 'IShellLink'
38 #include "pbd/windows_special_dirs.h"
39 #endif
40 
41 #if (defined PLATFORM_WINDOWS && defined HAVE_PORTAUDIO)
42 #include <portaudio.h>
43 #endif
44 
45 #include <boost/scoped_ptr.hpp>
46 
47 #include "pbd/gstdio_compat.h"
48 #include <glibmm/miscutils.h>
49 
50 #include "pbd/epa.h"
51 #include "pbd/error.h"
52 #include "pbd/string_convert.h"
53 #include "pbd/file_utils.h"
54 #include "pbd/search_path.h"
55 
56 #include "jack_utils.h"
57 
58 #ifdef __APPLE
59 #include <CFBundle.h>
60 #endif
61 
62 #include "pbd/i18n.h"
63 
64 using namespace std;
65 using namespace PBD;
66 
67 namespace ARDOUR {
68 	// The pretty driver names
69 	const char * const portaudio_driver_name = X_("Portaudio");
70 	const char * const coreaudio_driver_name = X_("CoreAudio");
71 	const char * const alsa_driver_name = X_("ALSA");
72 	const char * const oss_driver_name = X_("OSS");
73 	const char * const sun_driver_name = X_("Sun");
74 	const char * const freebob_driver_name = X_("FreeBoB");
75 	const char * const ffado_driver_name = X_("FFADO");
76 	const char * const netjack_driver_name = X_("NetJACK");
77 	const char * const dummy_driver_name = X_("Dummy");
78 }
79 
80 namespace {
81 
82 	// The real driver names
83 	const char * const portaudio_driver_command_line_name = X_("portaudio");
84 	const char * const coreaudio_driver_command_line_name = X_("coreaudio");
85 	const char * const alsa_driver_command_line_name = X_("alsa");
86 	const char * const oss_driver_command_line_name = X_("oss");
87 	const char * const sun_driver_command_line_name = X_("sun");
88 	const char * const freebob_driver_command_line_name = X_("freebob");
89 	const char * const ffado_driver_command_line_name = X_("firewire");
90 	const char * const netjack_driver_command_line_name = X_("netjack");
91 	const char * const dummy_driver_command_line_name = X_("dummy");
92 
93 	// should we provide more "pretty" names like above?
94 	const char * const alsa_seq_midi_driver_name = X_("alsa");
95 	const char * const alsa_raw_midi_driver_name = X_("alsarawmidi");
96 	const char * const alsaseq_midi_driver_name = X_("seq");
97 	const char * const alsaraw_midi_driver_name = X_("raw");
98 	const char * const winmme_midi_driver_name = X_("winmme");
99 	const char * const coremidi_midi_driver_name = X_("coremidi");
100 
101 	// this should probably be translated
102 	const char * const default_device_name = X_("Default");
103 }
104 
105 static ARDOUR::MidiOptions midi_options;
106 
107 std::string
get_none_string()108 get_none_string ()
109 {
110 	return _("None");
111 }
112 
113 void
get_jack_audio_driver_names(vector<string> & audio_driver_names)114 ARDOUR::get_jack_audio_driver_names (vector<string>& audio_driver_names)
115 {
116 #ifdef PLATFORM_WINDOWS
117 	audio_driver_names.push_back (portaudio_driver_name);
118 #elif __APPLE__
119 	audio_driver_names.push_back (coreaudio_driver_name);
120 #else
121 #ifdef HAVE_ALSA
122 	audio_driver_names.push_back (alsa_driver_name);
123 #endif
124 	audio_driver_names.push_back (oss_driver_name);
125 #if defined(__NetBSD__) || defined(__sun)
126 	audio_driver_names.push_back (sun_driver_name);
127 #endif
128 	audio_driver_names.push_back (freebob_driver_name);
129 	audio_driver_names.push_back (ffado_driver_name);
130 #endif
131 	audio_driver_names.push_back (netjack_driver_name);
132 	audio_driver_names.push_back (dummy_driver_name);
133 }
134 
135 void
get_jack_default_audio_driver_name(string & audio_driver_name)136 ARDOUR::get_jack_default_audio_driver_name (string& audio_driver_name)
137 {
138 	vector<string> drivers;
139 	get_jack_audio_driver_names (drivers);
140 	audio_driver_name = drivers.front ();
141 }
142 
143 void
get_jack_sample_rate_strings(vector<string> & samplerates)144 ARDOUR::get_jack_sample_rate_strings (vector<string>& samplerates)
145 {
146 	// do these really need to be translated?
147 	samplerates.push_back (_("8000Hz"));
148 	samplerates.push_back (_("22050Hz"));
149 	samplerates.push_back (_("44100Hz"));
150 	samplerates.push_back (_("48000Hz"));
151 	samplerates.push_back (_("88200Hz"));
152 	samplerates.push_back (_("96000Hz"));
153 	samplerates.push_back (_("192000Hz"));
154 }
155 
156 string
get_jack_default_sample_rate()157 ARDOUR::get_jack_default_sample_rate ()
158 {
159 	return _("48000Hz");
160 }
161 
162 void
get_jack_period_size_strings(std::vector<std::string> & period_sizes)163 ARDOUR::get_jack_period_size_strings (std::vector<std::string>& period_sizes)
164 {
165 	period_sizes.push_back ("32");
166 	period_sizes.push_back ("64");
167 	period_sizes.push_back ("128");
168 	period_sizes.push_back ("256");
169 	period_sizes.push_back ("512");
170 	period_sizes.push_back ("1024");
171 	period_sizes.push_back ("2048");
172 	period_sizes.push_back ("4096");
173 	period_sizes.push_back ("8192");
174 }
175 
176 string
get_jack_default_period_size()177 ARDOUR::get_jack_default_period_size ()
178 {
179 	return "1024";
180 }
181 
182 void
get_jack_dither_mode_strings(const string & driver,vector<string> & dither_modes)183 ARDOUR::get_jack_dither_mode_strings (const string& driver, vector<string>& dither_modes)
184 {
185 	dither_modes.push_back (get_none_string ());
186 
187 	if (driver == alsa_driver_name ) {
188 		dither_modes.push_back (_("Triangular"));
189 		dither_modes.push_back (_("Rectangular"));
190 		dither_modes.push_back (_("Shaped"));
191 	}
192 }
193 
194 string
get_jack_default_dither_mode(const string &)195 ARDOUR::get_jack_default_dither_mode (const string& /*driver*/)
196 {
197 	return get_none_string ();
198 }
199 
200 string
get_jack_latency_string(string samplerate,float periods,string period_size)201 ARDOUR::get_jack_latency_string (string samplerate, float periods, string period_size)
202 {
203 	uint32_t rate = atoi (samplerate);
204 	float psize = atof (period_size);
205 
206 	char buf[32];
207 	snprintf (buf, sizeof(buf), "%.1fmsec", (periods * psize) / (rate/1000.0));
208 
209 	return buf;
210 }
211 
212 bool
get_jack_command_line_audio_driver_name(const string & driver_name,string & command_line_name)213 get_jack_command_line_audio_driver_name (const string& driver_name, string& command_line_name)
214 {
215 	using namespace ARDOUR;
216 	if (driver_name == portaudio_driver_name) {
217 		command_line_name = portaudio_driver_command_line_name;
218 		return true;
219 	} else if (driver_name == coreaudio_driver_name) {
220 		command_line_name = coreaudio_driver_command_line_name;
221 		return true;
222 	} else if (driver_name == alsa_driver_name) {
223 		command_line_name = alsa_driver_command_line_name;
224 		return true;
225 	} else if (driver_name == oss_driver_name) {
226 		command_line_name = oss_driver_command_line_name;
227 		return true;
228 	} else if (driver_name == sun_driver_name) {
229 		command_line_name = sun_driver_command_line_name;
230 		return true;
231 	} else if (driver_name == freebob_driver_name) {
232 		command_line_name = freebob_driver_command_line_name;
233 		return true;
234 	} else if (driver_name == ffado_driver_name) {
235 		command_line_name = ffado_driver_command_line_name;
236 		return true;
237 	} else if (driver_name == netjack_driver_name) {
238 		command_line_name = netjack_driver_command_line_name;
239 		return true;
240 	} else if (driver_name == dummy_driver_name) {
241 		command_line_name = dummy_driver_command_line_name;
242 		return true;
243 	}
244 	return false;
245 }
246 
247 bool
get_jack_command_line_audio_device_name(const string & driver_name,const string & device_name,string & command_line_device_name)248 get_jack_command_line_audio_device_name (const string& driver_name,
249 		const string& device_name, string& command_line_device_name)
250 {
251 	using namespace ARDOUR;
252 	device_map_t devices;
253 
254 	get_jack_device_names_for_audio_driver (driver_name, devices);
255 
256 	for (device_map_t::const_iterator i = devices.begin (); i != devices.end(); ++i) {
257 		if (i->first == device_name) {
258 			command_line_device_name = i->second;
259 			return true;
260 		}
261 	}
262 	return false;
263 }
264 
265 bool
get_jack_command_line_dither_mode(const string & dither_mode,string & command_line_dither_mode)266 get_jack_command_line_dither_mode (const string& dither_mode, string& command_line_dither_mode)
267 {
268 	using namespace ARDOUR;
269 
270 	if (dither_mode == _("Triangular")) {
271 		command_line_dither_mode = "triangular";
272 		return true;
273 	} else if (dither_mode == _("Rectangular")) {
274 		command_line_dither_mode = "rectangular";
275 		return true;
276 	} else if (dither_mode == _("Shaped")) {
277 		command_line_dither_mode = "shaped";
278 		return true;
279 	}
280 
281 	return false;
282 }
283 
284 void
get_jack_alsa_device_names(device_map_t & devices)285 ARDOUR::get_jack_alsa_device_names (device_map_t& devices)
286 {
287 #ifdef HAVE_ALSA
288 	get_alsa_audio_device_names(devices, HalfDuplexOut);
289 #else
290 	/* silence a compiler unused variable warning */
291 	(void) devices;
292 #endif
293 }
294 
295 #ifdef __APPLE__
296 static OSStatus
getDeviceUIDFromID(AudioDeviceID id,char * name,size_t nsize)297 getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
298 {
299 	UInt32 size = sizeof(CFStringRef);
300 	CFStringRef UI;
301 	OSStatus res = AudioDeviceGetProperty(id, 0, false,
302 		kAudioDevicePropertyDeviceUID, &size, &UI);
303 	if (res == noErr)
304 		CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
305 	CFRelease(UI);
306 	return res;
307 }
308 #endif
309 
310 void
get_jack_coreaudio_device_names(device_map_t & devices)311 ARDOUR::get_jack_coreaudio_device_names (device_map_t& devices)
312 {
313 #ifdef __APPLE__
314 	// Find out how many Core Audio devices are there, if any...
315 	// (code snippet gently "borrowed" from St?hane Letz jackdmp;)
316 	OSStatus err;
317 	Boolean isWritable;
318 	UInt32 outSize = sizeof(isWritable);
319 
320 	err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
321 					   &outSize, &isWritable);
322 	if (err == noErr) {
323 		// Calculate the number of device available...
324 		int numCoreDevices = outSize / sizeof(AudioDeviceID);
325 		// Make space for the devices we are about to get...
326 		AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
327 		err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
328 					       &outSize, (void *) coreDeviceIDs);
329 		if (err == noErr) {
330 			// Look for the CoreAudio device name...
331 			char coreDeviceName[256];
332 			UInt32 nameSize;
333 
334 			for (int i = 0; i < numCoreDevices; i++) {
335 
336 				nameSize = sizeof (coreDeviceName);
337 
338 				/* enforce duplex devices only */
339 
340 				err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
341 								 0, true, kAudioDevicePropertyStreams,
342 								 &outSize, &isWritable);
343 
344 				if (err != noErr || outSize == 0) {
345 					continue;
346 				}
347 
348 				err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
349 								 0, false, kAudioDevicePropertyStreams,
350 								 &outSize, &isWritable);
351 
352 				if (err != noErr || outSize == 0) {
353 					continue;
354 				}
355 
356 				err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
357 								 0, true, kAudioDevicePropertyDeviceName,
358 								 &outSize, &isWritable);
359 				if (err == noErr) {
360 					err = AudioDeviceGetProperty(coreDeviceIDs[i],
361 								     0, true, kAudioDevicePropertyDeviceName,
362 								     &nameSize, (void *) coreDeviceName);
363 					if (err == noErr) {
364 						char drivername[128];
365 
366 						// this returns the unique id for the device
367 						// that must be used on the commandline for jack
368 
369 						if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
370 							devices.insert (make_pair (coreDeviceName, drivername));
371 						}
372 					}
373 				}
374 			}
375 		}
376 		delete [] coreDeviceIDs;
377 	}
378 #else
379 	/* silence a compiler unused variable warning */
380 	(void) devices;
381 #endif
382 }
383 
384 void
get_jack_portaudio_device_names(device_map_t & devices)385 ARDOUR::get_jack_portaudio_device_names (device_map_t& devices)
386 {
387 #if (defined PLATFORM_WINDOWS && defined HAVE_PORTAUDIO)
388 	if (Pa_Initialize() != paNoError) {
389 		return;
390 	}
391 
392 	for (PaDeviceIndex i = 0; i < Pa_GetDeviceCount (); ++i) {
393 		string api_name;
394 		string readable_name;
395 		string jack_device_name;
396 		const PaDeviceInfo* device_info = Pa_GetDeviceInfo(i);
397 
398 		if (device_info != NULL) { // it should never be ?
399 			api_name = Pa_GetHostApiInfo (device_info->hostApi)->name;
400 			readable_name = api_name + " " + device_info->name;
401 			jack_device_name = api_name + "::" + device_info->name;
402 			devices.insert (make_pair (readable_name, jack_device_name));
403 		}
404 	}
405 	Pa_Terminate();
406 #else
407 	/* silence a compiler unused variable warning */
408 	(void) devices;
409 #endif
410 }
411 
412 void
get_jack_oss_device_names(device_map_t & devices)413 ARDOUR::get_jack_oss_device_names (device_map_t& devices)
414 {
415 	devices.insert (make_pair (default_device_name, default_device_name));
416 }
417 
418 void
get_jack_sun_device_names(device_map_t & devices)419 ARDOUR::get_jack_sun_device_names (device_map_t& devices)
420 {
421 	devices.insert (make_pair (default_device_name, default_device_name));
422 }
423 
424 
425 void
get_jack_freebob_device_names(device_map_t & devices)426 ARDOUR::get_jack_freebob_device_names (device_map_t& devices)
427 {
428 	devices.insert (make_pair (default_device_name, default_device_name));
429 }
430 
431 void
get_jack_ffado_device_names(device_map_t & devices)432 ARDOUR::get_jack_ffado_device_names (device_map_t& devices)
433 {
434 	devices.insert (make_pair (default_device_name, default_device_name));
435 }
436 
437 void
get_jack_netjack_device_names(device_map_t & devices)438 ARDOUR::get_jack_netjack_device_names (device_map_t& devices)
439 {
440 	devices.insert (make_pair (default_device_name, default_device_name));
441 }
442 
443 void
get_jack_dummy_device_names(device_map_t & devices)444 ARDOUR::get_jack_dummy_device_names (device_map_t& devices)
445 {
446 	devices.insert (make_pair (default_device_name, default_device_name));
447 }
448 
449 bool
get_jack_device_names_for_audio_driver(const string & driver_name,device_map_t & devices)450 ARDOUR::get_jack_device_names_for_audio_driver (const string& driver_name, device_map_t& devices)
451 {
452 	devices.clear();
453 
454 	if (driver_name == portaudio_driver_name) {
455 		get_jack_portaudio_device_names (devices);
456 	} else if (driver_name == coreaudio_driver_name) {
457 		get_jack_coreaudio_device_names (devices);
458 	} else if (driver_name == alsa_driver_name) {
459 		get_jack_alsa_device_names (devices);
460 	} else if (driver_name == oss_driver_name) {
461 		get_jack_oss_device_names (devices);
462 	} else if (driver_name == sun_driver_name) {
463 		get_jack_sun_device_names (devices);
464 	} else if (driver_name == freebob_driver_name) {
465 		get_jack_freebob_device_names (devices);
466 	} else if (driver_name == ffado_driver_name) {
467 		get_jack_ffado_device_names (devices);
468 	} else if (driver_name == netjack_driver_name) {
469 		get_jack_netjack_device_names (devices);
470 	} else if (driver_name == dummy_driver_name) {
471 		get_jack_dummy_device_names (devices);
472 	}
473 
474 	return !devices.empty();
475 }
476 
477 
478 std::vector<std::string>
get_jack_device_names_for_audio_driver(const string & driver_name)479 ARDOUR::get_jack_device_names_for_audio_driver (const string& driver_name)
480 {
481 	std::vector<std::string> readable_names;
482 	device_map_t devices;
483 
484 	get_jack_device_names_for_audio_driver (driver_name, devices);
485 
486 	for (device_map_t::const_iterator i = devices.begin (); i != devices.end(); ++i) {
487 		readable_names.push_back (i->first);
488 	}
489 
490 	return readable_names;
491 }
492 
493 bool
get_jack_audio_driver_supports_two_devices(const string & driver)494 ARDOUR::get_jack_audio_driver_supports_two_devices (const string& driver)
495 {
496 	return (driver == alsa_driver_name || driver == oss_driver_name ||
497 			driver == sun_driver_name);
498 }
499 
500 bool
get_jack_audio_driver_supports_latency_adjustment(const string & driver)501 ARDOUR::get_jack_audio_driver_supports_latency_adjustment (const string& driver)
502 {
503 	return (driver == alsa_driver_name || driver == coreaudio_driver_name ||
504 			driver == ffado_driver_name || driver == portaudio_driver_name);
505 }
506 
507 bool
get_jack_audio_driver_supports_setting_period_count(const string & driver)508 ARDOUR::get_jack_audio_driver_supports_setting_period_count (const string& driver)
509 {
510 	return !(driver == dummy_driver_name || driver == coreaudio_driver_name ||
511 			driver == portaudio_driver_name);
512 }
513 
514 bool
get_jack_server_application_names(std::vector<std::string> & server_names)515 ARDOUR::get_jack_server_application_names (std::vector<std::string>& server_names)
516 {
517 #ifdef PLATFORM_WINDOWS
518 	server_names.push_back ("jackd.exe");
519 #else
520 	server_names.push_back ("jackd");
521 	server_names.push_back ("jackdmp");
522 #endif
523 	return !server_names.empty();
524 }
525 
526 void
set_path_env_for_jack_autostart(const vector<std::string> & dirs)527 ARDOUR::set_path_env_for_jack_autostart (const vector<std::string>& dirs)
528 {
529 #ifdef __APPLE__
530 	// push it back into the environment so that auto-started JACK can find it.
531 	// XXX why can't we just expect OS X users to have PATH set correctly? we can't ...
532 	setenv ("PATH", Searchpath(dirs).to_string().c_str(), 1);
533 #else
534 	/* silence a compiler unused variable warning */
535 	(void) dirs;
536 #endif
537 }
538 
539 bool
get_jack_server_dir_paths(vector<std::string> & server_dir_paths)540 ARDOUR::get_jack_server_dir_paths (vector<std::string>& server_dir_paths)
541 {
542 #ifdef __APPLE__
543 	/* this magic lets us finds the path to the OSX bundle, and then
544 	   we infer JACK's location from there
545 	*/
546 
547 	char execpath[MAXPATHLEN+1];
548 	uint32_t pathsz = sizeof (execpath);
549 
550 	_NSGetExecutablePath (execpath, &pathsz);
551 
552 	server_dir_paths.push_back (Glib::path_get_dirname (execpath));
553 #endif
554 
555 	Searchpath sp(string(g_getenv("PATH")));
556 
557 #ifdef PLATFORM_WINDOWS
558 	std::string reg;
559 
560 	/* since https://github.com/jackaudio/jack2/commit/ac62faa9c0268b89e3ea23c0318227612acd8079 */
561 	bool found = PBD::windows_query_registry ("Software\\JACK", "InstallPath", reg);
562 
563 	if (!found) {
564 		/* special-case jack 1.9.16, "Location" included jackd.exe */
565 		found = PBD::windows_query_registry ("Software\\JACK", "Location", reg);
566 		if (found) {
567 			reg = Glib::path_get_dirname (reg);
568 		}
569 	}
570 	if (!found) {
571 		// If the newer style regkey wasn't found, check for one in the older style...
572 		found = PBD::windows_query_registry ("Software\\Jack", "InstPath", reg, HKEY_CURRENT_USER);
573 	}
574 
575 	if (found) {
576 		sp.push_back (reg);
577 	}
578 
579 	gchar *install_dir = g_win32_get_package_installation_directory_of_module (NULL);
580 	if (install_dir) {
581 		sp.push_back (install_dir);
582 		g_free (install_dir);
583 	}
584 #else
585 	if (sp.empty()) {
586 		sp.push_back ("/usr/bin");
587 		sp.push_back ("/bin");
588 		sp.push_back ("/usr/local/bin");
589 		sp.push_back ("/opt/local/bin");
590 	}
591 #endif
592 
593 	std::copy (sp.begin(), sp.end(), std::back_inserter(server_dir_paths));
594 
595 	return !server_dir_paths.empty();
596 }
597 
598 bool
get_jack_server_paths(const vector<std::string> & server_dir_paths,const vector<string> & server_names,vector<std::string> & server_paths)599 ARDOUR::get_jack_server_paths (const vector<std::string>& server_dir_paths,
600 		const vector<string>& server_names,
601 		vector<std::string>& server_paths)
602 {
603 	for (vector<string>::const_iterator i = server_names.begin(); i != server_names.end(); ++i) {
604 		find_files_matching_pattern (server_paths, server_dir_paths, *i);
605 	}
606 	return !server_paths.empty();
607 }
608 
609 bool
get_jack_server_paths(vector<std::string> & server_paths)610 ARDOUR::get_jack_server_paths (vector<std::string>& server_paths)
611 {
612 	vector<std::string> server_dirs;
613 
614 	if (!get_jack_server_dir_paths (server_dirs)) {
615 		return false;
616 	}
617 
618 	vector<string> server_names;
619 
620 	if (!get_jack_server_application_names (server_names)) {
621 		return false;
622 	}
623 
624 	if (!get_jack_server_paths (server_dirs, server_names, server_paths)) {
625 		return false;
626 	}
627 
628 	return !server_paths.empty();
629 }
630 
631 bool
get_jack_default_server_path(std::string & server_path)632 ARDOUR::get_jack_default_server_path (std::string& server_path)
633 {
634 	vector<std::string> server_paths;
635 
636 	if (!get_jack_server_paths (server_paths)) {
637 		return false;
638 	}
639 
640 	server_path = server_paths.front ();
641 	return true;
642 }
643 
644 static string
quote_string(string str)645 quote_string (string str)
646 {
647 	/* escape quotes in string */
648 	size_t pos = 0;
649 	while ((pos = str.find("\"", pos)) != std::string::npos) {
650 		str.replace (pos, 1, "\\\"");
651 		pos += 2;
652 	}
653 	/* and quote the whole string */
654 	return "\"" + str + "\"";
655 }
656 
JackCommandLineOptions()657 ARDOUR::JackCommandLineOptions::JackCommandLineOptions ()
658 	: server_path ()
659 	, timeout(0)
660 	, no_mlock(false)
661 	, ports_max(128)
662 	, realtime(true)
663 	, priority(0)
664 	, unlock_gui_libs(false)
665 	, verbose(false)
666 	, temporary(true)
667 	, driver()
668 	, input_device()
669 	, output_device()
670 	, num_periods(2)
671 	, period_size(1024)
672 	, samplerate(48000)
673 	, input_latency(0)
674 	, output_latency(0)
675 	, hardware_metering(false)
676 	, hardware_monitoring(false)
677 	, dither_mode()
678 	, force16_bit(false)
679 	, soft_mode(false)
680 	, midi_driver()
681 {
682 
683 }
684 
685 bool
get_jack_command_line_string(JackCommandLineOptions & options,string & command_line)686 ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& command_line)
687 {
688 	vector<string> args;
689 
690 	args.push_back (options.server_path);
691 
692 #ifdef PLATFORM_WINDOWS
693 	// must use sync mode on windows
694 	args.push_back ("-S");
695 #endif
696 
697 #if (defined PLATFORM_WINDOWS || defined __APPLE__)
698 	// midi systems needs to be added before the audio driver for jack2
699 	if (!options.midi_driver.empty () && options.midi_driver != get_none_string ()) {
700 		args.push_back ("-X");
701 		args.push_back (options.midi_driver);
702 	}
703 #endif
704 
705 	/* XXX hack to enforce qjackctl-like behaviour */
706 	if (options.timeout == 0) {
707 		options.timeout = 200;
708 	}
709 
710 	if (options.timeout) {
711 		args.push_back ("-t");
712 		args.push_back (to_string (options.timeout));
713 	}
714 
715 	if (options.no_mlock) {
716 		args.push_back ("-m");
717 	}
718 
719 	args.push_back ("-p");
720 	args.push_back (to_string(options.ports_max));
721 
722 	if (options.realtime) {
723 		args.push_back ("-R");
724 		if (options.priority != 0) {
725 			args.push_back ("-P");
726 			args.push_back (to_string(options.priority));
727 		}
728 	} else {
729 		args.push_back ("-r");
730 	}
731 
732 	if (options.unlock_gui_libs) {
733 		args.push_back ("-u");
734 	}
735 
736 	if (options.verbose) {
737 		args.push_back ("-v");
738 	}
739 
740 	if (options.temporary) {
741 		args.push_back ("-T");
742 	}
743 
744 	if (options.driver == alsa_driver_name) {
745 		if (options.midi_driver == alsa_seq_midi_driver_name) {
746 			args.push_back ("-X");
747 			args.push_back ("alsa_midi");
748 		} else if (options.midi_driver == alsa_raw_midi_driver_name) {
749 			args.push_back ("-X");
750 			args.push_back ("alsarawmidi");
751 		}
752 	}
753 
754 	string command_line_driver_name;
755 
756 	string command_line_input_device_name;
757 	string command_line_output_device_name;
758 
759 	if (!get_jack_command_line_audio_driver_name (options.driver, command_line_driver_name)) {
760 		return false;
761 	}
762 
763 	args.push_back ("-d");
764 	args.push_back (command_line_driver_name);
765 
766 	if (options.driver != dummy_driver_name) {
767 		if (options.output_device.empty() && options.input_device.empty()) {
768 			return false;
769 		}
770 
771 
772 		if (!get_jack_command_line_audio_device_name (options.driver,
773 					options.input_device, command_line_input_device_name)) {
774 			return false;
775 		}
776 
777 		if (!get_jack_command_line_audio_device_name (options.driver,
778 					options.output_device, command_line_output_device_name)) {
779 			return false;
780 		}
781 
782 		if (options.input_device.empty()) {
783 			// playback only
784 			if (options.output_device.empty()) {
785 				return false;
786 			}
787 			args.push_back ("-P");
788 		} else if (options.output_device.empty()) {
789 			// capture only
790 			if (options.input_device.empty()) {
791 				return false;
792 			}
793 			args.push_back ("-C");
794 		} else if (options.input_device != options.output_device) {
795 			// capture and playback on two devices if supported
796 			if (get_jack_audio_driver_supports_two_devices (options.driver)) {
797 				args.push_back ("-C");
798 				args.push_back (command_line_input_device_name);
799 				args.push_back ("-P");
800 				args.push_back (command_line_output_device_name);
801 			} else {
802 				return false;
803 			}
804 		}
805 
806 		if (options.input_channels) {
807 			args.push_back ("-i");
808 			args.push_back (to_string (options.input_channels));
809 		}
810 
811 		if (options.output_channels) {
812 			args.push_back ("-o");
813 			args.push_back (to_string (options.output_channels));
814 		}
815 
816 		if (get_jack_audio_driver_supports_setting_period_count (options.driver)) {
817 			args.push_back ("-n");
818 			args.push_back (to_string (options.num_periods));
819 		}
820 	} else {
821 		// jackd dummy backend
822 		if (options.input_channels) {
823 			args.push_back ("-C");
824 			args.push_back (to_string (options.input_channels));
825 		}
826 
827 		if (options.output_channels) {
828 			args.push_back ("-P");
829 			args.push_back (to_string (options.output_channels));
830 		}
831 	}
832 
833 	args.push_back ("-r");
834 	args.push_back (to_string (options.samplerate));
835 
836 	args.push_back ("-p");
837 	args.push_back (to_string (options.period_size));
838 
839 	if (get_jack_audio_driver_supports_latency_adjustment (options.driver)) {
840 		if (options.input_latency) {
841 			args.push_back ("-I");
842 			args.push_back (to_string (options.input_latency));
843 		}
844 		if (options.output_latency) {
845 			args.push_back ("-O");
846 			args.push_back (to_string (options.output_latency));
847 		}
848 	}
849 
850 	if (options.driver != dummy_driver_name) {
851 		if (options.input_device == options.output_device && options.input_device != default_device_name) {
852 			args.push_back ("-d");
853 			args.push_back (command_line_input_device_name);
854 		}
855 	}
856 
857 	if (options.driver == alsa_driver_name) {
858 		if (options.hardware_metering) {
859 			args.push_back ("-M");
860 		}
861 		if (options.hardware_monitoring) {
862 			args.push_back ("-H");
863 		}
864 
865 		string command_line_dither_mode;
866 		if (get_jack_command_line_dither_mode (options.dither_mode, command_line_dither_mode)) {
867 			args.push_back ("-z");
868 			args.push_back (command_line_dither_mode);
869 		}
870 		if (options.force16_bit) {
871 			args.push_back ("-S");
872 		}
873 		if (options.soft_mode) {
874 			args.push_back ("-s");
875 		}
876 	}
877 
878 	if (options.driver == alsa_driver_name) {
879 
880 		if (options.midi_driver != alsa_seq_midi_driver_name) {
881 			if (!options.midi_driver.empty() && options.midi_driver != get_none_string ()) {
882 				args.push_back ("-X");
883 				args.push_back (options.midi_driver);
884 			}
885 		}
886 	}
887 
888 	ostringstream oss;
889 
890 	for (vector<string>::const_iterator i = args.begin(); i != args.end();) {
891 		if ((i != args.begin()) && (i->find_first_of(' ') != string::npos)) {
892 			// Be aware that (in Windows at least) Jack can't start if we supply a server path
893 			// surrounded in quote marks (maybe Jack already does something similar imternally??)
894 			// Fortunately, if it exists in our '.jackdrc' file, the server path will always be
895 			// its very first entry - so we skip quoting that entry if it did contain spaces.
896 			oss << quote_string (*i);
897 		} else {
898 			oss << *i;
899 		}
900 		if (++i != args.end()) oss << ' ';
901 	}
902 
903 	command_line = oss.str();
904 	return true;
905 }
906 
907 string
get_jack_server_config_file_name()908 ARDOUR::get_jack_server_config_file_name ()
909 {
910 	return ".jackdrc";
911 }
912 
913 std::string
get_jack_server_user_config_dir_path()914 ARDOUR::get_jack_server_user_config_dir_path ()
915 {
916 	return Glib::get_home_dir ();
917 }
918 
919 std::string
get_jack_server_user_config_file_path()920 ARDOUR::get_jack_server_user_config_file_path ()
921 {
922 	return Glib::build_filename (get_jack_server_user_config_dir_path (), get_jack_server_config_file_name ());
923 }
924 
925 bool
write_jack_config_file(const std::string & config_file_path,const string & command_line)926 ARDOUR::write_jack_config_file (const std::string& config_file_path, const string& command_line)
927 {
928 	if (!g_file_set_contents (config_file_path.c_str(), command_line.c_str(), -1, NULL)) {
929 		error << string_compose (_("cannot open JACK rc file %1 to store parameters"), config_file_path) << endmsg;
930 		return false;
931 	}
932 	return true;
933 }
934 
935 vector<string>
enumerate_midi_options()936 ARDOUR::enumerate_midi_options ()
937 {
938 	if (midi_options.empty()) {
939 #ifdef HAVE_ALSA
940 		midi_options.push_back (make_pair (_("(legacy) ALSA raw devices"), alsaraw_midi_driver_name));
941 		midi_options.push_back (make_pair (_("(legacy) ALSA sequencer"), alsaseq_midi_driver_name));
942 		midi_options.push_back (make_pair (_("ALSA (JACK1, 0.124 and later)"), alsa_seq_midi_driver_name));
943 		midi_options.push_back (make_pair (_("ALSA (JACK2, 1.9.8 and later)"), alsa_raw_midi_driver_name));
944 #endif
945 #if (defined PLATFORM_WINDOWS && defined HAVE_PORTAUDIO)
946 		/* Windows folks: what name makes sense here? Are there other
947 		   choices as well ?
948 		*/
949 		midi_options.push_back (make_pair (_("System MIDI (MME)"), winmme_midi_driver_name));
950 #endif
951 #ifdef __APPLE__
952 		midi_options.push_back (make_pair (_("CoreMIDI"), coremidi_midi_driver_name));
953 #endif
954 	}
955 
956 	vector<string> v;
957 
958 	for (MidiOptions::const_iterator i = midi_options.begin(); i != midi_options.end(); ++i) {
959 		v.push_back (i->first);
960 	}
961 
962 	v.push_back (get_none_string());
963 
964 	return v;
965 }
966 
967 int
set_midi_option(ARDOUR::JackCommandLineOptions & options,const string & opt)968 ARDOUR::set_midi_option (ARDOUR::JackCommandLineOptions& options, const string& opt)
969 {
970 	if (opt.empty() || opt == get_none_string()) {
971 		options.midi_driver = "";
972 		return 0;
973 	}
974 
975 	for (MidiOptions::const_iterator i = midi_options.begin(); i != midi_options.end(); ++i) {
976 		if (i->first == opt) {
977 			options.midi_driver = i->second;
978 			return 0;
979 		}
980 	}
981 
982 	return -1;
983 }
984 
985