Ardour  9.0-pre0-582-g084a23a80d
alsa_audiobackend.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
3  * Copyright (C) 2015-2018 Paul Davis <paul@linuxaudiosystems.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #ifndef __libbackend_alsa_audiobackend_h__
21 #define __libbackend_alsa_audiobackend_h__
22 
23 #include <cstdint>
24 #include <map>
25 #include <memory>
26 #include <set>
27 #include <string>
28 #include <vector>
29 
30 #include <pthread.h>
31 
32 
33 #include "pbd/natsort.h"
34 #include "pbd/rcu.h"
35 
36 #include "ardour/audio_backend.h"
39 #include "ardour/system_exec.h"
40 #include "ardour/types.h"
41 
43 
44 #include "alsa_rawmidi.h"
45 #include "alsa_sequencer.h"
46 #include "alsa_slave.h"
47 #include "zita-alsa-pcmi.h"
48 
49 namespace ARDOUR {
50 
51 class AlsaAudioBackend;
52 
54  public:
55  AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size);
56  AlsaMidiEvent (const AlsaMidiEvent& other);
57  size_t size () const { return _size; };
58  pframes_t timestamp () const { return _timestamp; };
59  const uint8_t* data () const { return _data; };
60  private:
61  size_t _size;
64 };
65 
66 typedef std::vector<AlsaMidiEvent> AlsaMidiBuffer;
67 
68 class AlsaAudioPort : public BackendPort {
69  public:
70  AlsaAudioPort (AlsaAudioBackend &b, const std::string&, PortFlags);
72 
73  DataType type () const { return DataType::AUDIO; };
74 
75  Sample* buffer () { return _buffer; }
76  const Sample* const_buffer () const { return _buffer; }
77  void* get_buffer (pframes_t nframes);
78 
79  private:
80  Sample _buffer[8192];
81 }; // class AlsaAudioPort
82 
83 class AlsaMidiPort : public BackendPort {
84  public:
85  AlsaMidiPort (AlsaAudioBackend &b, const std::string&, PortFlags);
87 
88  DataType type () const { return DataType::MIDI; };
89 
90  void* get_buffer (pframes_t nframes);
91  const AlsaMidiBuffer * const_buffer () const { return & _buffer[_bufperiod]; }
92 
93  void next_period() { if (_n_periods > 1) { get_buffer(0); _bufperiod = (_bufperiod + 1) % _n_periods; } }
94  void set_n_periods(int n) { if (n > 0 && n < 4) { _n_periods = n; } }
95 
96  private:
100 }; // class AlsaMidiPort
101 
103 {
104  public:
106  AlsaDeviceReservation (const char* device_name);
108 
109  bool acquire_device (const char* device_name, bool silent = false);
110  void release_device ();
111 
112  private:
115  void reservation_stdout (std::string, size_t);
117 };
118 
120 {
121  public:
124 
125  /* AUDIOBACKEND API */
126 
127  std::string name () const;
128  bool is_realtime () const;
129 
130  bool use_separate_input_and_output_devices () const { return true; }
131  bool match_input_output_devices_or_none () const { return false; }
132  bool can_set_period_size () const { return true; }
133 
134  std::vector<DeviceStatus> enumerate_devices () const;
135  std::vector<DeviceStatus> enumerate_input_devices () const;
136  std::vector<DeviceStatus> enumerate_output_devices () const;
137  std::vector<float> available_sample_rates (const std::string& device) const;
138  std::vector<float> available_sample_rates2 (const std::string&, const std::string&) const;
139  std::vector<uint32_t> available_buffer_sizes (const std::string& device) const;
140  std::vector<uint32_t> available_buffer_sizes2 (const std::string&, const std::string&) const;
141  std::vector<uint32_t> available_period_sizes (const std::string& driver, const std::string& device) const;
142 
145 
147  bool can_change_systemic_latency_when_running () const { return true; }
148 
149  bool can_request_update_devices () { return true; }
150  bool update_devices () { return true; }
151 
152  int set_device_name (const std::string&);
153  int set_input_device_name (const std::string&);
154  int set_output_device_name (const std::string&);
155  int set_sample_rate (float);
156  int set_buffer_size (uint32_t);
157  int set_peridod_size (uint32_t);
158  int set_interleaved (bool yn);
161  int set_systemic_midi_input_latency (std::string const, uint32_t);
162  int set_systemic_midi_output_latency (std::string const, uint32_t);
163 
164  int reset_device () { return 0; };
165 
166  /* Retrieving parameters */
167  std::string device_name () const;
168  std::string input_device_name () const;
169  std::string output_device_name () const;
170  float sample_rate () const;
171  uint32_t buffer_size () const;
172  uint32_t period_size () const;
173  bool interleaved () const;
174  uint32_t systemic_input_latency () const;
175  uint32_t systemic_output_latency () const;
176  uint32_t systemic_midi_input_latency (std::string const) const;
177  uint32_t systemic_midi_output_latency (std::string const) const;
178 
179  bool can_set_systemic_midi_latencies () const { return true; }
180 
181  /* External control app */
182  std::string control_app_name () const { return std::string (); }
184 
185  /* MIDI */
186  std::vector<std::string> enumerate_midi_options () const;
187  int set_midi_option (const std::string&);
188  std::string midi_option () const;
189 
190  std::vector<DeviceStatus> enumerate_midi_devices () const;
191  int set_midi_device_enabled (std::string const, bool);
192  bool midi_device_enabled (std::string const) const;
193 
194  /* State Control */
195  protected:
196  int _start (bool for_latency_measurement);
197  public:
198  int stop ();
199  int freewheel (bool);
200  float dsp_load () const;
202 
203  /* Process time */
207 
208  int create_process_thread (std::function<void()> func);
211  uint32_t process_thread_count ();
212 
214 
215  /* PORTENGINE API */
216 
217  void* private_handle () const;
218  const std::string& my_name () const;
219 
220  /* PortEngine API - forwarded to PortEngineSharedImpl */
221 
223  void get_physical_outputs (DataType type, std::vector<std::string>& results) { PortEngineSharedImpl::get_physical_outputs (type, results); }
224  void get_physical_inputs (DataType type, std::vector<std::string>& results) { PortEngineSharedImpl::get_physical_inputs (type, results); }
227  uint32_t port_name_size () const { return PortEngineSharedImpl::port_name_size(); }
232  int get_port_property (PortEngine::PortHandle ph, const std::string& key, std::string& value, std::string& type) const { return PortEngineSharedImpl::get_port_property (ph, key, value, type); }
233  int set_port_property (PortEngine::PortHandle ph, const std::string& key, const std::string& value, const std::string& type) { return PortEngineSharedImpl::set_port_property (ph, key, value, type); }
234  int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>& results) const { return PortEngineSharedImpl::get_ports (port_name_pattern, type, flags, results); }
236  PortEngine::PortPtr register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags) { return PortEngineSharedImpl::register_port (shortname, type, flags); }
238  int connect (const std::string& src, const std::string& dst) { return PortEngineSharedImpl::connect (src, dst); }
239  int disconnect (const std::string& src, const std::string& dst) { return PortEngineSharedImpl::disconnect (src, dst); }
240  int connect (PortEngine::PortHandle ph, const std::string& other) { return PortEngineSharedImpl::connect (ph, other); }
241  int disconnect (PortEngine::PortHandle ph, const std::string& other) { return PortEngineSharedImpl::disconnect (ph, other); }
243  bool connected (PortEngine::PortHandle ph, bool process_callback_safe) { return PortEngineSharedImpl::connected (ph, process_callback_safe); }
244  bool connected_to (PortEngine::PortHandle ph, const std::string& other, bool process_callback_safe) { return PortEngineSharedImpl::connected_to (ph, other, process_callback_safe); }
245  bool physically_connected (PortEngine::PortHandle ph, bool process_callback_safe) { return PortEngineSharedImpl::physically_connected (ph, process_callback_safe); }
246  int get_connections (PortEngine::PortHandle ph, std::vector<std::string>& results, bool process_callback_safe) { return PortEngineSharedImpl::get_connections (ph, results, process_callback_safe); }
247 
248  /* MIDI */
249  int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t const** buf, void* port_buffer, uint32_t event_index);
250  int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size);
251  uint32_t get_midi_event_count (void* port_buffer);
252  void midi_clear (void* port_buffer);
253 
254  /* Monitoring */
255 
256  bool can_monitor_input () const;
260 
261  /* Latency management */
262 
263  void set_latency_range (PortHandle, bool for_playback, LatencyRange);
265 
266  /* Getting access to the data buffer for a port */
267 
269 
271 
272  private:
273  std::string _instance_name;
275 
276  bool _run; /* keep going or stop, ardour thread */
277  bool _active; /* is running, process thread */
281 
283 
284  static std::vector<std::string> _midi_options;
285  static std::vector<AudioBackend::DeviceStatus> _input_audio_device_status;
286  static std::vector<AudioBackend::DeviceStatus> _output_audio_device_status;
287  static std::vector<AudioBackend::DeviceStatus> _duplex_audio_device_status;
288  static std::vector<AudioBackend::DeviceStatus> _midi_device_status;
291 
292  mutable std::string _input_audio_device;
293  mutable std::string _output_audio_device;
294  std::string _midi_driver_option;
295 
296  /* audio device reservation */
298 
299  /* audio settings */
300  float _samplerate;
303  static size_t _max_buffer_size;
304 
307 
308  /* midi settings */
310  bool enabled;
313  AlsaMidiDeviceInfo (bool en = true)
314  : enabled (en)
317  {}
318  };
319 
320  mutable std::map<std::string, struct AlsaMidiDeviceInfo *> _midi_devices;
321  struct AlsaMidiDeviceInfo * midi_device_info(std::string const) const;
322 
323  /* midi device changes */
328  static void* _midi_device_thread (void *arg);
331 
332  pthread_mutex_t _device_port_mutex;
333 
334  /* processing */
335  float _dsp_load;
338  pthread_t _main_thread;
339 
340  /* DLL, track main process callback timing */
341  double _t0, _t1;
342 
343  /* process threads */
344  static void* alsa_process_thread (void *);
345  std::vector<pthread_t> _threads;
346 
347  struct ThreadData {
349  std::function<void ()> f;
350  size_t stacksize;
351 
352  ThreadData (AlsaAudioBackend* e, std::function<void ()> fp, size_t stacksz)
353  : engine (e) , f (fp) , stacksize (stacksz) {}
354  };
355 
356  /* port engine */
357 
359 
361  int register_system_midi_ports (const std::string device = "");
363 
364  std::vector<AlsaMidiOut *> _rmidi_out;
365  std::vector<AlsaMidiIn *> _rmidi_in;
366 
369 
371  public:
372  enum DuplexMode {
375  FullDuplex = 3
376  };
377 
379  const char* device,
380  DuplexMode duplex,
381  unsigned int master_rate,
382  unsigned int master_samples_per_period,
383  unsigned int slave_rate,
384  unsigned int slave_samples_per_period,
385  unsigned int periods_per_cycle);
386 
388 
389  bool active; // set in sync with process-cb
390  bool halt;
391  bool dead;
392 
393  std::vector<BackendPortPtr> inputs;
394  std::vector<BackendPortPtr> outputs;
395 
398 
399  protected:
400  void update_latencies (uint32_t, uint32_t);
401 
402  private:
404  void halted ();
405  };
406 
407  /* additional re-sampled I/O */
408  bool add_slave (const char* slave_device,
409  unsigned int slave_rate,
410  unsigned int slave_spp,
411  unsigned int slave_ppc,
413 
414  typedef std::vector<AudioSlave*> AudioSlaves;
416 
417 }; // class AlsaAudioBackend
418 
419 } // namespace
420 
421 #endif /* __libbackend_alsa_audiobackend_h__ */
#define MaxAlsaMidiEventSize
Definition: alsa_midi.h:31
std::vector< BackendPortPtr > inputs
void update_latencies(uint32_t, uint32_t)
AudioSlave(const char *device, DuplexMode duplex, unsigned int master_rate, unsigned int master_samples_per_period, unsigned int slave_rate, unsigned int slave_samples_per_period, unsigned int periods_per_cycle)
std::vector< BackendPortPtr > outputs
pframes_t samples_since_cycle_start()
ARDOUR::DSPLoadCalculator _dsp_load_calc
int set_port_property(PortEngine::PortHandle ph, const std::string &key, const std::string &value, const std::string &type)
uint32_t get_midi_event_count(void *port_buffer)
ChanCount n_physical_outputs() const
int _start(bool for_latency_measurement)
std::vector< uint32_t > available_buffer_sizes2(const std::string &, const std::string &) const
LatencyRange get_latency_range(PortHandle, bool for_playback)
int disconnect(const std::string &src, const std::string &dst)
uint32_t systemic_midi_output_latency(std::string const) const
uint32_t period_size() const
int set_systemic_midi_input_latency(std::string const, uint32_t)
bool connected(PortEngine::PortHandle ph, bool process_callback_safe)
uint32_t systemic_output_latency() const
int set_output_device_name(const std::string &)
std::vector< uint32_t > available_buffer_sizes(const std::string &device) const
bool can_change_buffer_size_when_running() const
uint32_t buffer_size() const
void stop_listen_for_midi_device_changes()
void get_physical_inputs(DataType type, std::vector< std::string > &results)
int ensure_input_monitoring(PortHandle, bool)
std::vector< DeviceStatus > enumerate_midi_devices() const
void * private_handle() const
void set_latency_range(PortHandle, bool for_playback, LatencyRange)
void unregister_port(PortHandle ph)
int set_midi_device_enabled(std::string const, bool)
static void * alsa_process_thread(void *)
std::string device_name() const
std::string control_app_name() const
bool monitoring_input(PortHandle)
int connect(const std::string &src, const std::string &dst)
int register_system_midi_ports(const std::string device="")
std::vector< DeviceStatus > enumerate_devices() const
uint32_t systemic_midi_input_latency(std::string const) const
void midi_clear(void *port_buffer)
std::string input_device_name() const
static std::vector< AudioBackend::DeviceStatus > _duplex_audio_device_status
std::vector< float > available_sample_rates(const std::string &device) const
pthread_mutex_t _device_port_mutex
uint32_t process_thread_count()
std::vector< pthread_t > _threads
int set_midi_option(const std::string &)
int set_peridod_size(uint32_t)
bool can_change_sample_rate_when_running() const
int request_input_monitoring(PortHandle, bool)
int midi_event_get(pframes_t &timestamp, size_t &size, uint8_t const **buf, void *port_buffer, uint32_t event_index)
AlsaDeviceReservation _device_reservation
float sample_rate() const
int set_device_name(const std::string &)
std::vector< AudioSlave * > AudioSlaves
static std::vector< AudioBackend::DeviceStatus > _input_audio_device_status
samplepos_t sample_time()
struct AlsaMidiDeviceInfo * midi_device_info(std::string const) const
std::vector< uint32_t > available_period_sizes(const std::string &driver, const std::string &device) const
int set_port_name(PortEngine::PortHandle ph, const std::string &name)
size_t raw_buffer_size(DataType t)
uint32_t systemic_input_latency() const
int set_systemic_midi_output_latency(std::string const, uint32_t)
std::vector< DeviceStatus > enumerate_output_devices() const
int set_interleaved(bool yn)
static void * _midi_device_thread(void *arg)
static ARDOUR::ALSADeviceInfo _output_audio_device_info
bool port_is_physical(PortEngine::PortHandle ph) const
bool can_set_systemic_midi_latencies() const
std::vector< float > available_sample_rates2(const std::string &, const std::string &) const
bool match_input_output_devices_or_none() const
int get_port_property(PortEngine::PortHandle ph, const std::string &key, std::string &value, std::string &type) const
bool can_change_systemic_latency_when_running() const
static ARDOUR::ALSADeviceInfo _input_audio_device_info
std::vector< std::string > enumerate_midi_options() const
std::string name() const
bool midi_device_enabled(std::string const) const
static std::vector< std::string > _midi_options
void * get_buffer(PortHandle, pframes_t)
int get_connections(PortEngine::PortHandle ph, std::vector< std::string > &results, bool process_callback_safe)
PortEngine::PortPtr get_port_by_name(std::string const &name) const
static std::vector< AudioBackend::DeviceStatus > _midi_device_status
std::vector< AlsaMidiOut * > _rmidi_out
uint32_t port_name_size() const
std::string midi_option() const
std::vector< AlsaMidiIn * > _rmidi_in
int set_buffer_size(uint32_t)
bool can_monitor_input() const
bool connected_to(PortEngine::PortHandle ph, const std::string &other, bool process_callback_safe)
BackendPort * port_factory(std::string const &name, ARDOUR::DataType dt, ARDOUR::PortFlags flags)
int connect(PortEngine::PortHandle ph, const std::string &other)
int create_process_thread(std::function< void()> func)
bool can_measure_systemic_latency() const
bool physically_connected(PortEngine::PortHandle ph, bool process_callback_safe)
int set_systemic_output_latency(uint32_t)
int get_ports(const std::string &port_name_pattern, DataType type, PortFlags flags, std::vector< std::string > &results) const
static std::vector< AudioBackend::DeviceStatus > _output_audio_device_status
void get_physical_outputs(DataType type, std::vector< std::string > &results)
std::map< std::string, struct AlsaMidiDeviceInfo * > _midi_devices
PortFlags get_port_flags(PortEngine::PortHandle ph) const
PortEngine::PortPtr register_port(const std::string &shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags)
DataType port_data_type(PortEngine::PortHandle ph) const
int set_systemic_input_latency(uint32_t)
ChanCount n_physical_inputs() const
int disconnect_all(PortEngine::PortHandle ph)
bool add_slave(const char *slave_device, unsigned int slave_rate, unsigned int slave_spp, unsigned int slave_ppc, AudioSlave::DuplexMode)
int midi_event_put(void *port_buffer, pframes_t timestamp, const uint8_t *buffer, size_t size)
std::vector< DeviceStatus > enumerate_input_devices() const
std::string get_port_name(PortEngine::PortHandle ph) const
int disconnect(PortEngine::PortHandle ph, const std::string &other)
std::string output_device_name() const
samplepos_t sample_time_at_cycle_start()
void update_systemic_audio_latencies()
AlsaAudioBackend(AudioEngine &e, AudioBackendInfo &info)
bool use_separate_input_and_output_devices() const
int set_input_device_name(const std::string &)
const std::string & my_name() const
const Sample * const_buffer() const
AlsaAudioPort(AlsaAudioBackend &b, const std::string &, PortFlags)
void * get_buffer(pframes_t nframes)
DataType type() const
AlsaDeviceReservation(const char *device_name)
void reservation_stdout(std::string, size_t)
PBD::ScopedConnectionList _reservation_connection
bool acquire_device(const char *device_name, bool silent=false)
ARDOUR::SystemExec * _device_reservation
AlsaMidiEvent(const AlsaMidiEvent &other)
pframes_t timestamp() const
const uint8_t * data() const
AlsaMidiEvent(const pframes_t timestamp, const uint8_t *data, size_t size)
void * get_buffer(pframes_t nframes)
const AlsaMidiBuffer * const_buffer() const
AlsaMidiBuffer _buffer[3]
DataType type() const
AlsaMidiPort(AlsaAudioBackend &b, const std::string &, PortFlags)
AudioBackendInfo & info() const
int set_port_name(PortEngine::PortHandle, const std::string &)
uint32_t port_name_size() const
virtual void unregister_port(PortEngine::PortHandle)
bool physically_connected(PortEngine::PortHandle, bool process_callback_safe)
int disconnect(const std::string &src, const std::string &dst)
PortEngine::PortPtr get_port_by_name(const std::string &) const
int get_ports(const std::string &port_name_pattern, DataType type, PortFlags flags, std::vector< std::string > &) const
int connect(const std::string &src, const std::string &dst)
ChanCount n_physical_outputs() const
PortFlags get_port_flags(PortEngine::PortHandle) const
bool connected_to(PortEngine::PortHandle, const std::string &, bool process_callback_safe)
bool connected(PortEngine::PortHandle, bool process_callback_safe)
int get_connections(PortEngine::PortHandle, std::vector< std::string > &, bool process_callback_safe)
std::string get_port_name(PortEngine::PortHandle) const
ChanCount n_physical_inputs() const
void get_physical_outputs(DataType type, std::vector< std::string > &)
void get_physical_inputs(DataType type, std::vector< std::string > &)
DataType port_data_type(PortEngine::PortHandle) const
int disconnect_all(PortEngine::PortHandle)
bool port_is_physical(PortEngine::PortHandle) const
int get_port_property(PortEngine::PortHandle, const std::string &key, std::string &value, std::string &type) const
int set_port_property(PortEngine::PortHandle, const std::string &key, const std::string &value, const std::string &type)
PortEngine::PortPtr register_port(const std::string &shortname, ARDOUR::DataType, ARDOUR::PortFlags)
PortPtr const & PortHandle
Definition: port_engine.h:113
std::shared_ptr< ProtoPort > PortPtr
Definition: port_engine.h:107
uint32_t pframes_t
std::vector< AlsaMidiEvent > AlsaMidiBuffer
Temporal::samplecnt_t samplecnt_t
Temporal::samplepos_t samplepos_t
ThreadData(AlsaAudioBackend *e, std::function< void()> fp, size_t stacksz)