Audio Processing Framework (APF) version 0.5.0
jack_policy.h
Go to the documentation of this file.
1/******************************************************************************
2 Copyright (c) 2012-2016 Institut für Nachrichtentechnik, Universität Rostock
3 Copyright (c) 2006-2012 Quality & Usability Lab
4 Deutsche Telekom Laboratories, TU Berlin
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23*******************************************************************************/
24
25// https://AudioProcessingFramework.github.io/
26
29
30#ifndef APF_JACK_POLICY_H
31#define APF_JACK_POLICY_H
32
33#ifdef APF_JACK_POLICY_DEBUG
34#include <cstdio> // for printf()
35#endif
36
37#include <cassert> // for assert()
38
39#include "apf/jackclient.h"
40#include "apf/parameter_map.h"
41#include "apf/stringtools.h"
42#include "apf/iterator.h" // for has_begin_and_end
43
44#ifndef APF_MIMOPROCESSOR_INTERFACE_POLICY
45#define APF_MIMOPROCESSOR_INTERFACE_POLICY apf::jack_policy
46#endif
47
48namespace apf
49{
50
55class jack_policy : public JackClient
56{
57 public:
58 using sample_type = sample_t;
59 class Input;
60 class Output;
61
65
66 nframes_t block_size() const { return this->buffer_size(); }
67
68 protected:
73 : JackClient(p.get("name", "MimoProcessor"), use_jack_process_callback)
74 {}
75
76 virtual ~jack_policy() = default;
77
78 private:
79 template<typename X> class Xput;
80
81 struct i_am_in
82 {
83 using iterator = const sample_type*;
84 static const bool is_input = true;
85 static std::string prefix_name() { return "input_prefix"; }
86 static std::string default_prefix() { return "in_"; }
87 };
88
89 struct i_am_out
90 {
91 using iterator = sample_type*;
92 static const bool is_input = false;
93 static std::string prefix_name() { return "output_prefix"; }
94 static std::string default_prefix() { return "out_"; }
95 };
96
97 virtual int jack_process_callback(nframes_t nframes)
98 {
99 (void)nframes;
100 assert(nframes == this->block_size());
101 try
102 {
103 // call virtual member function which is implemented in derived class
104 // (template method design pattern)
105 this->process();
106 }
107 catch (std::exception& e)
108 {
109#ifdef APF_JACK_POLICY_DEBUG
110 printf("Error in process callback: %s\n", e.what());
111#endif
112 return 1; // Stop calling the callback
113 }
114 return 0;
115 }
116
117 virtual void process() = 0;
118};
119
120template<typename interface_policy, typename native_handle_type>
121struct thread_traits; // definition in mimoprocessor.h
122
123template<>
124struct thread_traits<jack_policy, pthread_t>
125{
126 static void update_priority(const jack_policy& obj, pthread_t thread_id) noexcept
127 {
128 if (obj.is_realtime())
129 {
130#ifdef APF_JACK_POLICY_DEBUG
131 printf("Trying to set priority...");
132#endif
133 struct sched_param param;
134 param.sched_priority = obj.get_real_time_priority();
135 if (pthread_setschedparam(thread_id, SCHED_FIFO, &param))
136 {
137 // We were trying our best to set the priority, but if it doesn't work,
138 // the show must go on!
139#ifdef APF_JACK_POLICY_DEBUG
140 printf("Can't set scheduling priority %d for thread!\n", param.sched_priority);
141#endif
142 }
143 }
144 else
145 {
146 // do nothing
147 }
148#ifdef APF_JACK_POLICY_DEBUG
149 struct sched_param param;
150 int policy;
151 pthread_getschedparam(thread_id, &policy, &param);
152 printf("worker thread: policy=%s, priority=%d\n",
153 (policy == SCHED_FIFO) ? "SCHED_FIFO" :
154 (policy == SCHED_RR) ? "SCHED_RR" :
155 (policy == SCHED_OTHER) ? "SCHED_OTHER" :
156 "???",
157 param.sched_priority);
158#endif
159 }
160};
161
162// Helper class to avoid code duplication in Input and Output
163template<typename X>
164class jack_policy::Xput
165{
166 public:
167 using iterator = typename X::iterator;
168
169 struct buffer_type : has_begin_and_end<iterator> { friend class Xput; };
170
171 void fetch_buffer()
172 {
173 this->buffer._begin = static_cast<sample_type*>(
174 jack_port_get_buffer(_port, _parent.block_size()));
175 this->buffer._end = this->buffer._begin + _parent.block_size();
176 }
177
178 std::string port_name() const { return _port_name; }
179
180 buffer_type buffer;
181
182 protected:
183 Xput(jack_policy& parent, const parameter_map& p);
184
185 ~Xput() { _parent.unregister_port(_port); }
186
187 private:
188 Xput(const Xput&); Xput& operator=(const Xput&); // deactivated
189
190 jack_policy& _parent;
191 JackClient::port_t* _port; // JACK port corresponding to this object.
192
193 JackClient::port_t* _init_port(const parameter_map& p, jack_policy& parent);
194
195 const std::string _port_name; // actual JACK port name
196};
197
198template<typename X>
199JackClient::port_t*
200jack_policy::Xput<X>::_init_port(const parameter_map& p, jack_policy& parent)
201{
202 auto name = std::string();
203
204 // first, try port_name
205 if (p.has_key("port_name"))
206 {
207 name = p["port_name"];
208 }
209 else
210 {
211 // then concatenate "input_prefix"/"output_prefix" with "id"
212 // if the prefix isn't specified, it's replaced by a default string
213 // worst case: duplicate string -> port registration will fail!
214
215 auto id = std::string();
216
217 if (p.has_key("id"))
218 {
219 id = p.get("id", "");
220 }
221 else
222 {
223 static int next_id = 1;
224 id = str::A2S(next_id++);
225 }
226
227 name = p.get(X::prefix_name(), X::default_prefix()) + id;
228 }
229 JackClient::port_t* rport = X::is_input ? parent.register_in_port(name) : parent.register_out_port(name);
230 if (rport==NULL){
231 throw std::runtime_error("Could not register JACK port!");
232 }
233 return rport;
234}
235
236template<typename X>
237jack_policy::Xput<X>::Xput(jack_policy& parent, const parameter_map& p)
238 : _parent(parent)
239 , _port(_init_port(p, _parent))
240 // get actual port name and save it to member variable
241 , _port_name(_port ? jack_port_name(_port) : "")
242{
243 // optionally connect to jack_port
244 std::string connect_to = p.get("connect-to", "");
245 if (connect_to != "")
246 {
247 if (X::is_input)
248 {
249 _parent.connect_ports(connect_to, _port_name);
250 }
251 else
252 {
253 _parent.connect_ports(_port_name, connect_to);
254 }
255 }
256}
257
258class jack_policy::Input : public Xput<i_am_in>
259{
260 protected:
261 Input(jack_policy& parent, const parameter_map& p)
262 : Xput<i_am_in>(parent, p)
263 {}
264
265 ~Input() = default;
266};
267
268class jack_policy::Output : public Xput<i_am_out>
269{
270 protected:
271 Output(jack_policy& parent, const parameter_map& p)
272 : Xput<i_am_out>(parent, p)
273 {}
274
275 ~Output() = default;
276};
277
278} // namespace apf
279
280#endif
C++ wrapper for a JACK client.
Definition: jackclient.h:68
nframes_t sample_rate() const
Definition: jackclient.h:296
bool deactivate() const
Deactivate JACK client.
Definition: jackclient.h:141
nframes_t buffer_size() const
Definition: jackclient.h:298
bool activate() const
Activate JACK client.
Definition: jackclient.h:126
@ use_jack_process_callback
JACK audio callback (jack_process_callback()) is called after activate()
Definition: jackclient.h:80
interface_policy using JACK.
Definition: jack_policy.h:56
jack_policy(const parameter_map &p=parameter_map())
Constructor.
Definition: jack_policy.h:72
Several more or less useful iterators and some macros.
JACK client (C++ wrapper for JACK).
std::string A2S(const T &input)
Converter "Anything to String".
Definition: stringtools.h:52
Audio Processing Framework.
Definition: iterator.h:61
A "dictionary" for parameters.
Helper functions for string conversion.
A "dictionary" for parameters.
Definition: parameter_map.h:68