Ardour  9.0-pre0-582-g084a23a80d
pulseaudio_backend.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2019 Robin Gareus <robin@gareus.org>
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 along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #ifndef __libbackend_pulse_audiobackend_h__
20 #define __libbackend_pulse_audiobackend_h__
21 
22 #include <cstdint>
23 #include <map>
24 #include <memory>
25 #include <set>
26 #include <string>
27 #include <vector>
28 
29 #include <pthread.h>
30 
31 #include <pulse/pulseaudio.h>
32 
33 #include "pbd/natsort.h"
34 
35 #include "ardour/audio_backend.h"
38 
39 #define MaxPulseMidiEventSize (256)
40 
41 namespace ARDOUR {
42 
43 class PulseAudioBackend;
44 
46 {
47 public:
48  PulseMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size);
50 
51  size_t size () const { return _size; };
52  pframes_t timestamp () const { return _timestamp; };
53  const uint8_t* data () const { return _data; };
54  const uint8_t* const_data () const { return _data; };
55 
56 private:
57  size_t _size;
60 };
61 
62 typedef std::vector<std::shared_ptr<PulseMidiEvent> > PulseMidiBuffer;
63 
64 
66 {
67 public:
68  PulseAudioPort (PulseAudioBackend& b, const std::string&, PortFlags);
70 
71  DataType type () const { return DataType::AUDIO; };
72 
73  Sample* buffer () { return _buffer; }
74  const Sample* const_buffer () const { return _buffer; }
75  void* get_buffer (pframes_t nframes);
76 
77 private:
78  Sample _buffer[8192];
79 }; // class PulseAudioPort
80 
81 class PulseMidiPort : public BackendPort
82 {
83 public:
84  PulseMidiPort (PulseAudioBackend& b, const std::string&, PortFlags);
86 
87  DataType type () const { return DataType::MIDI; };
88 
89  void* get_buffer (pframes_t nframes);
90  const PulseMidiBuffer* const_buffer () const { return &_buffer; }
91 
92 private:
94 }; // class PulseMidiPort
95 
97 {
98 public:
101 
102  /* AUDIOBACKEND API */
103 
104  std::string name () const;
105  bool is_realtime () const;
106 
107  std::vector<DeviceStatus> enumerate_devices () const;
108  std::vector<float> available_sample_rates (const std::string& device) const;
109  std::vector<uint32_t> available_buffer_sizes (const std::string& device) const;
110 
113  bool can_measure_systemic_latency () const { return false; }
114 
115  int set_device_name (const std::string&);
116  int set_sample_rate (float);
117  int set_buffer_size (uint32_t);
118  int set_interleaved (bool yn);
121 
122  int set_systemic_midi_input_latency (std::string const, uint32_t) { return 0; }
123  int set_systemic_midi_output_latency (std::string const, uint32_t) { return 0; }
124 
125  int reset_device () { return 0; };
126 
127  /* Retrieving parameters */
128  std::string device_name () const;
129  float sample_rate () const;
130  uint32_t buffer_size () const;
131  bool interleaved () const;
132  uint32_t systemic_input_latency () const;
133  uint32_t systemic_output_latency () const;
134  uint32_t systemic_midi_input_latency (std::string const) const { return 0; }
135  uint32_t systemic_midi_output_latency (std::string const) const { return 0; }
136 
137  /* External control app */
138  std::string control_app_name () const;
140 
141  /* MIDI */
142  std::vector<std::string> enumerate_midi_options () const;
143  std::vector<DeviceStatus> enumerate_midi_devices () const;
144  int set_midi_option (const std::string&);
145  std::string midi_option () const;
146 
147  int set_midi_device_enabled (std::string const, bool) { return 0; }
148  bool midi_device_enabled (std::string const) const { return true; }
149  bool can_set_systemic_midi_latencies () const { return false; }
150 
151  /* State Control */
152 protected:
153  int _start (bool for_latency_measurement);
154 
155 public:
156  int stop ();
157  int freewheel (bool);
158  float dsp_load () const;
160 
161  /* Process time */
165 
166  int create_process_thread (std::function<void()> func);
169  uint32_t process_thread_count ();
170 
172 
173  /* PORTENGINE API */
174 
175  void* private_handle () const;
176  const std::string& my_name () const;
177 
178  /* PortEngine API - forwarded to PortEngineSharedImpl */
179 
181  void get_physical_outputs (DataType type, std::vector<std::string>& results) { PortEngineSharedImpl::get_physical_outputs (type, results); }
182  void get_physical_inputs (DataType type, std::vector<std::string>& results) { PortEngineSharedImpl::get_physical_inputs (type, results); }
185  uint32_t port_name_size () const { return PortEngineSharedImpl::port_name_size(); }
190  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); }
191  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); }
192  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); }
194  PortEngine::PortPtr register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags) { return PortEngineSharedImpl::register_port (shortname, type, flags); }
196  int connect (const std::string& src, const std::string& dst) { return PortEngineSharedImpl::connect (src, dst); }
197  int disconnect (const std::string& src, const std::string& dst) { return PortEngineSharedImpl::disconnect (src, dst); }
198  int connect (PortEngine::PortHandle ph, const std::string& other) { return PortEngineSharedImpl::connect (ph, other); }
199  int disconnect (PortEngine::PortHandle ph, const std::string& other) { return PortEngineSharedImpl::disconnect (ph, other); }
201  bool connected (PortEngine::PortHandle ph, bool process_callback_safe) { return PortEngineSharedImpl::connected (ph, process_callback_safe); }
202  bool connected_to (PortEngine::PortHandle ph, const std::string& other, bool process_callback_safe) { return PortEngineSharedImpl::connected_to (ph, other, process_callback_safe); }
203  bool physically_connected (PortEngine::PortHandle ph, bool process_callback_safe) { return PortEngineSharedImpl::physically_connected (ph, process_callback_safe); }
204  int get_connections (PortEngine::PortHandle ph, std::vector<std::string>& results, bool process_callback_safe) { return PortEngineSharedImpl::get_connections (ph, results, process_callback_safe); }
205 
206  /* MIDI */
207  int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t const** buf, void* port_buffer, uint32_t event_index);
208  int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size);
209  uint32_t get_midi_event_count (void* port_buffer);
210  void midi_clear (void* port_buffer);
211 
212  /* Monitoring */
213 
214  bool can_monitor_input () const;
218 
219  /* Latency management */
220 
221  void set_latency_range (PortHandle, bool for_playback, LatencyRange);
223 
224  /* Getting access to the data buffer for a port */
225 
227 
229 
230 private:
231  std::string _instance_name;
232 
233  /* pulse */
234  struct pa_stream* p_stream;
235  struct pa_context* p_context;
236  struct pa_threaded_mainloop* p_mainloop;
237 
238  int init_pulse ();
239  void close_pulse (bool unlock = false);
240  int sync_pulse (pa_operation*);
241  bool cork_pulse (bool);
242 
243  static void context_state_cb (pa_context*, void*);
244  static void stream_state_cb (pa_stream*, void*);
245  static void stream_request_cb (pa_stream*, size_t, void*);
246  static void stream_latency_update_cb (pa_stream*, void*);
247  static void stream_xrun_cb (pa_stream*, void*);
248  static void stream_operation_cb (pa_stream*, int, void*);
249 
251 
252  bool _run; /* keep going or stop, ardour thread */
253  bool _active; /* is running, process thread */
256 
258 
259  /* audio settings */
260  float _samplerate;
263 
264  static const size_t _max_buffer_size;
265 
266  /* processing */
267  float _dsp_load;
270  pthread_t _main_thread;
271 
272  /* process threads */
273  static void* pulse_process_thread (void*);
274  std::vector<pthread_t> _threads;
275 
276  struct ThreadData {
278  std::function<void()> f;
279  size_t stacksize;
280 
281  ThreadData (PulseAudioBackend* e, std::function<void()> fp, size_t stacksz)
282  : engine (e), f (fp), stacksize (stacksz) {}
283  };
284 
285  /* port engine */
288 
289 }; // class PulseAudioBackend
290 
291 } // namespace
292 
293 #endif /* __libbackend_pulse_audiobackend_h__ */
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
int connect(PortEngine::PortHandle ph, const std::string &other)
struct pa_context * p_context
void set_latency_range(PortHandle, bool for_playback, LatencyRange)
uint32_t systemic_output_latency() const
void get_physical_outputs(DataType type, std::vector< std::string > &results)
bool can_change_buffer_size_when_running() const
PortFlags get_port_flags(PortEngine::PortHandle ph) const
std::string control_app_name() const
std::vector< DeviceStatus > enumerate_midi_devices() const
static void stream_operation_cb(pa_stream *, int, void *)
std::vector< pthread_t > _threads
uint32_t systemic_midi_output_latency(std::string const) const
uint32_t get_midi_event_count(void *port_buffer)
static void context_state_cb(pa_context *, void *)
int set_device_name(const std::string &)
ChanCount n_physical_outputs() const
std::string get_port_name(PortEngine::PortHandle ph) const
bool monitoring_input(PortHandle)
int disconnect(PortEngine::PortHandle ph, const std::string &other)
bool physically_connected(PortEngine::PortHandle ph, bool process_callback_safe)
uint32_t systemic_input_latency() const
void * private_handle() const
int disconnect(const std::string &src, const std::string &dst)
PortEngine::PortPtr get_port_by_name(std::string const &name) const
int create_process_thread(std::function< void()> func)
bool can_change_sample_rate_when_running() const
DataType port_data_type(PortEngine::PortHandle ph) const
int get_ports(const std::string &port_name_pattern, DataType type, PortFlags flags, std::vector< std::string > &results) const
int set_midi_device_enabled(std::string const, bool)
int set_buffer_size(uint32_t)
std::string device_name() const
PortEngine::PortPtr register_port(const std::string &shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags)
static void * pulse_process_thread(void *)
static void stream_xrun_cb(pa_stream *, void *)
samplepos_t sample_time_at_cycle_start()
bool connected(PortEngine::PortHandle ph, bool process_callback_safe)
std::string name() const
LatencyRange get_latency_range(PortHandle, bool for_playback)
int disconnect_all(PortEngine::PortHandle ph)
static void stream_request_cb(pa_stream *, size_t, void *)
int ensure_input_monitoring(PortHandle, bool)
std::vector< DeviceStatus > enumerate_devices() const
size_t raw_buffer_size(DataType t)
int midi_event_get(pframes_t &timestamp, size_t &size, uint8_t const **buf, void *port_buffer, uint32_t event_index)
bool can_measure_systemic_latency() const
void get_physical_inputs(DataType type, std::vector< std::string > &results)
BackendPort * port_factory(std::string const &name, ARDOUR::DataType dt, ARDOUR::PortFlags flags)
uint32_t buffer_size() const
std::string midi_option() const
int set_interleaved(bool yn)
int set_systemic_midi_output_latency(std::string const, uint32_t)
bool can_monitor_input() const
ChanCount n_physical_inputs() const
int request_input_monitoring(PortHandle, bool)
int _start(bool for_latency_measurement)
int set_port_name(PortEngine::PortHandle ph, const std::string &name)
struct pa_threaded_mainloop * p_mainloop
int set_systemic_output_latency(uint32_t)
bool port_is_physical(PortEngine::PortHandle ph) const
static void stream_latency_update_cb(pa_stream *, void *)
int set_systemic_midi_input_latency(std::string const, uint32_t)
static void stream_state_cb(pa_stream *, void *)
bool connected_to(PortEngine::PortHandle ph, const std::string &other, bool process_callback_safe)
int midi_event_put(void *port_buffer, pframes_t timestamp, const uint8_t *buffer, size_t size)
std::vector< uint32_t > available_buffer_sizes(const std::string &device) const
bool midi_device_enabled(std::string const) const
int set_port_property(PortEngine::PortHandle ph, const std::string &key, const std::string &value, const std::string &type)
PulseAudioBackend(AudioEngine &e, AudioBackendInfo &info)
std::vector< std::string > enumerate_midi_options() const
int get_port_property(PortEngine::PortHandle ph, const std::string &key, std::string &value, std::string &type) const
void midi_clear(void *port_buffer)
void unregister_port(PortHandle ph)
int sync_pulse(pa_operation *)
uint32_t systemic_midi_input_latency(std::string const) const
pframes_t samples_since_cycle_start()
int connect(const std::string &src, const std::string &dst)
std::vector< float > available_sample_rates(const std::string &device) const
void close_pulse(bool unlock=false)
ARDOUR::DSPLoadCalculator _dsp_load_calc
bool can_set_systemic_midi_latencies() const
static const size_t _max_buffer_size
int set_midi_option(const std::string &)
int get_connections(PortEngine::PortHandle ph, std::vector< std::string > &results, bool process_callback_safe)
void * get_buffer(PortHandle, pframes_t)
int set_systemic_input_latency(uint32_t)
const std::string & my_name() const
const Sample * const_buffer() const
void * get_buffer(pframes_t nframes)
PulseAudioPort(PulseAudioBackend &b, const std::string &, PortFlags)
const uint8_t * const_data() const
pframes_t timestamp() const
const uint8_t * data() const
PulseMidiEvent(const PulseMidiEvent &other)
PulseMidiEvent(const pframes_t timestamp, const uint8_t *data, size_t size)
void * get_buffer(pframes_t nframes)
PulseMidiPort(PulseAudioBackend &b, const std::string &, PortFlags)
const PulseMidiBuffer * const_buffer() const
uint32_t pframes_t
Temporal::samplecnt_t samplecnt_t
std::vector< std::shared_ptr< PulseMidiEvent > > PulseMidiBuffer
Temporal::samplepos_t samplepos_t
#define MaxPulseMidiEventSize
ThreadData(PulseAudioBackend *e, std::function< void()> fp, size_t stacksz)