inch-like progress on defining the API for AudioBackend and separating AudioEngine...
[ardour.git] / libs / ardour / jack_audiobackend.cc
1 #include "ardour/jack_audiobackend.h"
2
3 #define GET_PRIVATE_JACK_POINTER(j)  jack_client_t* _priv_jack = (jack_client_t*) (j); if (!_priv_jack) { return; }
4 #define GET_PRIVATE_JACK_POINTER_RET(j,r) jack_client_t* _priv_jack = (jack_client_t*) (j); if (!_priv_jack) { return r; }
5
6 int
7 JACKAudioBackend::start ()
8 {
9         Glib::Threads::Mutex::Lock lm (_state_lock);
10
11         if (running()) {
12                 /* already running */
13                 return 1;
14         }
15 }
16
17 int
18 JACKAudioBackend::stop ()
19 {
20         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
21
22         {
23                 Glib::Threads::Mutex::Lock lm (_process_lock);
24                 jack_client_close (_priv_jack);
25                 _jack = 0;
26         }
27
28         _buffer_size = 0;
29         _frame_rate = 0;
30         _raw_buffer_sizes.clear();
31
32         return 0;
33 }
34
35 int
36 JACKAudioBackend::pause ()
37 {
38         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
39
40         if (_priv_jack) {
41                 jack_deactivate (_priv_jack);
42         }
43
44         return 0;
45 }
46
47 int
48 JACKAudioBackend::freewheel (bool onoff)
49 {
50         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
51
52         if (onoff == _freewheeling) {
53                 /* already doing what has been asked for */
54                 
55                 return 0;
56         }
57
58         return jack_set_freewheel (_priv_jack, onoff);
59 }
60
61 int
62 JACKAudioBackend::set_parameters (const Parameters& params)
63 {
64         return 0;
65 }
66
67 int 
68 JACKAudioBackend::get_parameters (Parameters& params) const
69 {
70         return 0;
71 }
72
73 /*--- private support methods ---*/
74
75 int
76 JACKAudioBackend::connect_to_jack (string client_name, string session_uuid)
77 {
78         EnvironmentalProtectionAgency* global_epa = EnvironmentalProtectionAgency::get_global_epa ();
79         boost::scoped_ptr<EnvironmentalProtectionAgency> current_epa;
80         jack_status_t status;
81
82         /* revert all environment settings back to whatever they were when ardour started
83          */
84
85         if (global_epa) {
86                 current_epa.reset (new EnvironmentalProtectionAgency(true)); /* will restore settings when we leave scope */
87                 global_epa->restore ();
88         }
89
90         jack_client_name = client_name; /* might be reset below */
91 #ifdef HAVE_JACK_SESSION
92         if (!session_uuid.empty())
93             _jack = jack_client_open (jack_client_name.c_str(), JackSessionID, &status, session_uuid.c_str());
94         else
95 #endif
96         _jack = jack_client_open (jack_client_name.c_str(), JackNullOption, &status, 0);
97
98         if (_jack == NULL) {
99                 // error message is not useful here
100                 return -1;
101         }
102
103         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
104
105         if (status & JackNameNotUnique) {
106                 jack_client_name = jack_get_client_name (_priv_jack);
107         }
108
109         return 0;
110 }
111
112 int
113 JACKAudioBackend::disconnect_from_jack ()
114 {
115
116 int
117 AudioEngine::reconnect_to_jack ()
118 {
119         if (_running) {
120                 disconnect_from_jack ();
121                 /* XXX give jackd a chance */
122                 Glib::usleep (250000);
123         }
124
125         if (connect_to_jack (jack_client_name, "")) {
126                 error << _("failed to connect to JACK") << endmsg;
127                 return -1;
128         }
129
130         Ports::iterator i;
131
132         boost::shared_ptr<Ports> p = ports.reader ();
133
134         for (i = p->begin(); i != p->end(); ++i) {
135                 if (i->second->reestablish ()) {
136                         break;
137                 }
138         }
139
140         if (i != p->end()) {
141                 /* failed */
142                 remove_all_ports ();
143                 return -1;
144         }
145
146         GET_PRIVATE_JACK_POINTER_RET (_jack,-1);
147
148         MIDI::Manager::instance()->reestablish (_priv_jack);
149
150         if (_session) {
151                 _session->reset_jack_connection (_priv_jack);
152                 jack_bufsize_callback (jack_get_buffer_size (_priv_jack));
153                 _session->set_frame_rate (jack_get_sample_rate (_priv_jack));
154         }
155
156         last_monitor_check = 0;
157
158         set_jack_callbacks ();
159
160         if (jack_activate (_priv_jack) == 0) {
161                 _running = true;
162                 _has_run = true;
163         } else {
164                 return -1;
165         }
166
167         /* re-establish connections */
168
169         for (i = p->begin(); i != p->end(); ++i) {
170                 i->second->reconnect ();
171         }
172
173         MIDI::Manager::instance()->reconnect ();
174
175         Running (); /* EMIT SIGNAL*/
176
177         start_metering_thread ();
178
179         return 0;
180 }
181
182 int
183 JACKAudioBackend::request_buffer_size (pframes_t nframes)
184 {
185         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
186
187         if (nframes == jack_get_buffer_size (_priv_jack)) {
188                 return 0;
189         }
190
191         return jack_set_buffer_size (_priv_jack, nframes);
192 }
193
194 /* --- TRANSPORT STATE MANAGEMENT --- */
195
196 void
197 AudioEngine::transport_stop ()
198 {
199         GET_PRIVATE_JACK_POINTER (_jack);
200         jack_transport_stop (_priv_jack);
201 }
202
203 void
204 AudioEngine::transport_start ()
205 {
206         GET_PRIVATE_JACK_POINTER (_jack);
207         jack_transport_start (_priv_jack);
208 }
209
210 void
211 AudioEngine::transport_locate (framepos_t where)
212 {
213         GET_PRIVATE_JACK_POINTER (_jack);
214         jack_transport_locate (_priv_jack, where);
215 }
216
217 framepos_t 
218 AudioEngine::transport_frame () const 
219 {
220         GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
221         return jack_get_current_transport_frame (_priv_jack);
222 }
223
224 AudioEngine::TransportState
225 AudioEngine::transport_state ()
226 {
227         GET_PRIVATE_JACK_POINTER_RET (_jack, ((TransportState) JackTransportStopped));
228         jack_position_t pos;
229         return (TransportState) jack_transport_query (_priv_jack, &pos);
230 }
231
232
233 /* JACK Callbacks */
234
235 static void
236 ardour_jack_error (const char* msg)
237 {
238         error << "JACK: " << msg << endmsg;
239 }
240
241 void
242 JACKAudioBackend::set_jack_callbacks ()
243 {
244         GET_PRIVATE_JACK_POINTER (_jack);
245
246         if (jack_on_info_shutdown) {
247                 jack_on_info_shutdown (_priv_jack, halted_info, this);
248         } else {
249                 jack_on_shutdown (_priv_jack, halted, this);
250         }
251
252         jack_set_thread_init_callback (_priv_jack, _thread_init_callback, this);
253         jack_set_process_thread (_priv_jack, _process_thread, this);
254         jack_set_sample_rate_callback (_priv_jack, _sample_rate_callback, this);
255         jack_set_buffer_size_callback (_priv_jack, _bufsize_callback, this);
256         jack_set_graph_order_callback (_priv_jack, _graph_order_callback, this);
257         jack_set_port_registration_callback (_priv_jack, _registration_callback, this);
258         jack_set_port_connect_callback (_priv_jack, _connect_callback, this);
259         jack_set_xrun_callback (_priv_jack, _xrun_callback, this);
260         jack_set_sync_callback (_priv_jack, _jack_sync_callback, this);
261         jack_set_freewheel_callback (_priv_jack, _freewheel_callback, this);
262
263         if (_session && _session->config.get_jack_time_master()) {
264                 jack_set_timebase_callback (_priv_jack, 0, _jack_timebase_callback, this);
265         }
266
267 #ifdef HAVE_JACK_SESSION
268         if( jack_set_session_callback)
269                 jack_set_session_callback (_priv_jack, _session_callback, this);
270 #endif
271
272         if (jack_set_latency_callback) {
273                 jack_set_latency_callback (_priv_jack, _latency_callback, this);
274         }
275
276         jack_set_error_function (ardour_jack_error);
277 }
278
279 void
280 JACKAudioBackend::_jack_timebase_callback (jack_transport_state_t state, pframes_t nframes,
281                                       jack_position_t* pos, int new_position, void *arg)
282 {
283         static_cast<AudioEngine*> (arg)->jack_timebase_callback (state, nframes, pos, new_position);
284 }
285
286 void
287 JACKAudioBackend::jack_timebase_callback (jack_transport_state_t state, pframes_t nframes,
288                                      jack_position_t* pos, int new_position)
289 {
290         if (_jack && _session && _session->synced_to_jack()) {
291                 _session->jack_timebase_callback (state, nframes, pos, new_position);
292         }
293 }
294
295 int
296 JACKAudioBackend::_jack_sync_callback (jack_transport_state_t state, jack_position_t* pos, void* arg)
297 {
298         return static_cast<AudioEngine*> (arg)->jack_sync_callback (state, pos);
299 }
300
301 int
302 JACKAudioBackend::jack_sync_callback (jack_transport_state_t state, jack_position_t* pos)
303 {
304         if (_jack && _session) {
305                 return _session->jack_sync_callback (state, pos);
306         }
307
308         return true;
309 }
310
311 int
312 JACKAudioBackend::_xrun_callback (void *arg)
313 {
314         AudioEngine* ae = static_cast<AudioEngine*> (arg);
315         if (ae->connected()) {
316                 ae->Xrun (); /* EMIT SIGNAL */
317         }
318         return 0;
319 }
320
321 #ifdef HAVE_JACK_SESSION
322 void
323 JACKAudioBackend::_session_callback (jack_session_event_t *event, void *arg)
324 {
325         AudioEngine* ae = static_cast<AudioEngine*> (arg);
326         if (ae->connected()) {
327                 ae->JackSessionEvent ( event ); /* EMIT SIGNAL */
328         }
329 }
330 #endif
331
332 int
333 JACKAudioBackend::_graph_order_callback (void *arg)
334 {
335         AudioEngine* ae = static_cast<AudioEngine*> (arg);
336
337         if (ae->connected() && !ae->port_remove_in_progress) {
338                 ae->GraphReordered (); /* EMIT SIGNAL */
339         }
340         
341         return 0;
342 }
343
344 void
345 JACKAudioBackend::_freewheel_callback (int onoff, void *arg)
346 {
347         static_cast<AudioEngine*>(arg)->freewheel_callback (onoff);
348 }
349
350 void
351 JACKAudioBackend::freewheel_callback (int onoff)
352 {
353         _freewheeling = onoff;
354
355         if (onoff) {
356                 _pre_freewheel_mmc_enabled = MIDI::Manager::instance()->mmc()->send_enabled ();
357                 MIDI::Manager::instance()->mmc()->enable_send (false);
358         } else {
359                 MIDI::Manager::instance()->mmc()->enable_send (_pre_freewheel_mmc_enabled);
360         }
361 }
362
363 void
364 JACKAudioBackend::_registration_callback (jack_port_id_t /*id*/, int /*reg*/, void* arg)
365 {
366         AudioEngine* ae = static_cast<AudioEngine*> (arg);
367
368         if (!ae->port_remove_in_progress) {
369                 ae->PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
370         }
371 }
372
373 void
374 JACKAudioBackend::_latency_callback (jack_latency_callback_mode_t mode, void* arg)
375 {
376         return static_cast<AudioEngine *> (arg)->jack_latency_callback (mode);
377 }
378
379 void
380 JACKAudioBackend::_connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn, void* arg)
381 {
382         AudioEngine* ae = static_cast<AudioEngine*> (arg);
383         ae->connect_callback (id_a, id_b, conn);
384 }
385
386 void
387 JACKAudioBackend::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn)
388 {
389         if (port_remove_in_progress) {
390                 return;
391         }
392
393         GET_PRIVATE_JACK_POINTER (_jack);
394
395         jack_port_t* jack_port_a = jack_port_by_id (_priv_jack, id_a);
396         jack_port_t* jack_port_b = jack_port_by_id (_priv_jack, id_b);
397
398         boost::shared_ptr<Port> port_a;
399         boost::shared_ptr<Port> port_b;
400         Ports::iterator x;
401         boost::shared_ptr<Ports> pr = ports.reader ();
402
403
404         x = pr->find (make_port_name_relative (jack_port_name (jack_port_a)));
405         if (x != pr->end()) {
406                 port_a = x->second;
407         }
408
409         x = pr->find (make_port_name_relative (jack_port_name (jack_port_b)));
410         if (x != pr->end()) {
411                 port_b = x->second;
412         }
413
414         PortConnectedOrDisconnected (
415                 port_a, jack_port_name (jack_port_a),
416                 port_b, jack_port_name (jack_port_b),
417                 conn == 0 ? false : true
418                 ); /* EMIT SIGNAL */
419 }
420
421 void*
422 JACKAudioBackend::_process_thread (void *arg)
423 {
424         return static_cast<AudioEngine *> (arg)->process_thread ();
425 }
426
427 void*
428 JACKAudioBackend::process_thread ()
429 {
430         /* JACK doesn't do this for us when we use the wait API
431          */
432
433         _thread_init_callback (0);
434
435         _main_thread = new ProcessThread;
436
437         while (1) {
438                 GET_PRIVATE_JACK_POINTER_RET(_jack,0);
439
440                 pframes_t nframes = jack_cycle_wait (_priv_jack);
441
442                 if (process_callback (nframes)) {
443                         return 0;
444                 }
445
446                 jack_cycle_signal (_priv_jack, 0);
447         }
448
449         return 0;
450 }
451
452 int
453 JACKAudioBackend::_sample_rate_callback (pframes_t nframes, void *arg)
454 {
455         return static_cast<AudioEngine *> (arg)->jack_sample_rate_callback (nframes);
456 }
457
458 int
459 JACKAudioBackend::jack_sample_rate_callback (pframes_t nframes)
460 {
461         _frame_rate = nframes;
462         _usecs_per_cycle = (int) floor ((((double) frames_per_cycle() / nframes)) * 1000000.0);
463
464         /* check for monitor input change every 1/10th of second */
465
466         monitor_check_interval = nframes / 10;
467         last_monitor_check = 0;
468
469         if (_session) {
470                 _session->set_frame_rate (nframes);
471         }
472
473         SampleRateChanged (nframes); /* EMIT SIGNAL */
474
475         return 0;
476 }
477
478 void
479 JACKAudioBackend::jack_latency_callback (jack_latency_callback_mode_t mode)
480 {
481         if (_session) {
482                 _session->update_latency (mode == JackPlaybackLatency);
483         }
484 }
485
486 int
487 JACKAudioBackend::_bufsize_callback (pframes_t nframes, void *arg)
488 {
489         return static_cast<AudioEngine *> (arg)->jack_bufsize_callback (nframes);
490 }
491
492 int
493 JACKAudioBackend::jack_bufsize_callback (pframes_t nframes)
494 {
495         /* if the size has not changed, this should be a no-op */
496
497         if (nframes == _buffer_size) {
498                 return 0;
499         }
500
501         GET_PRIVATE_JACK_POINTER_RET (_jack, 1);
502
503         _buffer_size = nframes;
504         _usecs_per_cycle = (int) floor ((((double) nframes / frame_rate())) * 1000000.0);
505         last_monitor_check = 0;
506
507         if (jack_port_type_get_buffer_size) {
508                 _raw_buffer_sizes[DataType::AUDIO] = jack_port_type_get_buffer_size (_priv_jack, JACK_DEFAULT_AUDIO_TYPE);
509                 _raw_buffer_sizes[DataType::MIDI] = jack_port_type_get_buffer_size (_priv_jack, JACK_DEFAULT_MIDI_TYPE);
510         } else {
511
512                 /* Old version of JACK.
513
514                    These crude guesses, see below where we try to get the right answers.
515
516                    Note that our guess for MIDI deliberatey tries to overestimate
517                    by a little. It would be nicer if we could get the actual
518                    size from a port, but we have to use this estimate in the
519                    event that there are no MIDI ports currently. If there are
520                    the value will be adjusted below.
521                 */
522
523                 _raw_buffer_sizes[DataType::AUDIO] = nframes * sizeof (Sample);
524                 _raw_buffer_sizes[DataType::MIDI] = nframes * 4 - (nframes/2);
525         }
526
527         {
528                 Glib::Threads::Mutex::Lock lm (_process_lock);
529
530                 boost::shared_ptr<Ports> p = ports.reader();
531
532                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
533                         i->second->reset();
534                 }
535         }
536
537         if (_session) {
538                 _session->set_block_size (_buffer_size);
539         }
540
541         return 0;
542 }
543
544 void
545 JACKAudioBackend::halted_info (jack_status_t code, const char* reason, void *arg)
546 {
547         /* called from jack shutdown handler  */
548
549         AudioEngine* ae = static_cast<AudioEngine *> (arg);
550         bool was_running = ae->_running;
551
552         ae->stop_metering_thread ();
553
554         ae->_running = false;
555         ae->_buffer_size = 0;
556         ae->_frame_rate = 0;
557         ae->_jack = 0;
558
559         if (was_running) {
560                 MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
561 #ifdef HAVE_JACK_ON_INFO_SHUTDOWN
562                 switch (code) {
563                 case JackBackendError:
564                         ae->Halted(reason); /* EMIT SIGNAL */
565                         break;
566                 default:
567                         ae->Halted(""); /* EMIT SIGNAL */
568                 }
569 #else
570                 ae->Halted(""); /* EMIT SIGNAL */
571 #endif
572         }
573 }
574
575 void
576 JACKAudioBackend::halted (void *arg)
577 {
578         cerr << "HALTED by JACK\n";
579
580         /* called from jack shutdown handler  */
581
582         AudioEngine* ae = static_cast<AudioEngine *> (arg);
583         bool was_running = ae->_running;
584
585         ae->stop_metering_thread ();
586
587         ae->_running = false;
588         ae->_buffer_size = 0;
589         ae->_frame_rate = 0;
590         ae->_jack = 0;
591
592         if (was_running) {
593                 MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
594                 ae->Halted(""); /* EMIT SIGNAL */
595         }
596 }
597