Anklang 0.3.0-460-gc4ef46ba
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
driver-jack.cc
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#include "driver.hh"
3#include "datautils.hh"
4#include "platform.hh"
5#include "internal.hh"
6#include "strings.hh"
7#include <unistd.h>
8#include <atomic>
9
10#define JDEBUG(...) Ase::debug ("jack", __VA_ARGS__)
11
12#if __has_include(<jack/jack.h>)
13#include <jack/jack.h>
14
15#define MAX_JACK_STRING_SIZE 1024
16
17namespace { // Anon
18using namespace Ase;
19
20/*------------------------------------------------------------------------
21The jack driver as provided here should be usable. However, there are a few
22things that could be improved, here is a short list.
23
24Audio Engine start/stop
25-----------------------
26Currently the JACK driver registers a new ANKLANG client every time the device
27is opened. This is problematic because connections between the ANKLANG jack
28client and other applications will be disconnected on every close. So
29redirecting output song playback through some other application would have
30to be reconnected the next time the song plays. Also connecting ANKLANG to
31other JACK clients while the device is closed - before actual playback -
32would be impossible.
33
34To fix this, there should be an explicit audio engine start/stop in ANKLANG.
35Once the audio engine is started, the JACK client should remain registered
36with JACK, even if no song is playing. This should fix the problems this
37driver has due to JACK disconnect on device close.
38
39JACK Midi
40---------
41Apart from audio, JACK can provide midi events to clients. This can be
42added later on.
43
44Less buffering, better latency
45------------------------------
46Currently, the JACK driver has a ring buffer that holds some audio data. This
47introduces latency. This is not what JACK applications typically do. So here
48are some thoughts of how to avoid buffering completely.
49
50To do so, we make the JACK callback block until ANKLANG has processed the audio
51data.
52
53(1) [JACK Thread] jack_process_callback gets called with N input samples
54(2) [JACK Thread] wake up engine thread
55(3) [JACK Thread] wait for engine thread
56(4) [ENGINE Thread] engine thread processes N samples input -> N samples output
57(5) [ENGINE Thread] engine thread wakes up jack thread
58(6) [JACK Thread] jack_process_callback returns, supplying N output samples
59
60So the idea is to receive input samples from jack (1) and then stall the jack
61thread (2). The engine processes the samples (4) and wakes up the jack thread
62(5) which then returns (6) the samples the engine created. The engine thread
63can use helper threads to complete the job.
64
65Note that this optimization works best (no buffering/latency) if the engine
66block size and the jack block size are equal. It also works well if the jack
67block size is an integer multiple fo the engine block size.
68
69This avoids latency and buffering. However this may pose stricter RT
70requirements onto ANKLANG. So whether it runs as dropout-free as the current
71version would remain to be seen. A not so realtime version would buffer
72M complete blocks of N samples, still avoiding partially filled buffers.
73------------------------------------------------------------------------*/
74
95template<class T>
96class FrameRingBuffer {
97 ASE_CLASS_NON_COPYABLE (FrameRingBuffer);
98private:
99 std::vector<std::vector<T> > channel_buffer_;
100 std::atomic<int> atomic_read_frame_pos_ {0};
101 std::atomic<int> atomic_write_frame_pos_ {0};
102 uint channel_buffer_size_ = 0; // = n_frames + 1; the extra frame allows us to
103 // see the difference between an empty/full ringbuffer
104 uint n_channels_ = 0;
105public:
106 FrameRingBuffer (uint n_frames = 0,
107 uint n_channels = 1)
108 {
109 resize (n_frames, n_channels);
110 }
117 uint
118 get_readable_frames()
119 {
120 int wpos = atomic_write_frame_pos_;
121 int rpos = atomic_read_frame_pos_;
122
123 if (wpos < rpos) /* wpos == rpos -> empty ringbuffer */
124 wpos += channel_buffer_size_;
125
126 return wpos - rpos;
127 }
137 uint
138 read (uint n_frames,
139 T **frames)
140 {
141 int rpos = atomic_read_frame_pos_;
142 uint can_read = std::min (get_readable_frames(), n_frames);
143
144 uint read1 = std::min (can_read, channel_buffer_size_ - rpos);
145 uint read2 = can_read - read1;
146
147 for (uint ch = 0; ch < n_channels_; ch++)
148 {
149 fast_copy (read1, frames[ch], &channel_buffer_[ch][rpos]);
150 fast_copy (read2, frames[ch] + read1, &channel_buffer_[ch][0]);
151 }
152
153 atomic_read_frame_pos_ = (rpos + can_read) % channel_buffer_size_;
154 return can_read;
155 }
162 uint
163 get_writable_frames()
164 {
165 int wpos = atomic_write_frame_pos_;
166 int rpos = atomic_read_frame_pos_;
167
168 if (rpos <= wpos) /* wpos == rpos -> empty ringbuffer */
169 rpos += channel_buffer_size_;
170
171 // the extra frame allows us to see the difference between an empty/full ringbuffer
172 return rpos - wpos - 1;
173 }
183 uint
184 write (uint n_frames,
185 const T **frames)
186 {
187 int wpos = atomic_write_frame_pos_;
188 uint can_write = std::min (get_writable_frames(), n_frames);
189
190 uint write1 = std::min (can_write, channel_buffer_size_ - wpos);
191 uint write2 = can_write - write1;
192
193 for (uint ch = 0; ch < n_channels_; ch++)
194 {
195 fast_copy (write1, &channel_buffer_[ch][wpos], frames[ch]);
196 fast_copy (write2, &channel_buffer_[ch][0], frames[ch] + write1);
197 }
198
199 // It is important that the data from the previous writes get written
200 // to memory *before* the index variable is updated.
201 //
202 // Writing the C++ atomic variable (position) as last step should ensure
203 // correct ordering (also across threads).
204
205 atomic_write_frame_pos_ = (wpos + can_write) % channel_buffer_size_;
206 return can_write;
207 }
214 uint
215 get_total_n_frames() const
216 {
217 // the extra frame allows us to see the difference between an empty/full ringbuffer
218 return channel_buffer_size_ - 1;
219 }
226 uint
227 get_n_channels() const
228 {
229 return n_channels_;
230 }
237 void
238 clear()
239 {
240 atomic_read_frame_pos_ = 0;
241 atomic_write_frame_pos_ = 0;
242 }
249 void
250 resize (uint n_frames,
251 uint n_channels = 1)
252 {
253 n_channels_ = n_channels;
254 channel_buffer_.resize (n_channels);
255
256 // the extra frame allows us to see the difference between an empty/full ringbuffer
257 channel_buffer_size_ = n_frames + 1;
258 for (uint ch = 0; ch < n_channels_; ch++)
259 channel_buffer_[ch].resize (channel_buffer_size_);
260
261 clear();
262 }
263};
264
265static void
266error_callback_silent (const char *msg)
267{
268 JDEBUG ("%s\n", msg);
269}
270
271static void
272error_callback_show (const char *msg)
273{
274 Ase::printerr ("JACK: %s\n", msg);
275}
276
277static jack_client_t *
278connect_jack()
279{
280 /* don't report errors during open: silently use the next available driver if JACK is not there */
281 jack_set_error_function (error_callback_silent);
282
283 jack_status_t status;
284 jack_client_t *jack_client;
285 {
286 const String thisthreadname = this_thread_get_name(); // work around libjack starting threads without setting thread name
287 this_thread_set_name ("JackPcmDriver-C");
288 jack_client = jack_client_open (executable_name().c_str(), JackNoStartServer, &status);
289 this_thread_set_name (thisthreadname); // thread name workaround
290 }
291
292 jack_set_error_function (error_callback_show);
293
294 JDEBUG ("attaching to server returned status: %d\n", status);
295 return jack_client;
296}
297
298static void
299disconnect_jack (jack_client_t *jack_client)
300{
301 assert_return (jack_client != NULL);
302
303 jack_deactivate (jack_client);
304 jack_client_close (jack_client);
305}
306
307struct DeviceDetails {
308 uint ports = 0;
309 uint input_ports = 0;
310 uint output_ports = 0;
311 uint physical_ports = 0;
312 uint terminal_ports = 0;
313 bool default_device = false;
314
315 std::vector<std::string> input_port_names;
316 std::vector<std::string> output_port_names;
317 std::string input_port_alias;
318};
319
321query_jack_devices (jack_client_t *jack_client)
322{
324
325 assert_return (jack_client, devices);
326 assert_return (MAX_JACK_STRING_SIZE >= jack_port_name_size(), devices);
327
328 const char **jack_ports = jack_get_ports (jack_client, NULL, NULL, 0);
329 if (jack_ports)
330 {
331 bool have_default_device = false;
332
333 for (uint i = 0; jack_ports[i]; i++)
334 {
335 jack_port_t *jack_port = jack_port_by_name (jack_client, jack_ports[i]);
336 const char *end = strchr (jack_ports[i], ':');
337 if (!jack_port || !end)
338 continue;
339 std::string device_name (jack_ports[i], end);
340
341 const char *port_type = jack_port_type (jack_port);
342 if (strcmp (port_type, JACK_DEFAULT_AUDIO_TYPE) == 0)
343 {
344 DeviceDetails &details = devices[device_name];
345 details.ports++;
346
347 const int flags = jack_port_flags (jack_port);
348 if (flags & JackPortIsInput)
349 {
350 details.input_ports++;
351 details.input_port_names.push_back (jack_ports[i]);
352 }
353 if (flags & JackPortIsOutput)
354 {
355 details.output_ports++;
356 details.output_port_names.push_back (jack_ports[i]);
357 }
358 if (flags & JackPortIsTerminal)
359 details.terminal_ports++;
360 if (flags & JackPortIsPhysical)
361 {
362 details.physical_ports++;
363
364 if (!have_default_device && (flags & JackPortIsInput))
365 {
366 /* the first device that has physical ports is the default device */
367 details.default_device = true;
368 have_default_device = true;
369 char alias1[MAX_JACK_STRING_SIZE] = "", alias2[MAX_JACK_STRING_SIZE] = "";
370 char *aliases[2] = { alias1, alias2, };
371 const int cnt = jack_port_get_aliases (jack_port, aliases);
372 if (cnt >= 1 && alias1[0])
373 {
374 const char *acolon = strrchr (alias1, ':');
375 details.input_port_alias = acolon ? std::string (alias1, acolon - alias1) : alias1;
376 }
377 }
378 }
379 }
380 }
381 free (jack_ports);
382 }
383
384 return devices;
385}
386
387static void
388list_jack_drivers (Driver::EntryVec &entries)
389{
391 jack_client_t *jack_client = connect_jack();
392 if (jack_client)
393 {
394 devices = query_jack_devices (jack_client);
395 disconnect_jack (jack_client);
396 }
397
398 for (std::map<std::string, DeviceDetails>::iterator di = devices.begin(); di != devices.end(); di++)
399 {
400 const std::string &devid = di->first;
401 DeviceDetails &details = di->second;
402
403 /* the default device is usually the hardware device, so things should work as expected
404 * we could show try to show non-default devices as well, but this could be confusing
405 */
406 if (details.default_device && (details.input_ports || details.output_ports))
407 {
408 Driver::Entry entry;
409 entry.devid = devid;
410 entry.device_name = string_format ("JACK \"%s\" Audio Device", devid);
411 const std::string phprefix = details.physical_ports == details.ports ? "Physical: " : "";
412 if (!details.input_port_alias.empty())
413 entry.device_name += " [" + phprefix + details.input_port_alias + "]";
414 entry.capabilities = details.output_ports && details.input_ports ? "Full-Duplex Audio" : details.output_ports ? "Audio Input" : "Audio Output";
415 entry.capabilities += string_format (", channels: %d*playback + %d*capture", details.input_ports, details.output_ports);
416 entry.device_info = "Routing via the JACK Audio Connection Kit";
417 if (details.physical_ports == details.ports)
418 entry.notice = "Note: JACK adds latency compared to direct hardware access";
419 entry.priority = Driver::JACK;
420 entries.push_back (entry);
421 }
422 }
423}
424
425} // Anon
426
427namespace Ase {
428
429/* macro for jack dropout tests - see below */
430#define TEST_DROPOUT() if (unlink ("/tmp/ase-dropout") == 0) usleep (1.5 * 1000000. * buffer_frames_ / mix_freq_); /* sleep 1.5 * buffer size */
431
432// == JackPcmDriver ==
433class JackPcmDriver : public PcmDriver {
434 jack_client_t *jack_client_ = nullptr;
435 uint n_channels_ = 0;
436 uint mix_freq_ = 0;
437 std::vector<jack_port_t *> input_ports_;
438 std::vector<jack_port_t *> output_ports_;
439 FrameRingBuffer<float> input_ringbuffer_;
440 FrameRingBuffer<float> output_ringbuffer_;
441 uint buffer_frames_ = 0; /* input/output ringbuffer size in frames */
442 uint block_length_ = 0;
443
444 std::atomic<int> atomic_active_ {0};
445 std::atomic<int> atomic_xruns_ {0};
446 int printed_xruns_ = 0;
447
448 bool is_down_ = false;
449 bool printed_is_down_ = false;
450
451 uint64 device_read_counter_ = 0;
452 uint64 device_write_counter_ = 0;
453 int device_open_counter_ = 0;
454
455 int
456 process_callback (jack_nframes_t n_frames)
457 {
458 /* setup port pointers */
459 assert_return (input_ports_.size() == n_channels_, 0);
460 assert_return (output_ports_.size() == n_channels_, 0);
461
462 const float *in_values[n_channels_];
463 float *out_values[n_channels_];
464 for (uint ch = 0; ch < n_channels_; ch++)
465 {
466 in_values[ch] = (float *) jack_port_get_buffer (input_ports_[ch], n_frames);
467 out_values[ch] = (float *) jack_port_get_buffer (output_ports_[ch], n_frames);
468 }
469
470 if (!atomic_active_)
471 {
472 for (auto values : out_values)
473 floatfill (values, 0.0, n_frames);
474 }
475 else if (input_ringbuffer_.get_writable_frames() >= n_frames && output_ringbuffer_.get_readable_frames() >= n_frames)
476 {
477 /* handle input ports */
478 uint frames_written = input_ringbuffer_.write (n_frames, in_values);
479 assert_return (frames_written == n_frames, 0); // we checked the available space before
480
481 /* handle output ports */
482 uint read_frames = output_ringbuffer_.read (n_frames, out_values);
483 assert_return (read_frames == n_frames, 0); // we checked the available space before
484 }
485 else
486 {
487 /* underrun (less than n_frames available in input/output ringbuffer) -> write zeros */
488 atomic_xruns_++;
489
490 for (auto values : out_values)
491 floatfill (values, 0.0, n_frames);
492 }
493 return 0;
494 }
495
496 static jack_latency_range_t
497 get_latency_for_ports (const std::vector<jack_port_t *>& ports,
498 jack_latency_callback_mode_t mode)
499 {
500 jack_latency_range_t range = { 0, 0 };
501
502 // compute minimum possible and maximum possible latency over all ports
503 for (size_t p = 0; p < ports.size(); p++)
504 {
505 jack_latency_range_t port_range;
506
507 jack_port_get_latency_range (ports[p], mode, &port_range);
508
509 if (!p) // first port
510 range = port_range;
511 else
512 {
513 range.min = std::min (range.min, port_range.min);
514 range.max = std::max (range.max, port_range.max);
515 }
516 }
517 return range;
518 }
519 void
520 latency_callback (jack_latency_callback_mode_t mode)
521 {
522 // the capture/playback latency added is the number of samples in the ringbuffer
523 if (mode == JackCaptureLatency)
524 {
525 jack_latency_range_t range = get_latency_for_ports (input_ports_, mode);
526 range.min += buffer_frames_;
527 range.max += buffer_frames_;
528
529 for (auto port : output_ports_)
530 jack_port_set_latency_range (port, mode, &range);
531 }
532 else
533 {
534 jack_latency_range_t range = get_latency_for_ports (output_ports_, mode);
535 range.min += buffer_frames_;
536 range.max += buffer_frames_;
537
538 for (auto port : input_ports_)
539 jack_port_set_latency_range (port, mode, &range);
540 }
541 }
542 void
543 shutdown_callback()
544 {
545 is_down_ = true;
546 }
547public:
548 JackPcmDriver (const String &driver, const String &devid) :
549 PcmDriver (driver, devid)
550 {}
551 static PcmDriverP
552 create (const String &devid)
553 {
554 auto pdriverp = std::make_shared<JackPcmDriver> (kvpair_key (devid), kvpair_value (devid));
555 return pdriverp;
556 }
557 ~JackPcmDriver()
558 {
559 if (jack_client_)
560 close();
561 }
562 uint
563 pcm_n_channels () const override
564 {
565 return n_channels_;
566 }
567 uint
568 pcm_mix_freq () const override
569 {
570 return mix_freq_;
571 }
572 uint
573 pcm_block_length () const override
574 {
575 return block_length_;
576 }
577 virtual void
578 close () override
579 {
580 assert_return (opened());
581 disconnect_jack (jack_client_);
582 jack_client_ = nullptr;
583 }
584 virtual Error
585 open (IODir iodir, const PcmDriverConfig &config) override
586 {
587 assert_return (!opened(), Error::INTERNAL);
588 assert_return (!jack_client_, Error::INTERNAL);
589 assert_return (device_open_counter_++ == 0, Error::INTERNAL); // calling open more than once is not supported
590
591 jack_client_ = connect_jack();
592 if (!jack_client_)
593 return Ase::Error::FILE_OPEN_FAILED;
594
595 // always use duplex mode for this device
596 flags_ |= Flags::READABLE | Flags::WRITABLE;
597 n_channels_ = config.n_channels;
598
599 /* try setup */
600 Ase::Error error = Ase::Error::NONE;
601
602 mix_freq_ = jack_get_sample_rate (jack_client_);
603 block_length_ = config.block_length;
604
605 for (uint i = 0; i < n_channels_; i++)
606 {
607 const int port_name_size = jack_port_name_size();
608 char port_name[port_name_size];
609 jack_port_t *port;
610
611 snprintf (port_name, port_name_size, "in_%u", i);
612 port = jack_port_register (jack_client_, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
613 if (port)
614 input_ports_.push_back (port);
615 else
616 error = Ase::Error::FILE_OPEN_FAILED;
617
618 snprintf (port_name, port_name_size, "out_%u", i);
619 port = jack_port_register (jack_client_, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
620 if (port)
621 output_ports_.push_back (port);
622 else
623 error = Ase::Error::FILE_OPEN_FAILED;
624 }
625
626 /* initialize ring buffers */
627 if (error == 0)
628 {
629 // keep at least two jack callback sizes for dropout free audio
630 uint min_buffer_frames = jack_get_buffer_size (jack_client_) * 2;
631
632 // keep an extra engine buffer size (this compensates also for cases where the
633 // engine buffer size is not a 2^N value, which would otherwise cause the
634 // buffer never to be fully filled with 2 periods of data)
635 min_buffer_frames += config.block_length;
636
637 // honor the user defined latency specification
638 //
639 // the user defined latency is only used to adjust our local buffering
640 // -> it doesn't take into account latencies outside anklang, such as the buffering
641 // jack does, or latencies added by other clients)
642 uint user_buffer_frames = config.latency_ms * config.mix_freq / 1000;
643 uint buffer_frames = std::max (min_buffer_frames, user_buffer_frames);
644
645 input_ringbuffer_.resize (buffer_frames, n_channels_);
646 output_ringbuffer_.resize (buffer_frames, n_channels_);
647 buffer_frames_ = output_ringbuffer_.get_writable_frames();
648
649 // the ringbuffer should be exactly as big as requested
650 if (buffer_frames_ != buffer_frames)
651 {
652 Ase::warning ("JACK driver: ring buffer size not correct: (buffer_frames_ != buffer_frames); (%u != %u)\n",
653 buffer_frames_, buffer_frames);
654 error = Ase::Error::INTERNAL;
655 }
656 JDEBUG ("%s: ringbuffer size=%d duration=%.3fms", devid_, buffer_frames_, buffer_frames_ / double (mix_freq_) * 1000);
657
658 /* initialize output ringbuffer with silence
659 * this will prevent dropouts at initialization, when no data is there at all
660 */
661 std::vector<float> silence (output_ringbuffer_.get_total_n_frames());
662 std::vector<const float *> silence_buffers (output_ringbuffer_.get_n_channels());
663
664 fill (silence_buffers.begin(), silence_buffers.end(), &silence[0]);
665
666 uint frames_written = output_ringbuffer_.write (buffer_frames, &silence_buffers[0]);
667 if (frames_written != buffer_frames)
668 Ase::warning ("JACK driver: output silence init failed: (frames_written != jack->buffer_frames)\n");
669 }
670
671 /* activate */
672 if (error == 0)
673 {
674 jack_set_process_callback (jack_client_, [] (jack_nframes_t n_frames, void *p) {
675 return static_cast <JackPcmDriver *> (p)->process_callback (n_frames);
676 }, this);
677
678 jack_set_latency_callback (jack_client_, [] (jack_latency_callback_mode_t mode, void *p) {
679 static_cast <JackPcmDriver *> (p)->latency_callback (mode);
680 }, this);
681
682 jack_on_shutdown (jack_client_, [] (void *p) {
683 static_cast<JackPcmDriver *> (p)->shutdown_callback();
684 }, this);
685
686 int active_err;
687 {
688 const String thisthreadname = this_thread_get_name(); // work around libjack starting threads without setting thread name
689 this_thread_set_name ("JackPcmDriver-A");
690 active_err = jack_activate (jack_client_);
691 this_thread_set_name (thisthreadname); // thread name workaround
692 }
693
694 if (active_err != 0)
695 error = Ase::Error::FILE_OPEN_FAILED;
696 }
697
698 /* connect ports */
699 if (error == 0) // we may want to make auto connect configurable (so it can be turned off)
700 {
701 std::map<std::string, DeviceDetails> devices = query_jack_devices (jack_client_);
703
704 di = devices.find (devid_);
705 if (di != devices.end())
706 {
707 const DeviceDetails &details = di->second;
708
709 for (uint ch = 0; ch < n_channels_; ch++)
710 {
711 if (details.output_ports > ch)
712 jack_connect (jack_client_, details.output_port_names[ch].c_str(),
713 jack_port_name (input_ports_[ch]));
714 if (details.input_ports > ch)
715 jack_connect (jack_client_, jack_port_name (output_ports_[ch]),
716 details.input_port_names[ch].c_str());
717 }
718 }
719 }
720
721 /* setup PCM handle or shutdown */
722 if (error == 0)
723 {
724 flags_ |= Flags::OPENED;
725
726 uint dummy;
727 pcm_latency (&dummy, &dummy); // debugging only: print latency values
728 }
729 else
730 {
731 disconnect_jack (jack_client_);
732 jack_client_ = nullptr;
733 }
734 JDEBUG ("%s: opening PCM: readable=%d writable=%d mix=%.1fHz block=%d: %s", devid_, readable(), writable(), mix_freq_, block_length_, ase_error_blurb (error));
735 return error;
736 }
737 virtual bool
738 pcm_check_io (long *timeoutp) override
739 {
740 assert_return (jack_client_ != nullptr, false);
741
742 if (0)
743 {
744 /* One of the things that we want to test is whether the JACK driver would
745 * recover properly if a dropout should occur.
746 *
747 * Since dropouts occur rarely, we can use the TEST_DROPOUT macro. This
748 * will check if /tmp/drop exists, and if so, sleep for some time to
749 * ensure ASE can't write to/read from the ring buffer in time. Such an
750 * artificial dropout can be created using
751 *
752 * $ touch /tmp/drop
753 *
754 * The file will be removed and a sleep will happen.
755 *
756 * - for production builds, the macro should never be used
757 * - the macro invocation can be moved to other places in the source code
758 * to introduce a dropout there
759 */
760 TEST_DROPOUT();
761 }
762
763 /* enable processing in callback (if not already active) */
764 atomic_active_ = 1;
765
766 /* report jack driver xruns */
767 if (atomic_xruns_ != printed_xruns_)
768 {
769 printed_xruns_ = atomic_xruns_;
770 Ase::printerr ("JACK: %s: %d beast driver xruns\n", devid_, printed_xruns_);
771 }
772 /* report jack shutdown */
773 if (is_down_ && !printed_is_down_)
774 {
775 printed_is_down_ = true;
776 Ase::printerr ("JACK: %s: connection to jack server lost\n", devid_);
777 Ase::printerr ("JACK: %s: -> to continue, manually stop playback and restart\n", devid_);
778 }
779
780 uint n_frames_avail = std::min (output_ringbuffer_.get_writable_frames(), input_ringbuffer_.get_readable_frames());
781
782 /* check whether data can be processed */
783 if (n_frames_avail >= block_length_)
784 return true; /* need processing */
785
786 /* calculate timeout until processing is possible or needed */
787 uint diff_frames = block_length_ - n_frames_avail;
788 *timeoutp = diff_frames * 1000 / mix_freq_;
789
790 /* wait at least 1ms, because caller may interpret (timeout == 0) as "process now" */
791 *timeoutp = std::max<int> (*timeoutp, 1);
792 return false;
793 }
794 void
795 pcm_latency (uint *rlatency, uint *wlatency) const override
796 {
797 assert_return (jack_client_ != NULL);
798
799 jack_nframes_t jack_rlatency = 0;
800 for (auto port : input_ports_)
801 {
802 jack_latency_range_t in_lrange;
803 jack_port_get_latency_range (port, JackCaptureLatency, &in_lrange);
804
805 jack_rlatency = std::max (jack_rlatency, in_lrange.max);
806 }
807
808 jack_nframes_t jack_wlatency = 0;
809 for (auto port : output_ports_)
810 {
811 jack_latency_range_t out_lrange;
812 jack_port_get_latency_range (port, JackPlaybackLatency, &out_lrange);
813
814 jack_wlatency = std::max (jack_wlatency, out_lrange.max);
815 }
816
817 uint total_latency = buffer_frames_ + jack_rlatency + jack_wlatency;
818 JDEBUG ("%s: jack_rlatency=%.3f ms jack_wlatency=%.3f ms ringbuffer=%.3f ms total_latency=%.3f ms",
819 devid_,
820 jack_rlatency / double (mix_freq_) * 1000,
821 jack_wlatency / double (mix_freq_) * 1000,
822 buffer_frames_ / double (mix_freq_) * 1000,
823 total_latency / double (mix_freq_) * 1000);
824
825 // ring buffer is normally completely filled
826 // -> the buffer latency counts as additional write latency
827
828 *rlatency = jack_rlatency;
829 *wlatency = jack_wlatency + buffer_frames_;
830 }
831 virtual size_t
832 pcm_read (size_t n, float *values) override
833 {
834 assert_return (jack_client_ != nullptr, 0);
835 assert_return (n == block_length_ * n_channels_, 0);
836
837 device_read_counter_++; // read must always gets called before write (see jack_device_write)
838
839 float deinterleaved_frame_data[block_length_ * n_channels_];
840 float *deinterleaved_frames[n_channels_];
841 for (uint ch = 0; ch < n_channels_; ch++)
842 deinterleaved_frames[ch] = &deinterleaved_frame_data[ch * block_length_];
843
844 // in check_io, we already ensured that there is enough data in the input_ringbuffer
845
846 uint frames_read = input_ringbuffer_.read (block_length_, deinterleaved_frames);
847 assert_return (frames_read == block_length_, 0);
848
849 for (uint ch = 0; ch < n_channels_; ch++)
850 {
851 const float *src = deinterleaved_frames[ch];
852 float *dest = &values[ch];
853
854 for (uint i = 0; i < frames_read; i++)
855 {
856 *dest = src[i];
857 dest += n_channels_;
858 }
859 }
860 return block_length_ * n_channels_;
861 }
862 virtual void
863 pcm_write (size_t n, const float *values) override
864 {
865 assert_return (jack_client_ != nullptr);
866 assert_return (n == block_length_ * n_channels_);
867
868 /* our buffer management is based on the assumption that jack_device_read()
869 * will always be performed before jack_device_write() - ANKLANG doesn't
870 * always guarantee this (for instance when removing the pcm input module
871 * from the snet while audio is playing), so we read and discard input
872 * if ANKLANG didn't call jack_device_read() already
873 */
874 device_write_counter_++;
875 if (device_read_counter_ < device_write_counter_)
876 {
877 float junk_frames[block_length_ * n_channels_];
878 pcm_read (n, junk_frames);
879 assert_return (device_read_counter_ == device_write_counter_);
880 }
881
882 // deinterleave
883 float deinterleaved_frame_data[block_length_ * n_channels_];
884 const float *deinterleaved_frames[n_channels_];
885 for (uint ch = 0; ch < n_channels_; ch++)
886 {
887 float *channel_data = &deinterleaved_frame_data[ch * block_length_];
888 for (uint i = 0; i < block_length_; i++)
889 channel_data[i] = values[ch + i * n_channels_];
890 deinterleaved_frames[ch] = channel_data;
891 }
892
893 // in check_io, we already ensured that there is enough space in the output_ringbuffer
894
895 uint frames_written = output_ringbuffer_.write (block_length_, deinterleaved_frames);
896 assert_return (frames_written == block_length_);
897 }
898};
899
900static const String jack_pcm_driverid = PcmDriver::register_driver ("jack", JackPcmDriver::create, list_jack_drivers);
901} // Ase
902
903#endif // __has_include(<jack/jack.h>)
Base class for a PCM devices.
Definition driver.hh:99
close
#define ASE_CLASS_NON_COPYABLE(ClassName)
Delete copy ctor and assignment operator.
Definition cxxaux.hh:106
snprintf
T end(T... args)
T fill(T... args)
free
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
Definition internal.hh:29
T max(T... args)
T min(T... args)
The Anklang C++ API namespace.
Definition api.hh:9
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
Definition cxxaux.hh:25
void floatfill(float *dst, float f, size_t n)
Fill n values of dst with f.
Definition datautils.hh:29
Error
Enum representing Error states.
Definition api.hh:22
std::string executable_name()
Retrieve the name part of executable_path().
Definition platform.cc:742
uint32_t uint
Provide 'uint' as convenience type.
Definition cxxaux.hh:18
void fast_copy(size_t n, float *d, const float *s)
Copy a block of floats.
Definition datautils.hh:37
Driver information for PCM and MIDI handling.
Definition driver.hh:16
PCM device configuration.
Definition driver.hh:91
open
read
write
strchr
strrchr