1 /* 2 * Copyright (C) 2015-2016 Tim Mayberry <mojofunk@gmail.com> 3 * Copyright (C) 2015-2018 Robin Gareus <robin@gareus.org> 4 * Copyright (C) 2017-2018 Paul Davis <paul@linuxaudiosystems.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #ifndef __libbackend_portaudio_backend_h__ 22 #define __libbackend_portaudio_backend_h__ 23 24 #include <string> 25 #include <vector> 26 #include <set> 27 28 #include <stdint.h> 29 #include <pthread.h> 30 31 #include <boost/shared_ptr.hpp> 32 33 #include "ardour/audio_backend.h" 34 #include "ardour/dsp_load_calculator.h" 35 #include "ardour/port_engine_shared.h" 36 #include "ardour/types.h" 37 38 #include "portaudio_io.h" 39 #include "winmmemidi_io.h" 40 #include "cycle_timer.h" 41 42 namespace ARDOUR { 43 44 class PortAudioBackend; 45 46 class PortMidiEvent { 47 public: 48 PortMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size); 49 PortMidiEvent (const PortMidiEvent& other); size()50 size_t size () const { return _size; }; timestamp()51 pframes_t timestamp () const { return _timestamp; }; data()52 const uint8_t* data () const { return _data; }; 53 bool operator< (const PortMidiEvent &other) const { return timestamp () < other.timestamp (); }; 54 private: 55 size_t _size; 56 pframes_t _timestamp; 57 uint8_t _data[MaxWinMidiEventSize]; 58 }; 59 60 typedef std::vector<PortMidiEvent> PortMidiBuffer; 61 62 class PortAudioPort : public BackendPort { 63 public: 64 PortAudioPort (PortAudioBackend &b, const std::string&, PortFlags); 65 ~PortAudioPort (); 66 type()67 DataType type () const { return DataType::AUDIO; }; 68 buffer()69 Sample* buffer () { return _buffer; } const_buffer()70 const Sample* const_buffer () const { return _buffer; } 71 void* get_buffer (pframes_t nframes); 72 73 private: 74 Sample _buffer[8192]; 75 }; // class PortAudioPort 76 77 class PortMidiPort : public BackendPort { 78 public: 79 PortMidiPort (PortAudioBackend &b, const std::string&, PortFlags); 80 ~PortMidiPort (); 81 type()82 DataType type () const { return DataType::MIDI; }; 83 84 void* get_buffer (pframes_t nframes); const_buffer()85 const PortMidiBuffer * const_buffer () const { return & _buffer[_bufperiod]; } 86 next_period()87 void next_period() { if (_n_periods > 1) { get_buffer(0); _bufperiod = (_bufperiod + 1) % _n_periods; } } set_n_periods(int n)88 void set_n_periods(int n) { if (n > 0 && n < 3) { _n_periods = n; } } 89 90 private: 91 PortMidiBuffer _buffer[2]; 92 int _n_periods; 93 int _bufperiod; 94 }; // class PortMidiPort 95 96 class PortAudioBackend : public AudioBackend, public PortEngineSharedImpl { 97 public: 98 PortAudioBackend (AudioEngine& e, AudioBackendInfo& info); 99 ~PortAudioBackend (); 100 101 /* AUDIOBACKEND API */ 102 103 std::string name () const; 104 bool is_realtime () const; 105 106 bool requires_driver_selection() const; 107 std::string driver_name () const; 108 std::vector<std::string> enumerate_drivers () const; 109 int set_driver (const std::string&); 110 can_request_update_devices()111 bool can_request_update_devices () { return true; } 112 bool update_devices (); 113 can_use_buffered_io()114 bool can_use_buffered_io () { return true; } 115 void set_use_buffered_io (bool); get_use_buffered_io()116 bool get_use_buffered_io () { return _use_blocking_api; } 117 118 bool use_separate_input_and_output_devices () const; 119 std::vector<DeviceStatus> enumerate_devices () const; 120 std::vector<DeviceStatus> enumerate_input_devices () const; 121 std::vector<DeviceStatus> enumerate_output_devices () const; 122 123 std::vector<float> available_sample_rates (const std::string& device) const; 124 std::vector<uint32_t> available_buffer_sizes (const std::string& device) const; 125 uint32_t available_input_channel_count (const std::string& device) const; 126 uint32_t available_output_channel_count (const std::string& device) const; 127 128 bool can_change_sample_rate_when_running () const; 129 bool can_change_buffer_size_when_running () const; 130 131 int set_device_name (const std::string&); 132 int set_input_device_name (const std::string&); 133 int set_output_device_name (const std::string&); 134 int set_sample_rate (float); 135 int set_buffer_size (uint32_t); 136 int set_interleaved (bool yn); 137 int set_input_channels (uint32_t); 138 int set_output_channels (uint32_t); 139 int set_systemic_input_latency (uint32_t); 140 int set_systemic_output_latency (uint32_t); 141 int set_systemic_midi_input_latency (std::string const, uint32_t); 142 int set_systemic_midi_output_latency (std::string const, uint32_t); 143 reset_device()144 int reset_device () { return 0; }; 145 146 /* Retrieving parameters */ 147 std::string device_name () const; 148 std::string input_device_name () const; 149 std::string output_device_name () const; 150 float sample_rate () const; 151 uint32_t buffer_size () const; 152 bool interleaved () const; 153 uint32_t input_channels () const; 154 uint32_t output_channels () const; 155 uint32_t systemic_input_latency () const; 156 uint32_t systemic_output_latency () const; 157 uint32_t systemic_midi_input_latency (std::string const) const; 158 uint32_t systemic_midi_output_latency (std::string const) const; 159 can_measure_systemic_latency()160 bool can_measure_systemic_latency () const { return true; } can_set_systemic_midi_latencies()161 bool can_set_systemic_midi_latencies () const { return true; } 162 163 /* External control app */ 164 std::string control_app_name () const; 165 void launch_control_app (); 166 167 /* MIDI */ 168 std::vector<std::string> enumerate_midi_options () const; 169 int set_midi_option (const std::string&); 170 std::string midi_option () const; 171 172 std::vector<DeviceStatus> enumerate_midi_devices () const; 173 int set_midi_device_enabled (std::string const, bool); 174 bool midi_device_enabled (std::string const) const; 175 176 protected: 177 /* State Control */ 178 int _start (bool for_latency_measurement); 179 public: 180 int stop (); 181 int freewheel (bool); 182 float dsp_load () const; 183 size_t raw_buffer_size (DataType t); 184 185 /* Process time */ 186 samplepos_t sample_time (); 187 samplepos_t sample_time_at_cycle_start (); 188 pframes_t samples_since_cycle_start (); 189 190 int create_process_thread (boost::function<void()> func); 191 int join_process_threads (); 192 bool in_process_thread (); 193 uint32_t process_thread_count (); 194 195 void update_latencies (); 196 197 /* PORTENGINE API */ 198 199 void* private_handle () const; 200 const std::string& my_name () const; 201 202 203 /* PortEngine API - forwarded to PortEngineSharedImpl */ 204 port_is_physical(PortEngine::PortHandle ph)205 bool port_is_physical (PortEngine::PortHandle ph) const { return PortEngineSharedImpl::port_is_physical (ph); } get_physical_outputs(DataType type,std::vector<std::string> & results)206 void get_physical_outputs (DataType type, std::vector<std::string>& results) { PortEngineSharedImpl::get_physical_outputs (type, results); } get_physical_inputs(DataType type,std::vector<std::string> & results)207 void get_physical_inputs (DataType type, std::vector<std::string>& results) { PortEngineSharedImpl::get_physical_inputs (type, results); } n_physical_outputs()208 ChanCount n_physical_outputs () const { return PortEngineSharedImpl::n_physical_outputs (); } n_physical_inputs()209 ChanCount n_physical_inputs () const { return PortEngineSharedImpl::n_physical_inputs (); } port_name_size()210 uint32_t port_name_size () const { return PortEngineSharedImpl::port_name_size(); } set_port_name(PortEngine::PortHandle ph,const std::string & name)211 int set_port_name (PortEngine::PortHandle ph, const std::string& name) { return PortEngineSharedImpl::set_port_name (ph, name); } get_port_name(PortEngine::PortHandle ph)212 std::string get_port_name (PortEngine::PortHandle ph) const { return PortEngineSharedImpl::get_port_name (ph); } get_port_flags(PortEngine::PortHandle ph)213 PortFlags get_port_flags (PortEngine::PortHandle ph) const { return PortEngineSharedImpl::get_port_flags (ph); } get_port_by_name(std::string const & name)214 PortEngine::PortPtr get_port_by_name (std::string const & name) const { return PortEngineSharedImpl::get_port_by_name (name); } get_port_property(PortEngine::PortHandle ph,const std::string & key,std::string & value,std::string & type)215 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); } set_port_property(PortEngine::PortHandle ph,const std::string & key,const std::string & value,const std::string & type)216 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); } get_ports(const std::string & port_name_pattern,DataType type,PortFlags flags,std::vector<std::string> & results)217 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); } port_data_type(PortEngine::PortHandle ph)218 DataType port_data_type (PortEngine::PortHandle ph) const { return PortEngineSharedImpl::port_data_type (ph); } register_port(const std::string & shortname,ARDOUR::DataType type,ARDOUR::PortFlags flags)219 PortEngine::PortPtr register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags) { return PortEngineSharedImpl::register_port (shortname, type, flags); } unregister_port(PortHandle ph)220 void unregister_port (PortHandle ph) { if (!_run) return; PortEngineSharedImpl::unregister_port (ph); } connect(const std::string & src,const std::string & dst)221 int connect (const std::string& src, const std::string& dst) { return PortEngineSharedImpl::connect (src, dst); } disconnect(const std::string & src,const std::string & dst)222 int disconnect (const std::string& src, const std::string& dst) { return PortEngineSharedImpl::disconnect (src, dst); } connect(PortEngine::PortHandle ph,const std::string & other)223 int connect (PortEngine::PortHandle ph, const std::string& other) { return PortEngineSharedImpl::connect (ph, other); } disconnect(PortEngine::PortHandle ph,const std::string & other)224 int disconnect (PortEngine::PortHandle ph, const std::string& other) { return PortEngineSharedImpl::disconnect (ph, other); } disconnect_all(PortEngine::PortHandle ph)225 int disconnect_all (PortEngine::PortHandle ph) { return PortEngineSharedImpl::disconnect_all (ph); } connected(PortEngine::PortHandle ph,bool process_callback_safe)226 bool connected (PortEngine::PortHandle ph, bool process_callback_safe) { return PortEngineSharedImpl::connected (ph, process_callback_safe); } connected_to(PortEngine::PortHandle ph,const std::string & other,bool process_callback_safe)227 bool connected_to (PortEngine::PortHandle ph, const std::string& other, bool process_callback_safe) { return PortEngineSharedImpl::connected_to (ph, other, process_callback_safe); } physically_connected(PortEngine::PortHandle ph,bool process_callback_safe)228 bool physically_connected (PortEngine::PortHandle ph, bool process_callback_safe) { return PortEngineSharedImpl::physically_connected (ph, process_callback_safe); } get_connections(PortEngine::PortHandle ph,std::vector<std::string> & results,bool process_callback_safe)229 int get_connections (PortEngine::PortHandle ph, std::vector<std::string>& results, bool process_callback_safe) { return PortEngineSharedImpl::get_connections (ph, results, process_callback_safe); } 230 231 /* MIDI */ 232 int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t const** buf, void* port_buffer, uint32_t event_index); 233 int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size); 234 uint32_t get_midi_event_count (void* port_buffer); 235 void midi_clear (void* port_buffer); 236 237 /* Monitoring */ 238 239 bool can_monitor_input () const; 240 int request_input_monitoring (PortHandle, bool); 241 int ensure_input_monitoring (PortHandle, bool); 242 bool monitoring_input (PortHandle); 243 244 /* Latency management */ 245 246 void set_latency_range (PortHandle, bool for_playback, LatencyRange); 247 LatencyRange get_latency_range (PortHandle, bool for_playback); 248 249 /* Getting access to the data buffer for a port */ 250 251 void* get_buffer (PortHandle, pframes_t); 252 253 void* blocking_process_thread (); 254 255 void* freewheel_process_thread (); 256 257 private: // Methods 258 bool start_blocking_process_thread (); 259 bool stop_blocking_process_thread (); 260 bool blocking_process_freewheel (); 261 bool blocking_process_main (const float* interleaved_input_data, 262 float* interleaved_output_data); 263 264 void process_port_connection_changes (); 265 void process_incoming_midi (); 266 void process_outgoing_midi (); 267 268 bool engine_halted (); 269 bool running (); 270 271 static int portaudio_callback(const void* input, 272 void* output, 273 unsigned long frameCount, 274 const PaStreamCallbackTimeInfo* timeInfo, 275 PaStreamCallbackFlags statusFlags, 276 void* userData); 277 278 bool process_callback(const float* input, 279 float* output, 280 uint32_t sample_count, 281 const PaStreamCallbackTimeInfo* timeInfo, 282 PaStreamCallbackFlags statusFlags); 283 284 bool start_freewheel_process_thread (); 285 bool stop_freewheel_process_thread (); 286 287 static bool set_mmcss_pro_audio (HANDLE* task_handle); 288 static bool reset_mmcss (HANDLE task_handle); 289 290 private: 291 std::string _instance_name; 292 PortAudioIO *_pcmio; 293 WinMMEMidiIO *_midiio; 294 295 bool _run; /* keep going or stop, ardour thread */ 296 bool _active; /* is running, process thread */ 297 bool _use_blocking_api; 298 bool _freewheel; 299 bool _freewheeling; 300 bool _freewheel_ack; 301 bool _reinit_thread_callback; 302 bool _measure_latency; 303 304 ARDOUR::DSPLoadCalculator _dsp_calc; 305 306 bool _freewheel_thread_active; 307 308 pthread_mutex_t _freewheel_mutex; 309 pthread_cond_t _freewheel_signal; 310 311 uint64_t _cycle_count; 312 uint64_t _total_deviation_us; 313 uint64_t _max_deviation_us; 314 315 CycleTimer _cycle_timer; 316 uint64_t _last_cycle_start; 317 318 static std::vector<std::string> _midi_options; 319 static std::vector<AudioBackend::DeviceStatus> _input_audio_device_status; 320 static std::vector<AudioBackend::DeviceStatus> _output_audio_device_status; 321 static std::vector<AudioBackend::DeviceStatus> _midi_device_status; 322 323 mutable std::string _input_audio_device; 324 mutable std::string _output_audio_device; 325 std::string _midi_driver_option; 326 327 /* audio settings */ 328 float _samplerate; 329 size_t _samples_per_period; 330 static size_t _max_buffer_size; 331 332 uint32_t _n_inputs; 333 uint32_t _n_outputs; 334 335 uint32_t _systemic_audio_input_latency; 336 uint32_t _systemic_audio_output_latency; 337 338 MidiDeviceInfo* midi_device_info(const std::string&) const; 339 340 /* portaudio specific */ 341 int name_to_id(std::string) const; 342 343 /* processing */ 344 float _dsp_load; 345 samplecnt_t _processed_samples; 346 347 /* blocking thread */ 348 pthread_t _main_blocking_thread; 349 350 /* main thread in callback mode(or fw thread when running) */ 351 pthread_t _main_thread; 352 353 /* freewheel thread in callback mode */ 354 pthread_t _pthread_freewheel; 355 356 /* process threads */ 357 static void* portaudio_process_thread (void *); 358 std::vector<pthread_t> _threads; 359 360 struct ThreadData { 361 PortAudioBackend* engine; 362 boost::function<void ()> f; 363 size_t stacksize; 364 ThreadDataThreadData365 ThreadData (PortAudioBackend* e, boost::function<void ()> fp, size_t stacksz) 366 : engine (e) , f (fp) , stacksize (stacksz) {} 367 }; 368 369 /* port engine */ 370 BackendPort* port_factory (std::string const & name, ARDOUR::DataType dt, ARDOUR::PortFlags flags); 371 372 int register_system_audio_ports (); 373 int register_system_midi_ports (); 374 375 }; // class PortAudioBackend 376 377 } // namespace 378 379 #endif /* __libbackend_portaudio_backend_h__ */ 380