2 // Copyright (C) 2009, 2010 Tim Blechmann
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.
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.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; see the file COPYING. If not, write to
16 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 // Boston, MA 02111-1307, USA.
19 #ifndef AUDIO_BACKEND_JACK_BACKEND_HPP
20 #define AUDIO_BACKEND_JACK_BACKEND_HPP
26 #include <jack/jack.h>
27 #include <jack/thread.h>
29 #include "utilities/branch_hints.hpp"
31 #include "audio_backend_common.hpp"
32 #include "cpu_time_info.hpp"
38 * the jack callback thread is pinned to the first cpu of the system
40 * \todo later it may be interesting to directly map the io busses to the jack port regions
41 * \todo rethink the use of output port lock
43 template <typename engine_functor
,
44 typename sample_type
= float,
48 public detail::audio_delivery_helper
<sample_type
, jack_default_audio_sample_t
, blocking
, false>,
49 public detail::audio_settings_basic
,
50 protected engine_functor
52 typedef detail::audio_delivery_helper
<sample_type
, jack_default_audio_sample_t
, blocking
, false> super
;
56 client(NULL
), time_is_synced(false)
61 if (audio_is_active())
67 uint32_t get_audio_blocksize(void) const
73 void open_client(std::string
const & server_name
, std::string
const & name
, uint32_t input_port_count
,
74 uint32_t output_port_count
, uint32_t blocksize
)
76 blocksize_
= blocksize
;
79 client
= server_name
.empty() ? jack_client_open(name
.c_str(), JackNoStartServer
, &status
)
80 : jack_client_open(name
.c_str(), jack_options_t(JackNoStartServer
| JackServerName
),
81 &status
, server_name
.c_str());
82 boost::atomic_thread_fence(boost::memory_order_release
); // ensure visibility on other threads
84 if (status
& JackServerFailed
)
85 throw std::runtime_error("Unable to connect to JACK server");
87 if (status
& JackNameNotUnique
) {
88 const char * client_name
= jack_get_client_name(client
);
89 std::cout
<< "unique client name: " << client_name
<< std::endl
;
92 /* initialize callbacks */
93 jack_set_thread_init_callback (client
, jack_thread_init_callback
, this);
94 jack_set_process_callback (client
, jack_process_callback
, this);
95 jack_set_xrun_callback(client
, jack_xrun_callback
, this);
96 jack_on_info_shutdown(client
, (JackInfoShutdownCallback
)jack_on_info_shutdown_callback
, NULL
);
100 for (uint32_t i
= 0; i
!= input_port_count
; ++i
) {
101 std::string
portname ("input_");
102 portname
+= std::to_string(i
+1);
104 jack_port_register(client
, portname
.c_str(), JACK_DEFAULT_AUDIO_TYPE
, JackPortIsInput
, 0);
105 input_ports
.push_back(port
);
107 input_channels
= input_port_count
;
108 super::input_samples
.resize(input_port_count
);
110 output_ports
.clear();
111 for (uint32_t i
= 0; i
!= output_port_count
; ++i
) {
112 std::string
portname ("output_");
113 portname
+= std::to_string(i
+1);
115 jack_port_register(client
, portname
.c_str(), JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
116 output_ports
.push_back(port
);
118 output_channels
= output_port_count
;
119 super::output_samples
.resize(output_port_count
);
121 samplerate_
= jack_get_sample_rate(client
);
122 jack_frames
= jack_get_buffer_size(client
);
124 if (jack_frames
% blocksize_
)
125 throw std::runtime_error("Jack buffer size is not a multiple of blocksize");
128 void close_client(void)
131 jack_client_close(client
);
136 bool audio_is_opened(void)
138 return client
!= NULL
;
141 bool audio_is_active(void)
146 void activate_audio(void)
149 jack_activate(client
);
152 void deactivate_audio(void)
154 jack_deactivate(client
);
158 void get_cpuload(float & peak
, float & average
) const
160 cpu_time_accumulator
.get(peak
, average
);
163 int connect_input(size_t channel
, const char * portname
)
165 if (channel
>= input_ports
.size())
167 return jack_connect(client
, portname
, jack_port_name(input_ports
[channel
]));
170 int connect_output(size_t channel
, const char * portname
)
172 if (channel
>= output_ports
.size())
174 return jack_connect(client
, jack_port_name(output_ports
[channel
]), portname
);
177 int connect_all_inputs(const char * client_name
)
179 const char **ports
= jack_get_ports (client
, client_name
, NULL
, JackPortIsOutput
);
186 if (i
== input_ports
.size())
189 int err
= jack_connect(client
, ports
[i
], jack_port_name(input_ports
[i
]));
199 int connect_all_outputs(const char * client_name
)
201 const char **ports
= jack_get_ports (client
, client_name
, NULL
, JackPortIsInput
);
208 if (i
== output_ports
.size())
211 int err
= jack_connect(client
, jack_port_name(output_ports
[i
]), ports
[i
]);
221 int max_realtime_priority(void) const
223 return jack_client_max_real_time_priority(client
);
226 int realtime_priority(void) const
228 return jack_client_real_time_priority(client
);
232 static void jack_thread_init_callback(void * arg
)
234 boost::atomic_thread_fence(boost::memory_order_acquire
);
235 jack_backend
* self
= static_cast<jack_backend
*>(arg
);
236 if (jack_client_thread_id(self
->client
) == pthread_self())
237 engine_functor::init_thread();
239 name_thread("Jack Helper");
242 static int jack_process_callback(jack_nframes_t frames
, void * arg
)
244 return static_cast<jack_backend
*>(arg
)->perform(frames
);
247 static int jack_on_info_shutdown_callback(jack_status_t code
, const char *reason
, void *arg
)
249 std::cerr
<< "Jack server was shut down: " << reason
<< std::endl
;
250 std::cerr
<< "Exiting ..." << std::endl
;
251 exit(0); // TODO: later we may want to call a function
254 static int jack_xrun_callback(void * arg
)
256 return static_cast<jack_backend
*>(arg
)->handle_xrun();
259 int handle_xrun(void)
261 time_is_synced
= false;
262 engine_functor::log_("Jack: xrun detected - resyncing clock\n");
266 int perform(jack_nframes_t frames
)
268 if (unlikely(!time_is_synced
)) {
269 engine_functor::sync_clock();
270 time_is_synced
= true;
273 /* get port regions */
274 jack_default_audio_sample_t
** inputs
= (jack_default_audio_sample_t
**)alloca(input_channels
* sizeof(jack_default_audio_sample_t
*));
275 jack_default_audio_sample_t
** outputs
= (jack_default_audio_sample_t
**)alloca(output_channels
* sizeof(jack_default_audio_sample_t
*));
276 for (uint16_t i
= 0; i
!= input_channels
; ++i
)
277 inputs
[i
] = (jack_default_audio_sample_t
*) jack_port_get_buffer(input_ports
[i
], frames
);
279 for (uint16_t i
= 0; i
!= output_channels
; ++i
)
280 outputs
[i
] = (jack_default_audio_sample_t
*) jack_port_get_buffer(output_ports
[i
], frames
);
282 jack_nframes_t processed
= 0;
283 while (processed
!= frames
) {
284 super::fetch_inputs((const float**)inputs
, blocksize_
, input_channels
);
285 engine_functor::run_tick();
286 super::deliver_outputs(outputs
, blocksize_
, output_channels
);
287 processed
+= blocksize_
;
290 cpu_time_accumulator
.update(jack_cpu_load(client
));
295 static int jack_buffersize_callback(jack_nframes_t frames
, void * arg
)
297 return static_cast<jack_backend
*>(arg
)->buffer_size_callback(frames
);
300 int buffer_size_callback(jack_nframes_t frames
)
302 jack_frames
= frames
;
303 if (jack_frames
% blocksize_
)
304 /* we need a multiple of the blocksize */
309 jack_client_t
* client
;
310 jack_status_t status
;
316 std::vector
<jack_port_t
*> input_ports
, output_ports
;
317 jack_nframes_t jack_frames
;
318 cpu_time_info cpu_time_accumulator
;
321 } /* namespace nova */
324 #endif /* AUDIO_BACKEND_JACK_BACKEND_HPP */