1 /* 2 * Copyright (C) 2015-2018 Robin Gareus <robin@gareus.org> 3 * Copyright (C) 2016-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_coreaudio_backend_h__ 21 #define __libbackend_coreaudio_backend_h__ 22 23 #include <string> 24 #include <vector> 25 #include <map> 26 #include <set> 27 28 #include <stdint.h> 29 #include <pthread.h> 30 31 #include <boost/shared_ptr.hpp> 32 33 #include "pbd/natsort.h" 34 #include "ardour/audio_backend.h" 35 #include "ardour/dsp_load_calculator.h" 36 #include "ardour/port_engine_shared.h" 37 #include "ardour/types.h" 38 39 #include "coreaudio_pcmio.h" 40 #include "coremidi_io.h" 41 42 #define MaxCoreMidiEventSize 256 // matches CoreMidi's MIDIPacket (https://developer.apple.com/documentation/coremidi/midipacket) 43 44 namespace ARDOUR { 45 46 class CoreAudioBackend; 47 48 class CoreMidiEvent { 49 public: 50 CoreMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size); 51 CoreMidiEvent (const CoreMidiEvent& other); size()52 size_t size () const { return _size; }; timestamp()53 pframes_t timestamp () const { return _timestamp; }; data()54 const uint8_t* data () const { return _data; }; 55 bool operator< (const CoreMidiEvent &other) const { return timestamp () < other.timestamp (); }; 56 private: 57 size_t _size; 58 pframes_t _timestamp; 59 uint8_t _data[MaxCoreMidiEventSize]; 60 }; 61 62 typedef std::vector<CoreMidiEvent> CoreMidiBuffer; 63 64 class CoreAudioPort : public BackendPort { 65 public: 66 CoreAudioPort (CoreAudioBackend &b, const std::string&, PortFlags); 67 ~CoreAudioPort (); 68 type()69 DataType type () const { return DataType::AUDIO; }; 70 buffer()71 Sample* buffer () { return _buffer; } const_buffer()72 const Sample* const_buffer () const { return _buffer; } 73 void* get_buffer (pframes_t nframes); 74 75 private: 76 Sample _buffer[8192]; 77 }; // class CoreAudioPort 78 79 class CoreMidiPort : public BackendPort { 80 public: 81 CoreMidiPort (CoreAudioBackend &b, const std::string&, PortFlags); 82 ~CoreMidiPort (); 83 type()84 DataType type () const { return DataType::MIDI; }; 85 86 void* get_buffer (pframes_t nframes); const_buffer()87 const CoreMidiBuffer * const_buffer () const { return & _buffer[_bufperiod]; } 88 next_period()89 void next_period() { if (_n_periods > 1) { get_buffer(0); _bufperiod = (_bufperiod + 1) % _n_periods; } } set_n_periods(int n)90 void set_n_periods(int n) { if (n > 0 && n < 3) { _n_periods = n; } } 91 92 void parse_events (const uint64_t time, const uint8_t *data, const size_t size); 93 void clear_events (); 94 void reset_parser (); 95 96 private: 97 CoreMidiBuffer _buffer[2]; 98 int _n_periods; 99 int _bufperiod; 100 101 int queue_event (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size); 102 bool process_byte (const uint64_t, const uint8_t); 103 record_byte(uint8_t byte)104 void record_byte(uint8_t byte) { 105 if (_total_bytes < sizeof(_parser_buffer)) { 106 _parser_buffer[_total_bytes] = byte; 107 } else { 108 ++_unbuffered_bytes; 109 } 110 ++_total_bytes; 111 } 112 prepare_byte_event(const uint64_t time,const uint8_t byte)113 void prepare_byte_event(const uint64_t time, const uint8_t byte) { 114 _parser_buffer[0] = byte; 115 _event.prepare(time, 1); 116 } 117 prepare_buffered_event(const uint64_t time)118 bool prepare_buffered_event(const uint64_t time) { 119 const bool result = _unbuffered_bytes == 0; 120 if (result) { 121 _event.prepare(time, _total_bytes); 122 } 123 _total_bytes = 0; 124 _unbuffered_bytes = 0; 125 if (_status_byte >= 0xf0) { 126 _expected_bytes = 0; 127 _status_byte = 0; 128 } 129 return result; 130 } 131 132 struct ParserEvent { 133 uint64_t _time; 134 size_t _size; 135 bool _pending; ParserEventParserEvent136 ParserEvent (const uint64_t time, const size_t size) 137 : _time(time) 138 , _size(size) 139 , _pending(false) {} 140 prepareParserEvent141 void prepare(const uint64_t time, const size_t size) { 142 _time = time; 143 _size = size; 144 _pending = true; 145 } 146 } _event; 147 148 bool _first_time; 149 size_t _unbuffered_bytes; 150 size_t _total_bytes; 151 size_t _expected_bytes; 152 uint8_t _status_byte; 153 uint8_t _parser_buffer[1024]; 154 155 }; // class CoreMidiPort 156 157 class CoreAudioBackend : public AudioBackend, public PortEngineSharedImpl { 158 public: 159 CoreAudioBackend (AudioEngine& e, AudioBackendInfo& info); 160 ~CoreAudioBackend (); 161 162 /* AUDIOBACKEND API */ 163 164 std::string name () const; 165 bool is_realtime () const; 166 use_separate_input_and_output_devices()167 bool use_separate_input_and_output_devices () const { return true; } 168 std::vector<DeviceStatus> enumerate_devices () const; 169 std::vector<DeviceStatus> enumerate_input_devices () const; 170 std::vector<DeviceStatus> enumerate_output_devices () const; 171 172 std::vector<float> available_sample_rates (const std::string& device) const; 173 std::vector<float> available_sample_rates2 (const std::string&, const std::string&) const; 174 std::vector<uint32_t> available_buffer_sizes (const std::string& device) const; 175 std::vector<uint32_t> available_buffer_sizes2 (const std::string&, const std::string&) const; 176 uint32_t available_input_channel_count (const std::string& device) const; 177 uint32_t available_output_channel_count (const std::string& device) const; 178 179 bool can_change_sample_rate_when_running () const; 180 bool can_change_buffer_size_when_running () const; can_measure_systemic_latency()181 bool can_measure_systemic_latency () const { return true; } 182 183 int set_device_name (const std::string&); 184 int set_input_device_name (const std::string&); 185 int set_output_device_name (const std::string&); 186 int set_sample_rate (float); 187 int set_buffer_size (uint32_t); 188 int set_interleaved (bool yn); 189 int set_input_channels (uint32_t); 190 int set_output_channels (uint32_t); 191 int set_systemic_input_latency (uint32_t); 192 int set_systemic_output_latency (uint32_t); set_systemic_midi_input_latency(std::string const,uint32_t)193 int set_systemic_midi_input_latency (std::string const, uint32_t) { return 0; } set_systemic_midi_output_latency(std::string const,uint32_t)194 int set_systemic_midi_output_latency (std::string const, uint32_t) { return 0; } 195 reset_device()196 int reset_device () { return 0; }; 197 198 /* Retrieving parameters */ 199 std::string device_name () const; 200 std::string input_device_name () const; 201 std::string output_device_name () const; 202 float sample_rate () const; 203 uint32_t buffer_size () const; 204 bool interleaved () const; 205 uint32_t input_channels () const; 206 uint32_t output_channels () const; 207 uint32_t systemic_input_latency () const; 208 uint32_t systemic_output_latency () const; systemic_midi_input_latency(std::string const)209 uint32_t systemic_midi_input_latency (std::string const) const { return 0; } systemic_midi_output_latency(std::string const)210 uint32_t systemic_midi_output_latency (std::string const) const { return 0; } 211 212 uint32_t systemic_hw_input_latency () const; 213 uint32_t systemic_hw_output_latency () const; 214 can_set_systemic_midi_latencies()215 bool can_set_systemic_midi_latencies () const { return false; /* XXX */} 216 217 /* External control app */ control_app_name()218 std::string control_app_name () const { return std::string ("Apple"); } 219 void launch_control_app (); 220 221 /* MIDI */ 222 std::vector<std::string> enumerate_midi_options () const; 223 int set_midi_option (const std::string&); 224 std::string midi_option () const; 225 enumerate_midi_devices()226 std::vector<DeviceStatus> enumerate_midi_devices () const { 227 return std::vector<AudioBackend::DeviceStatus> (); 228 } set_midi_device_enabled(std::string const,bool)229 int set_midi_device_enabled (std::string const, bool) { 230 return true; 231 } midi_device_enabled(std::string const)232 bool midi_device_enabled (std::string const) const { 233 return false; 234 } 235 236 // really private, but needing static access: 237 int process_callback(uint32_t, uint64_t); 238 void error_callback(); 239 void xrun_callback(); 240 void buffer_size_callback(); 241 void sample_rate_callback(); 242 void hw_changed_callback(); 243 244 protected: 245 /* State Control */ 246 int _start (bool for_latency_measurement); 247 public: 248 int stop (); 249 int freewheel (bool); 250 float dsp_load () const; 251 size_t raw_buffer_size (DataType t); 252 253 /* Process time */ 254 samplepos_t sample_time (); 255 samplepos_t sample_time_at_cycle_start (); 256 pframes_t samples_since_cycle_start (); 257 258 int create_process_thread (boost::function<void()> func); 259 int join_process_threads (); 260 bool in_process_thread (); 261 uint32_t process_thread_count (); 262 263 void update_latencies (); 264 265 /* PORTENGINE API */ 266 267 void* private_handle () const; 268 const std::string& my_name () const; 269 270 /* PortEngine API - forwarded to PortEngineSharedImpl */ 271 port_is_physical(PortEngine::PortHandle ph)272 bool port_is_physical (PortEngine::PortHandle ph) const { return PortEngineSharedImpl::port_is_physical (ph); } get_physical_outputs(DataType type,std::vector<std::string> & results)273 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)274 void get_physical_inputs (DataType type, std::vector<std::string>& results) { PortEngineSharedImpl::get_physical_inputs (type, results); } n_physical_outputs()275 ChanCount n_physical_outputs () const { return PortEngineSharedImpl::n_physical_outputs (); } n_physical_inputs()276 ChanCount n_physical_inputs () const { return PortEngineSharedImpl::n_physical_inputs (); } port_name_size()277 uint32_t port_name_size () const { return PortEngineSharedImpl::port_name_size(); } set_port_name(PortEngine::PortHandle ph,const std::string & name)278 int set_port_name (PortEngine::PortHandle ph, const std::string& name) { return PortEngineSharedImpl::set_port_name (ph, name); } get_port_name(PortEngine::PortHandle ph)279 std::string get_port_name (PortEngine::PortHandle ph) const { return PortEngineSharedImpl::get_port_name (ph); } get_port_flags(PortEngine::PortHandle ph)280 PortFlags get_port_flags (PortEngine::PortHandle ph) const { return PortEngineSharedImpl::get_port_flags (ph); } get_port_by_name(std::string const & name)281 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)282 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)283 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)284 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)285 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)286 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)287 void unregister_port (PortHandle ph) { if (!_run) return; PortEngineSharedImpl::unregister_port (ph); } connect(const std::string & src,const std::string & dst)288 int connect (const std::string& src, const std::string& dst) { return PortEngineSharedImpl::connect (src, dst); } disconnect(const std::string & src,const std::string & dst)289 int disconnect (const std::string& src, const std::string& dst) { return PortEngineSharedImpl::disconnect (src, dst); } connect(PortEngine::PortHandle ph,const std::string & other)290 int connect (PortEngine::PortHandle ph, const std::string& other) { return PortEngineSharedImpl::connect (ph, other); } disconnect(PortEngine::PortHandle ph,const std::string & other)291 int disconnect (PortEngine::PortHandle ph, const std::string& other) { return PortEngineSharedImpl::disconnect (ph, other); } disconnect_all(PortEngine::PortHandle ph)292 int disconnect_all (PortEngine::PortHandle ph) { return PortEngineSharedImpl::disconnect_all (ph); } connected(PortEngine::PortHandle ph,bool process_callback_safe)293 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)294 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)295 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)296 int get_connections (PortEngine::PortHandle ph, std::vector<std::string>& results, bool process_callback_safe) { return PortEngineSharedImpl::get_connections (ph, results, process_callback_safe); } 297 298 /* MIDI */ 299 int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t const** buf, void* port_buffer, uint32_t event_index); midi_event_put(void * port_buffer,pframes_t timestamp,const uint8_t * buffer,size_t size)300 int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size) { 301 return _midi_event_put (port_buffer, timestamp, buffer, size); 302 } 303 304 uint32_t get_midi_event_count (void* port_buffer); 305 void midi_clear (void* port_buffer); 306 307 /* Monitoring */ 308 309 bool can_monitor_input () const; 310 int request_input_monitoring (PortHandle, bool); 311 int ensure_input_monitoring (PortHandle, bool); 312 bool monitoring_input (PortHandle); 313 314 /* Latency management */ 315 316 void set_latency_range (PortHandle, bool for_playback, LatencyRange); 317 LatencyRange get_latency_range (PortHandle, bool for_playback); 318 319 /* Getting access to the data buffer for a port */ 320 321 void* get_buffer (PortHandle, pframes_t); 322 323 void* freewheel_thread (); 324 void pre_process (); 325 void coremidi_rediscover (); 326 327 static int _midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size); 328 329 private: 330 std::string _instance_name; 331 CoreAudioPCM *_pcmio; 332 CoreMidiIo *_midiio; 333 334 bool _run; /* keep going or stop, ardour thread */ 335 bool _active_ca; /* is running, process thread */ 336 bool _active_fw; /* is running, process thread */ 337 bool _preinit; 338 bool _freewheeling; 339 bool _freewheel; 340 bool _freewheel_ack; 341 bool _reinit_thread_callback; 342 bool _measure_latency; 343 344 uint64_t _last_process_start; 345 346 pthread_mutex_t _process_callback_mutex; 347 348 pthread_mutex_t _freewheel_mutex; 349 pthread_cond_t _freewheel_signal; 350 351 static std::vector<std::string> _midi_options; 352 static std::vector<AudioBackend::DeviceStatus> _input_audio_device_status; 353 static std::vector<AudioBackend::DeviceStatus> _output_audio_device_status; 354 static std::vector<AudioBackend::DeviceStatus> _duplex_audio_device_status; 355 static std::vector<AudioBackend::DeviceStatus> _midi_device_status; 356 357 mutable std::string _input_audio_device; 358 mutable std::string _output_audio_device; 359 std::string _midi_driver_option; 360 361 /* audio settings */ 362 float _samplerate; 363 size_t _samples_per_period; 364 static size_t _max_buffer_size; 365 366 uint32_t _n_inputs; 367 uint32_t _n_outputs; 368 369 uint32_t _systemic_audio_input_latency; 370 uint32_t _systemic_audio_output_latency; 371 372 /* coreaudio specific */ 373 enum DeviceFilter { All, Input, Output, Duplex }; 374 uint32_t name_to_id(std::string, DeviceFilter filter = All) const; 375 376 /* processing */ 377 float _dsp_load; 378 ARDOUR::DSPLoadCalculator _dsp_load_calc; 379 uint64_t _processed_samples; 380 381 pthread_t _main_thread; 382 pthread_t _freeewheel_thread; 383 384 /* process threads */ 385 static void* coreaudio_process_thread (void *); 386 std::vector<pthread_t> _threads; 387 388 struct ThreadData { 389 CoreAudioBackend* engine; 390 boost::function<void ()> f; 391 size_t stacksize; 392 ThreadDataThreadData393 ThreadData (CoreAudioBackend* e, boost::function<void ()> fp, size_t stacksz) 394 : engine (e) , f (fp) , stacksize (stacksz) {} 395 }; 396 397 /* port engine */ 398 int register_system_audio_ports (); 399 find_port_in(std::vector<BackendPortPtr> const & plist,const std::string & port_name)400 BackendPortPtr find_port_in (std::vector<BackendPortPtr> const & plist, const std::string& port_name) const { 401 for (std::vector<BackendPortPtr>::const_iterator it = plist.begin (); it != plist.end (); ++it) { 402 if ((*it)->name () == port_name) { 403 return *it; 404 } 405 } 406 return BackendPortPtr(); 407 } 408 409 BackendPort* port_factory (std::string const & name, ARDOUR::DataType type, ARDOUR::PortFlags); 410 411 void reset_midi_parsers (); 412 413 }; // class CoreAudioBackend 414 415 } // namespace 416 417 #endif /* __libbackend_coreaudio_backend_h__ */ 418