DummyAudioBackend: basic process threads and support structure
[ardour.git] / libs / backends / dummy / dummy_audiobackend.cc
1 /*
2  * Copyright (C) 2014 Robin Gareus <robin@gareus.org>
3  * Copyright (C) 2013 Paul Davis
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
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include <sys/time.h>
21 #include "dummy_audiobackend.h"
22 #include "pbd/error.h"
23 #include "i18n.h"
24
25 using namespace ARDOUR;
26
27 static std::string s_instance_name;
28 DummyAudioBackend::DummyAudioBackend (AudioEngine& e)
29         : AudioBackend (e)
30         , _running (false)
31         , _freewheeling (false)
32         , _samplerate (48000)
33         , _audio_buffersize (1024)
34         , _dsp_load (0)
35         , _n_inputs (0)
36         , _n_outputs (0)
37         , _systemic_input_latency (0)
38         , _systemic_output_latency (0)
39         , _processed_samples (0)
40 {
41         _instance_name = s_instance_name;
42 }
43
44 DummyAudioBackend::~DummyAudioBackend ()
45 {
46 }
47
48 /* AUDIOBACKEND API */
49
50 std::string
51 DummyAudioBackend::name () const
52 {
53         return X_("Dummy");
54 }
55
56 bool
57 DummyAudioBackend::is_realtime () const
58 {
59         return false;
60 }
61
62 std::vector<AudioBackend::DeviceStatus>
63 DummyAudioBackend::enumerate_devices () const
64 {
65         std::vector<AudioBackend::DeviceStatus> s;
66         s.push_back (DeviceStatus (_("Dummy"), true));
67         return s;
68 }
69
70 std::vector<float>
71 DummyAudioBackend::available_sample_rates (const std::string&) const
72 {
73         std::vector<float> sr;
74         sr.push_back (44100.0);
75         sr.push_back (48000.0);
76         return sr;
77 }
78
79 std::vector<uint32_t>
80 DummyAudioBackend::available_buffer_sizes (const std::string&) const
81 {
82         std::vector<uint32_t> bs;
83         bs.push_back (64);
84         bs.push_back (1024);
85         return bs;
86 }
87
88 uint32_t
89 DummyAudioBackend::available_input_channel_count (const std::string&) const
90 {
91         return 128;
92 }
93
94 uint32_t
95 DummyAudioBackend::available_output_channel_count (const std::string&) const
96 {
97         return 128;
98 }
99
100 bool
101 DummyAudioBackend::can_change_sample_rate_when_running () const
102 {
103         return true;
104 }
105
106 bool
107 DummyAudioBackend::can_change_buffer_size_when_running () const
108 {
109         return true;
110 }
111
112 int
113 DummyAudioBackend::set_device_name (const std::string&)
114 {
115         return 0;
116 }
117
118 int
119 DummyAudioBackend::set_sample_rate (float sr)
120 {
121         if (sr <= 0) { return -1; }
122         _samplerate = sr;
123         engine.sample_rate_change (sr);
124         return 0;
125 }
126
127 int
128 DummyAudioBackend::set_buffer_size (uint32_t bs)
129 {
130         return -1;
131         _audio_buffersize = bs;
132         engine.buffer_size_change (bs);
133         return 0;
134 }
135
136 int
137 DummyAudioBackend::set_interleaved (bool yn)
138 {
139         if (!yn) { return 0; }
140         return -1;
141 }
142
143 int
144 DummyAudioBackend::set_input_channels (uint32_t)
145 {
146         return -1;
147 }
148
149 int
150 DummyAudioBackend::set_output_channels (uint32_t)
151 {
152         return -1;
153 }
154
155 int
156 DummyAudioBackend::set_systemic_input_latency (uint32_t)
157 {
158         return -1;
159 }
160
161 int
162 DummyAudioBackend::set_systemic_output_latency (uint32_t)
163 {
164         return -1;
165 }
166
167 /* Retrieving parameters */
168 std::string
169 DummyAudioBackend::device_name () const
170 {
171         return _("Dummy Device");
172 }
173
174 float
175 DummyAudioBackend::sample_rate () const
176 {
177         return _samplerate;
178 }
179
180 uint32_t
181 DummyAudioBackend::buffer_size () const
182 {
183         return _audio_buffersize;
184 }
185
186 bool
187 DummyAudioBackend::interleaved () const
188 {
189         return false;
190 }
191
192 uint32_t
193 DummyAudioBackend::input_channels () const
194 {
195         return 0;
196 }
197
198 uint32_t
199 DummyAudioBackend::output_channels () const
200 {
201         return 0;
202 }
203
204 uint32_t
205 DummyAudioBackend::systemic_input_latency () const
206 {
207         return 0;
208 }
209
210 uint32_t
211 DummyAudioBackend::systemic_output_latency () const
212 {
213         return 0;
214 }
215
216 /* MIDI */
217 std::vector<std::string>
218 DummyAudioBackend::enumerate_midi_options () const
219 {
220         std::vector<std::string> m;
221         m.push_back (_("None"));
222         return m;
223 }
224
225 int
226 DummyAudioBackend::set_midi_option (const std::string&)
227 {
228         return -1;
229 }
230
231 std::string
232 DummyAudioBackend::midi_option () const
233 {
234         return "";
235 }
236
237 /* State Control */
238
239 static void * pthread_process (void *arg)
240 {
241         DummyAudioBackend *d = static_cast<DummyAudioBackend *>(arg);
242         d->main_process_thread ();
243         pthread_exit (0);
244         return 0;
245 }
246
247 int
248 DummyAudioBackend::_start (bool /*for_latency_measurement*/)
249 {
250         if (_running) {
251                 PBD::error << _("DummyAudioBackend: already active.") << endmsg;
252                 return -1;
253         }
254         if (pthread_create (&_main_thread, NULL, pthread_process, this)) {
255                 PBD::error << _("DummyAudioBackend: cannot start.") << endmsg;
256         }
257
258         int timeout = 5000;
259         while (!_running && --timeout > 0) { usleep (1000); }
260
261         if (timeout == 0 || !_running) {
262                 PBD::error << _("DummyAudioBackend: failed to start process thread.") << endmsg;
263                 return -1;
264         }
265
266         if (engine.reestablish_ports ()) {
267                 PBD::error << _("DummyAudioBackend: Could not re-establish ports.") << endmsg;
268                 stop ();
269                 return -1;
270         }
271
272         engine.reconnect_ports ();
273         return 0;
274 }
275
276 int
277 DummyAudioBackend::stop ()
278 {
279         void *status;
280         if (!_running) {
281                 return -1;
282         }
283
284         _running = false;
285         if (pthread_join (_main_thread, &status)) {
286                 PBD::error << _("DummyAudioBackend: failed to terminate.") << endmsg;
287                 return -1;
288         }
289         return 0;
290 }
291
292 int
293 DummyAudioBackend::freewheel (bool onoff)
294 {
295         if (onoff != _freewheeling) {
296                 return 0;
297         }
298         _freewheeling = onoff;
299         engine.freewheel_callback (onoff);
300         return 0;
301 }
302
303 float
304 DummyAudioBackend::dsp_load () const
305 {
306         return 100.f * _dsp_load;
307 }
308
309 size_t
310 DummyAudioBackend::raw_buffer_size (DataType t)
311 {
312         return 0;
313 }
314
315 /* Process time */
316 pframes_t
317 DummyAudioBackend::sample_time ()
318 {
319         return _processed_samples;
320 }
321
322 pframes_t
323 DummyAudioBackend::sample_time_at_cycle_start ()
324 {
325         return _processed_samples;
326 }
327
328 pframes_t
329 DummyAudioBackend::samples_since_cycle_start ()
330 {
331         return 0;
332 }
333
334
335 void *
336 DummyAudioBackend::dummy_process_thread (void *arg)
337 {
338         ThreadData* td = reinterpret_cast<ThreadData*> (arg);
339         boost::function<void ()> f = td->f;
340         delete td;
341         f ();
342         return 0;
343 }
344
345 int
346 DummyAudioBackend::create_process_thread (boost::function<void()> func)
347 {
348         pthread_t thread_id;
349         pthread_attr_t attr;
350         size_t stacksize = 100000;
351
352         pthread_attr_init (&attr);
353         pthread_attr_setstacksize (&attr, stacksize);
354         ThreadData* td = new ThreadData (this, func, stacksize);
355
356         if (pthread_create (&thread_id, &attr, dummy_process_thread, td)) {
357                 PBD::error << _("AudioEngine: cannot create process thread.") << endmsg;
358                 return -1;
359         }
360
361         _threads.push_back (thread_id);
362         return 0;
363 }
364
365 int
366 DummyAudioBackend::join_process_threads ()
367 {
368         int rv = 0;
369
370         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
371         {
372                 void *status;
373                 if (pthread_join (*i, &status)) {
374                         PBD::error << _("AudioEngine: cannot terminate process thread.") << endmsg;
375                         rv -= 1;
376                 }
377         }
378         _threads.clear ();
379         return rv;
380 }
381
382 bool
383 DummyAudioBackend::in_process_thread ()
384 {
385         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
386         {
387 #ifdef COMPILER_MINGW
388                 if (*i == GetCurrentThread ()) {
389                         return true;
390                 }
391 #else // pthreads
392                 if (pthread_equal (*i, pthread_self ()) != 0) {
393                         return true;
394                 }
395 #endif
396         }
397         return false;
398 }
399
400 uint32_t
401 DummyAudioBackend::process_thread_count ()
402 {
403         return _threads.size ();
404 }
405
406 void
407 DummyAudioBackend::update_latencies ()
408 {
409 }
410
411 /* PORTENGINE API */
412
413 void*
414 DummyAudioBackend::private_handle () const
415 {
416         return NULL;
417 }
418
419 const std::string&
420 DummyAudioBackend::my_name () const
421 {
422         return _instance_name;
423 }
424
425 bool
426 DummyAudioBackend::available () const
427 {
428         return true;
429 }
430
431 uint32_t
432 DummyAudioBackend::port_name_size () const
433 {
434         return 256;
435 }
436
437 int
438 DummyAudioBackend::set_port_name (PortEngine::PortHandle, const std::string&)
439 {
440         return -1;
441 }
442
443 std::string
444 DummyAudioBackend::get_port_name (PortEngine::PortHandle) const
445 {
446         return "port:XXX";
447 }
448
449 PortEngine::PortHandle
450 DummyAudioBackend::get_port_by_name (const std::string&) const
451 {
452         PortEngine::PortHandle port_handle = 0;
453         return port_handle;
454 }
455
456 int
457 DummyAudioBackend::get_ports (
458                 const std::string& port_name_pattern,
459                 DataType type, PortFlags flags,
460                 std::vector<std::string>&) const
461 {
462         return 0;
463 }
464
465 DataType
466 DummyAudioBackend::port_data_type (PortEngine::PortHandle) const
467 {
468         return DataType::AUDIO;
469 }
470
471 PortEngine::PortHandle
472 DummyAudioBackend::register_port (
473                 const std::string&,
474                 ARDOUR::DataType,
475                 ARDOUR::PortFlags)
476 {
477         PortEngine::PortHandle port_handle = 0;
478         return port_handle;
479 }
480
481 void
482 DummyAudioBackend::unregister_port (PortEngine::PortHandle)
483 {
484 }
485
486 int
487 DummyAudioBackend::connect (const std::string& src, const std::string& dst)
488 {
489         return -1;
490 }
491
492 int
493 DummyAudioBackend::disconnect (const std::string& src, const std::string& dst)
494 {
495         return -1;
496 }
497
498 int
499 DummyAudioBackend::connect (PortEngine::PortHandle, const std::string&)
500 {
501         return -1;
502 }
503
504 int
505 DummyAudioBackend::disconnect (PortEngine::PortHandle, const std::string&)
506 {
507         return -1;
508 }
509
510 int
511 DummyAudioBackend::disconnect_all (PortEngine::PortHandle)
512 {
513         return -1;
514 }
515
516 bool
517 DummyAudioBackend::connected (PortEngine::PortHandle, bool process_callback_safe)
518 {
519         return false;
520 }
521
522 bool
523 DummyAudioBackend::connected_to (PortEngine::PortHandle, const std::string&, bool process_callback_safe)
524 {
525         return false;
526 }
527
528 bool
529 DummyAudioBackend::physically_connected (PortEngine::PortHandle, bool process_callback_safe)
530 {
531         return false;
532 }
533
534 int
535 DummyAudioBackend::get_connections (PortEngine::PortHandle, std::vector<std::string>&, bool process_callback_safe)
536 {
537         return false;
538 }
539
540 /* MIDI */
541 int
542 DummyAudioBackend::midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index)
543 {
544         return -1;
545 }
546
547 int
548 DummyAudioBackend::midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size)
549 {
550         return -1;
551 }
552
553 uint32_t
554 DummyAudioBackend::get_midi_event_count (void* port_buffer)
555 {
556         return -1;
557 }
558
559 void
560 DummyAudioBackend::midi_clear (void* port_buffer)
561 {
562 }
563
564 /* Monitoring */
565
566 bool
567 DummyAudioBackend::can_monitor_input () const
568 {
569         return false;
570 }
571
572 int
573 DummyAudioBackend::request_input_monitoring (PortEngine::PortHandle, bool)
574 {
575         return -1;
576 }
577
578 int
579 DummyAudioBackend::ensure_input_monitoring (PortEngine::PortHandle, bool)
580 {
581         return -1;
582 }
583
584 bool
585 DummyAudioBackend::monitoring_input (PortEngine::PortHandle)
586 {
587         return false;
588 }
589
590 /* Latency management */
591
592 void
593 DummyAudioBackend::set_latency_range (PortEngine::PortHandle, bool for_playback, LatencyRange)
594 {
595 }
596
597 LatencyRange
598 DummyAudioBackend::get_latency_range (PortEngine::PortHandle, bool for_playback)
599 {
600         LatencyRange r;
601         r.min = 0;
602         r.max = 0;
603         return r;
604 }
605
606 /* Discovering physical ports */
607
608 bool
609 DummyAudioBackend::port_is_physical (PortEngine::PortHandle) const
610 {
611         return false;
612 }
613
614 void
615 DummyAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>&)
616 {
617 }
618
619 void
620 DummyAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>&)
621 {
622 }
623
624 ChanCount
625 DummyAudioBackend::n_physical_outputs () const
626 {
627         ChanCount cc;
628         cc.set (DataType::AUDIO, 0);
629         cc.set (DataType::MIDI, 0);
630         return cc;
631 }
632
633 ChanCount
634 DummyAudioBackend::n_physical_inputs () const
635 {
636         ChanCount cc;
637         cc.set (DataType::AUDIO, 0);
638         cc.set (DataType::MIDI, 0);
639         return cc;
640 }
641
642 /* Getting access to the data buffer for a port */
643
644 void*
645 DummyAudioBackend::get_buffer (PortEngine::PortHandle, pframes_t)
646 {
647 }
648
649 /* Engine Process */
650 void *
651 DummyAudioBackend::main_process_thread ()
652 {
653         AudioEngine::thread_init_callback (this);
654         _running = true;
655         _processed_samples = 0;
656
657         struct timeval clock1, clock2;
658         ::gettimeofday (&clock1, NULL);
659         while (_running) {
660                 if (engine.process_callback (_audio_buffersize)) {
661                         return 0;
662                 }
663                 _processed_samples += _audio_buffersize;
664                 if (!_freewheeling) {
665                         ::gettimeofday (&clock2, NULL);
666                         const int elapsed_time = (clock2.tv_sec - clock1.tv_sec) * 1000000 + (clock2.tv_usec - clock1.tv_usec);
667                         const int nomial_time = 1000000 * _audio_buffersize / _samplerate;
668                         _dsp_load = elapsed_time / (float) nomial_time;
669                         if (elapsed_time < nomial_time) {
670                                 ::usleep (nomial_time - elapsed_time);
671                         } else {
672                                 ::usleep (100); // don't hog cpu
673                         }
674                 } else {
675                         _dsp_load = 1.0;
676                         ::usleep (100); // don't hog cpu
677                 }
678                 ::gettimeofday (&clock1, NULL);
679         }
680         _running = false;
681         return 0;
682 }
683
684 /******************************************************************************/
685
686 static boost::shared_ptr<DummyAudioBackend> _instance;
687
688 static boost::shared_ptr<AudioBackend>
689 backend_factory (AudioEngine& e)
690 {
691         if (!_instance) {
692                 _instance.reset (new DummyAudioBackend (e));
693         }
694         return _instance;
695 }
696
697 static int
698 instantiate (const std::string& arg1, const std::string& /* arg2 */)
699 {
700         s_instance_name = arg1;
701         return 0;
702 }
703
704 static int
705 deinstantiate ()
706 {
707         _instance.reset ();
708         return 0;
709 }
710
711 static bool
712 already_configured ()
713 {
714         return false;
715 }
716
717 static ARDOUR::AudioBackendInfo _descriptor = {
718         "Dummy",
719         instantiate,
720         deinstantiate,
721         backend_factory,
722         already_configured,
723 };
724
725 extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
726 {
727         return &_descriptor;
728 }