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