inch-like progress on defining the API for AudioBackend and separating AudioEngine...
[ardour.git] / libs / ardour / audioengine.cc
1 /*
2     Copyright (C) 2002 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <unistd.h>
21 #include <cerrno>
22 #include <vector>
23 #include <exception>
24 #include <stdexcept>
25 #include <sstream>
26
27 #include <glibmm/timer.h>
28
29 #include "pbd/pthread_utils.h"
30 #include "pbd/stacktrace.h"
31 #include "pbd/unknown_type.h"
32 #include "pbd/epa.h"
33
34 #include <jack/weakjack.h>
35
36 #include "midi++/port.h"
37 #include "midi++/jack_midi_port.h"
38 #include "midi++/mmc.h"
39 #include "midi++/manager.h"
40
41 #include "ardour/audio_port.h"
42 #include "ardour/audioengine.h"
43 #include "ardour/buffer.h"
44 #include "ardour/cycle_timer.h"
45 #include "ardour/internal_send.h"
46 #include "ardour/meter.h"
47 #include "ardour/midi_port.h"
48 #include "ardour/port.h"
49 #include "ardour/process_thread.h"
50 #include "ardour/session.h"
51
52 #include "i18n.h"
53
54 using namespace std;
55 using namespace ARDOUR;
56 using namespace PBD;
57
58 gint AudioEngine::m_meter_exit;
59 AudioEngine* AudioEngine::_instance = 0;
60
61 AudioEngine::AudioEngine ()
62         : session_remove_pending (false)
63         , session_removal_countdown (-1)
64         , monitor_check_interval (INT32_MAX)
65         , last_monitor_check (0)
66         , _processed_frames (0)
67         , _freewheeling (false)
68         , _pre_freewheel_mmc_enabled (false)
69         , _usecs_per_cycle (0)
70         , port_remove_in_progress (false)
71         , m_meter_thread (0)
72         , _main_thread (0)
73         , ports (new Ports)
74 {
75         g_atomic_int_set (&m_meter_exit, 0);
76
77         Port::set_engine (this);
78 }
79
80 AudioEngine::~AudioEngine ()
81 {
82         config_connection.disconnect ();
83
84         {
85                 Glib::Threads::Mutex::Lock tm (_process_lock);
86                 session_removed.signal ();
87                 stop_metering_thread ();
88         }
89 }
90
91 AudioEngine*
92 AudioEngine::create ()
93 {
94         if (_instance) {
95                 return _instance;
96         }
97         return new AudioEngine;
98 }
99
100 jack_client_t*
101 AudioEngine::jack() const
102 {
103         return _jack;
104 }
105
106 void
107 _thread_init_callback (void * /*arg*/)
108 {
109         /* make sure that anybody who needs to know about this thread
110            knows about it.
111         */
112
113         pthread_set_name (X_("audioengine"));
114
115         PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("Audioengine"), 4096);
116         PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("Audioengine"), 128);
117
118         SessionEvent::create_per_thread_pool (X_("Audioengine"), 512);
119
120         MIDI::JackMIDIPort::set_process_thread (pthread_self());
121 }
122
123
124 int
125 AudioEngine::start ()
126 {
127         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
128
129         if (!_running) {
130
131                 if (!jack_port_type_get_buffer_size) {
132                         warning << _("This version of JACK is old - you should upgrade to a newer version that supports jack_port_type_get_buffer_size()") << endmsg;
133                 }
134
135                 if (_session) {
136                         BootMessage (_("Connect session to engine"));
137                         _session->set_frame_rate (jack_get_sample_rate (_priv_jack));
138                 }
139
140                 /* a proxy for whether jack_activate() will definitely call the buffer size
141                  * callback. with older versions of JACK, this function symbol will be null.
142                  * this is reliable, but not clean.
143                  */
144
145                 if (!jack_port_type_get_buffer_size) {
146                         jack_bufsize_callback (jack_get_buffer_size (_priv_jack));
147                 }
148                 
149                 _processed_frames = 0;
150                 last_monitor_check = 0;
151
152                 set_jack_callbacks ();
153
154                 if (jack_activate (_priv_jack) == 0) {
155                         _running = true;
156                         _has_run = true;
157                         Running(); /* EMIT SIGNAL */
158                 } else {
159                         // error << _("cannot activate JACK client") << endmsg;
160                 }
161         }
162                 
163         return _running ? 0 : -1;
164 }
165
166 int
167 AudioEngine::stop (bool forever)
168 {
169         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
170
171         if (_priv_jack) {
172                 if (forever) {
173                         disconnect_from_jack ();
174                 } else {
175                         jack_deactivate (_priv_jack);
176                         MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
177                         Stopped(); /* EMIT SIGNAL */
178                 }
179         }
180
181         if (forever) {
182                 stop_metering_thread ();
183         }
184
185         return _running ? -1 : 0;
186 }
187
188
189 void
190 AudioEngine::split_cycle (pframes_t offset)
191 {
192         /* caller must hold process lock */
193
194         Port::increment_global_port_buffer_offset (offset);
195
196         /* tell all Ports that we're going to start a new (split) cycle */
197
198         boost::shared_ptr<Ports> p = ports.reader();
199
200         for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
201                 i->second->cycle_split ();
202         }
203 }
204
205
206 /** Method called by our ::process_thread when there is work to be done.
207  *  @param nframes Number of frames to process.
208  */
209 int
210 AudioEngine::process_callback (pframes_t nframes)
211 {
212         GET_PRIVATE_JACK_POINTER_RET(_jack,0);
213         Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
214
215         PT_TIMING_REF;
216         PT_TIMING_CHECK (1);
217
218         /// The number of frames that will have been processed when we've finished
219         pframes_t next_processed_frames;
220
221         /* handle wrap around of total frames counter */
222
223         if (max_framepos - _processed_frames < nframes) {
224                 next_processed_frames = nframes - (max_framepos - _processed_frames);
225         } else {
226                 next_processed_frames = _processed_frames + nframes;
227         }
228
229         if (!tm.locked()) {
230                 /* return having done nothing */
231                 _processed_frames = next_processed_frames;
232                 return 0;
233         }
234
235         if (session_remove_pending) {
236
237                 /* perform the actual session removal */
238
239                 if (session_removal_countdown < 0) {
240
241                         /* fade out over 1 second */
242                         session_removal_countdown = _frame_rate/2;
243                         session_removal_gain = 1.0;
244                         session_removal_gain_step = 1.0/session_removal_countdown;
245
246                 } else if (session_removal_countdown > 0) {
247
248                         /* we'll be fading audio out.
249                            
250                            if this is the last time we do this as part 
251                            of session removal, do a MIDI panic now
252                            to get MIDI stopped. This relies on the fact
253                            that "immediate data" (aka "out of band data") from
254                            MIDI tracks is *appended* after any other data, 
255                            so that it emerges after any outbound note ons, etc.
256                         */
257
258                         if (session_removal_countdown <= nframes) {
259                                 _session->midi_panic ();
260                         }
261
262                 } else {
263                         /* fade out done */
264                         _session = 0;
265                         session_removal_countdown = -1; // reset to "not in progress"
266                         session_remove_pending = false;
267                         session_removed.signal(); // wakes up thread that initiated session removal
268                 }
269         }
270
271         if (_session == 0) {
272
273                 if (!_freewheeling) {
274                         MIDI::Manager::instance()->cycle_start(nframes);
275                         MIDI::Manager::instance()->cycle_end();
276                 }
277
278                 _processed_frames = next_processed_frames;
279
280                 return 0;
281         }
282
283         /* tell all relevant objects that we're starting a new cycle */
284
285         InternalSend::CycleStart (nframes);
286         Port::set_global_port_buffer_offset (0);
287         Port::set_cycle_framecnt (nframes);
288
289         /* tell all Ports that we're starting a new cycle */
290
291         boost::shared_ptr<Ports> p = ports.reader();
292
293         for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
294                 i->second->cycle_start (nframes);
295         }
296
297         /* test if we are freewheeling and there are freewheel signals connected.
298            ardour should act normally even when freewheeling unless /it/ is
299            exporting 
300         */
301
302         if (_freewheeling && !Freewheel.empty()) {
303
304                 Freewheel (nframes);
305
306         } else {
307                 MIDI::Manager::instance()->cycle_start(nframes);
308
309                 if (_session) {
310                         _session->process (nframes);
311                 }
312
313                 MIDI::Manager::instance()->cycle_end();
314         }
315
316         if (_freewheeling) {
317                 return 0;
318         }
319
320         if (!_running) {
321                 _processed_frames = next_processed_frames;
322                 return 0;
323         }
324
325         if (last_monitor_check + monitor_check_interval < next_processed_frames) {
326
327                 boost::shared_ptr<Ports> p = ports.reader();
328
329                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
330
331                         bool x;
332
333                         if (i->second->last_monitor() != (x = i->second->jack_monitoring_input ())) {
334                                 i->second->set_last_monitor (x);
335                                 /* XXX I think this is dangerous, due to
336                                    a likely mutex in the signal handlers ...
337                                 */
338                                 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
339                         }
340                 }
341                 last_monitor_check = next_processed_frames;
342         }
343
344         if (_session->silent()) {
345
346                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
347
348                         if (i->second->sends_output()) {
349                                 i->second->get_buffer(nframes).silence(nframes);
350                         }
351                 }
352         }
353
354         if (session_remove_pending && session_removal_countdown) {
355
356                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
357
358                         if (i->second->sends_output()) {
359
360                                 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
361                                 if (ap) {
362                                         Sample* s = ap->engine_get_whole_audio_buffer ();
363                                         gain_t g = session_removal_gain;
364                                         
365                                         for (pframes_t n = 0; n < nframes; ++n) {
366                                                 *s++ *= g;
367                                                 g -= session_removal_gain_step;
368                                         }
369                                 }
370                         }
371                 }
372                 
373                 if (session_removal_countdown > nframes) {
374                         session_removal_countdown -= nframes;
375                 } else {
376                         session_removal_countdown = 0;
377                 }
378
379                 session_removal_gain -= (nframes * session_removal_gain_step);
380         }
381
382         // Finalize ports
383
384         for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
385                 i->second->cycle_end (nframes);
386         }
387
388         _processed_frames = next_processed_frames;
389
390         PT_TIMING_CHECK (2);
391         
392         return 0;
393 }
394
395
396 void
397 AudioEngine::stop_metering_thread ()
398 {
399         if (m_meter_thread) {
400                 g_atomic_int_set (&m_meter_exit, 1);
401                 m_meter_thread->join ();
402                 m_meter_thread = 0;
403         }
404 }
405
406 void
407 AudioEngine::start_metering_thread ()
408 {
409         if (m_meter_thread == 0) {
410                 g_atomic_int_set (&m_meter_exit, 0);
411                 m_meter_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::meter_thread, this));
412         }
413 }
414
415 void
416 AudioEngine::meter_thread ()
417 {
418         pthread_set_name (X_("meter"));
419
420         while (true) {
421                 Glib::usleep (10000); /* 1/100th sec interval */
422                 if (g_atomic_int_get(&m_meter_exit)) {
423                         break;
424                 }
425                 Metering::Meter ();
426         }
427 }
428
429 void
430 AudioEngine::set_session (Session *s)
431 {
432         Glib::Threads::Mutex::Lock pl (_process_lock);
433
434         SessionHandlePtr::set_session (s);
435
436         if (_session) {
437
438                 start_metering_thread ();
439
440                 pframes_t blocksize = jack_get_buffer_size (_jack);
441
442                 /* page in as much of the session process code as we
443                    can before we really start running.
444                 */
445
446                 boost::shared_ptr<Ports> p = ports.reader();
447
448                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
449                         i->second->cycle_start (blocksize);
450                 }
451
452                 _session->process (blocksize);
453                 _session->process (blocksize);
454                 _session->process (blocksize);
455                 _session->process (blocksize);
456                 _session->process (blocksize);
457                 _session->process (blocksize);
458                 _session->process (blocksize);
459                 _session->process (blocksize);
460
461                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
462                         i->second->cycle_end (blocksize);
463                 }
464         }
465 }
466
467 void
468 AudioEngine::remove_session ()
469 {
470         Glib::Threads::Mutex::Lock lm (_process_lock);
471
472         if (_running) {
473
474                 stop_metering_thread ();
475
476                 if (_session) {
477                         session_remove_pending = true;
478                         session_removed.wait(_process_lock);
479                 }
480
481         } else {
482                 SessionHandlePtr::set_session (0);
483         }
484
485         remove_all_ports ();
486 }
487
488 void
489 AudioEngine::port_registration_failure (const std::string& portname)
490 {
491         GET_PRIVATE_JACK_POINTER (_jack);
492         string full_portname = jack_client_name;
493         full_portname += ':';
494         full_portname += portname;
495
496
497         jack_port_t* p = jack_port_by_name (_priv_jack, full_portname.c_str());
498         string reason;
499
500         if (p) {
501                 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
502         } else {
503                 reason = string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with more ports if you need this many tracks."), PROGRAM_NAME);
504         }
505
506         throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
507 }
508
509 boost::shared_ptr<Port>
510 AudioEngine::register_port (DataType dtype, const string& portname, bool input)
511 {
512         boost::shared_ptr<Port> newport;
513
514         try {
515                 if (dtype == DataType::AUDIO) {
516                         newport.reset (new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput)));
517                 } else if (dtype == DataType::MIDI) {
518                         newport.reset (new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput)));
519                 } else {
520                         throw PortRegistrationFailure("unable to create port (unknown type)");
521                 }
522
523                 RCUWriter<Ports> writer (ports);
524                 boost::shared_ptr<Ports> ps = writer.get_copy ();
525                 ps->insert (make_pair (make_port_name_relative (portname), newport));
526
527                 /* writer goes out of scope, forces update */
528
529                 return newport;
530         }
531
532         catch (PortRegistrationFailure& err) {
533                 throw err;
534         } catch (std::exception& e) {
535                 throw PortRegistrationFailure(string_compose(
536                                 _("unable to create port: %1"), e.what()).c_str());
537         } catch (...) {
538                 throw PortRegistrationFailure("unable to create port (unknown error)");
539         }
540 }
541
542 boost::shared_ptr<Port>
543 AudioEngine::register_input_port (DataType type, const string& portname)
544 {
545         return register_port (type, portname, true);
546 }
547
548 boost::shared_ptr<Port>
549 AudioEngine::register_output_port (DataType type, const string& portname)
550 {
551         return register_port (type, portname, false);
552 }
553
554 int
555 AudioEngine::unregister_port (boost::shared_ptr<Port> port)
556 {
557         /* caller must hold process lock */
558
559         if (!_running) {
560                 /* probably happening when the engine has been halted by JACK,
561                    in which case, there is nothing we can do here.
562                    */
563                 return 0;
564         }
565
566         {
567                 RCUWriter<Ports> writer (ports);
568                 boost::shared_ptr<Ports> ps = writer.get_copy ();
569                 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
570
571                 if (x != ps->end()) {
572                         ps->erase (x);
573                 }
574
575                 /* writer goes out of scope, forces update */
576         }
577
578         ports.flush ();
579
580         return 0;
581 }
582
583 int
584 AudioEngine::connect (const string& source, const string& destination)
585 {
586         int ret;
587
588         if (!_running) {
589                 if (!_has_run) {
590                         fatal << _("connect called before engine was started") << endmsg;
591                         /*NOTREACHED*/
592                 } else {
593                         return -1;
594                 }
595         }
596
597         string s = make_port_name_non_relative (source);
598         string d = make_port_name_non_relative (destination);
599
600
601         boost::shared_ptr<Port> src = get_port_by_name (s);
602         boost::shared_ptr<Port> dst = get_port_by_name (d);
603
604         if (src) {
605                 ret = src->connect (d);
606         } else if (dst) {
607                 ret = dst->connect (s);
608         } else {
609                 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
610                 ret = -1;
611         }
612
613         if (ret > 0) {
614                 /* already exists - no error, no warning */
615         } else if (ret < 0) {
616                 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
617                                         source, s, destination, d)
618                       << endmsg;
619         }
620
621         return ret;
622 }
623
624 int
625 AudioEngine::disconnect (const string& source, const string& destination)
626 {
627         int ret;
628
629         if (!_running) {
630                 if (!_has_run) {
631                         fatal << _("disconnect called before engine was started") << endmsg;
632                         /*NOTREACHED*/
633                 } else {
634                         return -1;
635                 }
636         }
637
638         string s = make_port_name_non_relative (source);
639         string d = make_port_name_non_relative (destination);
640
641         boost::shared_ptr<Port> src = get_port_by_name (s);
642         boost::shared_ptr<Port> dst = get_port_by_name (d);
643
644         if (src) {
645                         ret = src->disconnect (d);
646         } else if (dst) {
647                         ret = dst->disconnect (s);
648         } else {
649                 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
650                 ret = -1;
651         }
652         return ret;
653 }
654
655 int
656 AudioEngine::disconnect (boost::shared_ptr<Port> port)
657 {
658         GET_PRIVATE_JACK_POINTER_RET (_jack,-1);
659
660         if (!_running) {
661                 if (!_has_run) {
662                         fatal << _("disconnect called before engine was started") << endmsg;
663                         /*NOTREACHED*/
664                 } else {
665                         return -1;
666                 }
667         }
668
669         return port->disconnect_all ();
670 }
671
672 ARDOUR::framecnt_t
673 AudioEngine::frame_rate () const
674 {
675         GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
676         if (_frame_rate == 0) {
677                 return (_frame_rate = jack_get_sample_rate (_priv_jack));
678         } else {
679                 return _frame_rate;
680         }
681 }
682
683 size_t
684 AudioEngine::raw_buffer_size (DataType t)
685 {
686         std::map<DataType,size_t>::const_iterator s = _raw_buffer_sizes.find(t);
687         return (s != _raw_buffer_sizes.end()) ? s->second : 0;
688 }
689
690 ARDOUR::pframes_t
691 AudioEngine::frames_per_cycle () const
692 {
693         GET_PRIVATE_JACK_POINTER_RET (_jack,0);
694         if (_buffer_size == 0) {
695                 return jack_get_buffer_size (_jack);
696         } else {
697                 return _buffer_size;
698         }
699 }
700
701 /** @param name Full or short name of port
702  *  @return Corresponding Port or 0.
703  */
704
705 boost::shared_ptr<Port>
706 AudioEngine::get_port_by_name (const string& portname)
707 {
708         if (!_running) {
709                 if (!_has_run) {
710                         fatal << _("get_port_by_name() called before engine was started") << endmsg;
711                         /*NOTREACHED*/
712                 } else {
713                         boost::shared_ptr<Port> ();
714                 }
715         }
716
717         if (!port_is_mine (portname)) {
718                 /* not an ardour port */
719                 return boost::shared_ptr<Port> ();
720         }
721
722         boost::shared_ptr<Ports> pr = ports.reader();
723         std::string rel = make_port_name_relative (portname);
724         Ports::iterator x = pr->find (rel);
725
726         if (x != pr->end()) {
727                 /* its possible that the port was renamed by some 3rd party and
728                    we don't know about it. check for this (the check is quick
729                    and cheap), and if so, rename the port (which will alter
730                    the port map as a side effect).
731                 */
732                 const std::string check = make_port_name_relative (jack_port_name (x->second->jack_port()));
733                 if (check != rel) {
734                         x->second->set_name (check);
735                 }
736                 return x->second;
737         }
738
739         return boost::shared_ptr<Port> ();
740 }
741
742 void
743 AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
744 {
745         RCUWriter<Ports> writer (ports);
746         boost::shared_ptr<Ports> p = writer.get_copy();
747         Ports::iterator x = p->find (old_relative_name);
748         
749         if (x != p->end()) {
750                 boost::shared_ptr<Port> port = x->second;
751                 p->erase (x);
752                 p->insert (make_pair (new_relative_name, port));
753         }
754 }
755
756 const char **
757 AudioEngine::get_ports (const string& port_name_pattern, const string& type_name_pattern, uint32_t flags)
758 {
759         GET_PRIVATE_JACK_POINTER_RET (_jack,0);
760         if (!_running) {
761                 if (!_has_run) {
762                         fatal << _("get_ports called before engine was started") << endmsg;
763                         /*NOTREACHED*/
764                 } else {
765                         return 0;
766                 }
767         }
768         return jack_get_ports (_priv_jack, port_name_pattern.c_str(), type_name_pattern.c_str(), flags);
769 }
770
771 void
772 AudioEngine::died ()
773 {
774         /* called from a signal handler for SIGPIPE */
775
776         stop_metering_thread ();
777
778         _running = false;
779         _buffer_size = 0;
780         _frame_rate = 0;
781         _jack = 0;
782 }
783
784 bool
785 AudioEngine::can_request_hardware_monitoring ()
786 {
787         GET_PRIVATE_JACK_POINTER_RET (_jack,false);
788         const char ** ports;
789
790         if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) {
791                 return false;
792         }
793
794         free (ports);
795
796         return true;
797 }
798
799 ChanCount
800 AudioEngine::n_physical (unsigned long flags) const
801 {
802         ChanCount c;
803
804         GET_PRIVATE_JACK_POINTER_RET (_jack, c);
805
806         const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags);
807         if (ports == 0) {
808                 return c;
809         }
810
811         for (uint32_t i = 0; ports[i]; ++i) {
812                 if (!strstr (ports[i], "Midi-Through")) {
813                         DataType t (jack_port_type (jack_port_by_name (_jack, ports[i])));
814                         c.set (t, c.get (t) + 1);
815                 }
816         }
817
818         free (ports);
819
820         return c;
821 }
822
823 ChanCount
824 AudioEngine::n_physical_inputs () const
825 {
826         return n_physical (JackPortIsInput);
827 }
828
829 ChanCount
830 AudioEngine::n_physical_outputs () const
831 {
832         return n_physical (JackPortIsOutput);
833 }
834
835 void
836 AudioEngine::get_physical (DataType type, unsigned long flags, vector<string>& phy)
837 {
838         GET_PRIVATE_JACK_POINTER (_jack);
839         const char ** ports;
840
841         if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) {
842                 return;
843         }
844
845         if (ports) {
846                 for (uint32_t i = 0; ports[i]; ++i) {
847                         if (strstr (ports[i], "Midi-Through")) {
848                                 continue;
849                         }
850                         phy.push_back (ports[i]);
851                 }
852                 free (ports);
853         }
854 }
855
856 /** Get physical ports for which JackPortIsOutput is set; ie those that correspond to
857  *  a physical input connector.
858  */
859 void
860 AudioEngine::get_physical_inputs (DataType type, vector<string>& ins)
861 {
862         get_physical (type, JackPortIsOutput, ins);
863 }
864
865 /** Get physical ports for which JackPortIsInput is set; ie those that correspond to
866  *  a physical output connector.
867  */
868 void
869 AudioEngine::get_physical_outputs (DataType type, vector<string>& outs)
870 {
871         get_physical (type, JackPortIsInput, outs);
872 }
873
874
875 int
876 AudioEngine::reset_timebase ()
877 {
878         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
879         if (_session) {
880                 if (_session->config.get_jack_time_master()) {
881                         return jack_set_timebase_callback (_priv_jack, 0, _jack_timebase_callback, this);
882                 } else {
883                         return jack_release_timebase (_jack);
884                 }
885         }
886         return 0;
887 }
888
889 void
890 AudioEngine::remove_all_ports ()
891 {
892         /* make sure that JACK callbacks that will be invoked as we cleanup
893          * ports know that they have nothing to do.
894          */
895
896         port_remove_in_progress = true;
897
898         /* process lock MUST be held by caller
899         */
900
901         {
902                 RCUWriter<Ports> writer (ports);
903                 boost::shared_ptr<Ports> ps = writer.get_copy ();
904                 ps->clear ();
905         }
906
907         /* clear dead wood list in RCU */
908
909         ports.flush ();
910
911         port_remove_in_progress = false;
912 }
913
914
915 string
916 AudioEngine::make_port_name_relative (string portname) const
917 {
918         string::size_type len;
919         string::size_type n;
920
921         len = portname.length();
922
923         for (n = 0; n < len; ++n) {
924                 if (portname[n] == ':') {
925                         break;
926                 }
927         }
928
929         if ((n != len) && (portname.substr (0, n) == jack_client_name)) {
930                 return portname.substr (n+1);
931         }
932
933         return portname;
934 }
935
936 string
937 AudioEngine::make_port_name_non_relative (string portname) const
938 {
939         string str;
940
941         if (portname.find_first_of (':') != string::npos) {
942                 return portname;
943         }
944
945         str  = jack_client_name;
946         str += ':';
947         str += portname;
948
949         return str;
950 }
951
952 bool
953 AudioEngine::port_is_mine (const string& portname) const
954 {
955         if (portname.find_first_of (':') != string::npos) {
956                 if (portname.substr (0, jack_client_name.length ()) != jack_client_name) {
957                         return false;
958                 }
959         }
960         return true;
961 }
962
963 bool
964 AudioEngine::port_is_physical (const std::string& portname) const
965 {
966         GET_PRIVATE_JACK_POINTER_RET(_jack, false);
967
968         jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str());
969
970         if (!port) {
971                 return false;
972         }
973
974         return jack_port_flags (port) & JackPortIsPhysical;
975 }
976
977 void
978 AudioEngine::destroy ()
979 {
980         delete _instance;
981         _instance = 0;
982 }
983
984 int
985 AudioEngine::discover_backends ()
986 {
987         vector<std::string> backend_modules;
988         AudioBackend* backend;
989
990         Glib::PatternSpec so_extension_pattern("*.so");
991         Glib::PatternSpec dylib_extension_pattern("*.dylib");
992
993         find_matching_files_in_search_path (backend_search_path (),
994                                             so_extension_pattern, backend_modules);
995
996         find_matching_files_in_search_path (backend_search_path (),
997                                             dylib_extension_pattern, backend_modules);
998
999         DEBUG_TRACE (DEBUG::Panning, string_compose (_("looking for backends in %1"), backend_search_path().to_string()));
1000
1001         for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) {
1002                 if ((backend = backend_discover (*i)) != 0) {
1003                         _backends.insert (make_pair (backend->name(), backend));
1004                 }
1005         }
1006 }
1007
1008 AudioBackend*
1009 AudioEngine::backend_discover (string path)
1010 {
1011         Glib::Module* module = new Glib::Module(path);
1012         AudioBackend* (*dfunc)(void);
1013         void* func = 0;
1014
1015         if (!module) {
1016                 error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path,
1017                                 Glib::Module::get_last_error()) << endmsg;
1018                 delete module;
1019                 return 0;
1020         }
1021
1022         if (!module->get_symbol("backend_factory", func)) {
1023                 error << string_compose(_("AudioEngine: module \"%1\" has no factory function."), path) << endmsg;
1024                 error << Glib::Module::get_last_error() << endmsg;
1025                 delete module;
1026                 return 0;
1027         }
1028
1029         dfunc = (AudioBackend* (*)(void))func;
1030         AudioBackend* backend = dfunc();
1031
1032         return backend;
1033 }