Jack2: JackFreebobDriver.cpp Source File

Jack2 1.9.12

JackFreebobDriver.cpp
1 /*
2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2004 Grame
4 Copyright (C) 2007 Pieter Palmers
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
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 */
21
22 #include <iostream>
23 #include <unistd.h>
24 #include <math.h>
25 #include <stdio.h>
26 #include <memory.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <stdarg.h>
31 #include <signal.h>
32 #include <sys/types.h>
33 #include <sys/time.h>
34 #include <regex.h>
35 #include <string.h>
36
37 #include "JackFreebobDriver.h"
38 #include "JackEngineControl.h"
39 #include "JackClientControl.h"
40 #include "JackPort.h"
41 #include "JackGraphManager.h"
42 #include "JackLockedEngine.h"
43
44 namespace Jack
45 {
46
47 #define jack_get_microseconds GetMicroSeconds
48
49 #define SAMPLE_MAX_24BIT 8388608.0f
50 #define SAMPLE_MAX_16BIT 32768.0f
51
52 int
53 JackFreebobDriver::freebob_driver_read (freebob_driver_t * driver, jack_nframes_t nframes)
54 {
55 jack_default_audio_sample_t* buf = NULL;
56 freebob_sample_t nullbuffer[nframes];
57 void *addr_of_nullbuffer = (void *)nullbuffer;
58
59 freebob_streaming_stream_type stream_type;
60
61 printEnter();
62
63 // make sure all buffers have a valid buffer if not connected
64 for (unsigned int i = 0; i < driver->capture_nchannels; i++) {
65 stream_type = freebob_streaming_get_playback_stream_type(driver->dev, i);
66 if (stream_type == freebob_stream_type_audio) {
67 freebob_streaming_set_playback_stream_buffer(driver->dev, i,
68 (char *)(nullbuffer), freebob_buffer_type_float);
69 } else if (stream_type == freebob_stream_type_midi) {
70 // these should be read/written with the per-stream functions
71 } else { // empty other buffers without doing something with them
72 freebob_streaming_set_playback_stream_buffer(driver->dev, i,
73 (char *)(nullbuffer), freebob_buffer_type_uint24);
74 }
75 }
76
77 for (int i = 0; i < fCaptureChannels; i++) {
78 stream_type = freebob_streaming_get_capture_stream_type(driver->dev, i);
79 if (stream_type == freebob_stream_type_audio) {
80
81 if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) {
82 buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[i], nframes);
83
84 if (!buf) {
85 buf = (jack_default_audio_sample_t *)addr_of_nullbuffer;
86 }
87
88 freebob_streaming_set_capture_stream_buffer(driver->dev, i, (char *)(buf), freebob_buffer_type_float);
89 }
90 } else if (stream_type == freebob_stream_type_midi) {
91 // these should be read/written with the per-stream functions
92 } else { // empty other buffers without doing something with them
93 freebob_streaming_set_capture_stream_buffer(driver->dev, i, (char *)(nullbuffer), freebob_buffer_type_uint24);
94 }
95
96 }
97
98 // now transfer the buffers
99 freebob_streaming_transfer_capture_buffers(driver->dev);
100 printExit();
101 return 0;
102 }
103
104 int
105 JackFreebobDriver::freebob_driver_write (freebob_driver_t * driver, jack_nframes_t nframes)
106 {
107 jack_default_audio_sample_t* buf = NULL;
108
109 freebob_streaming_stream_type stream_type;
110
111 freebob_sample_t nullbuffer[nframes];
112 void *addr_of_nullbuffer = (void*)nullbuffer;
113
114 memset(&nullbuffer, 0, nframes*sizeof(freebob_sample_t));
115
116 printEnter();
117 driver->process_count++;
118 assert(driver->dev);
119
120 // make sure all buffers output silence if not connected
121 for (unsigned int i = 0; i < driver->playback_nchannels; i++) {
122 stream_type = freebob_streaming_get_playback_stream_type(driver->dev, i);
123 if (stream_type == freebob_stream_type_audio) {
124 freebob_streaming_set_playback_stream_buffer(driver->dev, i,
125 (char *)(nullbuffer), freebob_buffer_type_float);
126 } else if (stream_type == freebob_stream_type_midi) {
127 // these should be read/written with the per-stream functions
128 } else { // empty other buffers without doing something with them
129 freebob_streaming_set_playback_stream_buffer(driver->dev, i,
130 (char *)(nullbuffer), freebob_buffer_type_uint24);
131 }
132 }
133
134 for (int i = 0; i < fPlaybackChannels; i++) {
135 stream_type = freebob_streaming_get_playback_stream_type(driver->dev, i);
136 if (stream_type == freebob_stream_type_audio) {
137 // Ouput ports
138 if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
139 buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[i], nframes);
140 if (!buf) {
141 buf = (jack_default_audio_sample_t *)addr_of_nullbuffer;
142 }
143 freebob_streaming_set_playback_stream_buffer(driver->dev, i, (char *)(buf), freebob_buffer_type_float);
144 }
145 }
146 }
147
148 freebob_streaming_transfer_playback_buffers(driver->dev);
149 printExit();
150 return 0;
151 }
152
153 jack_nframes_t
154 JackFreebobDriver::freebob_driver_wait (freebob_driver_t *driver, int extra_fd, int *status,
155 float *delayed_usecs)
156 {
157 int nframes;
158 jack_time_t wait_enter;
159 jack_time_t wait_ret;
160
161 printEnter();
162
163 wait_enter = jack_get_microseconds ();
164 if (wait_enter > driver->wait_next) {
165 /*
166 * This processing cycle was delayed past the
167 * next due interrupt! Do not account this as
168 * a wakeup delay:
169 */
170 driver->wait_next = 0;
171 driver->wait_late++;
172 }
173 // *status = -2; interrupt
174 // *status = -3; timeout
175 // *status = -4; extra FD
176
177 nframes = freebob_streaming_wait(driver->dev);
178
179 wait_ret = jack_get_microseconds ();
180
181 if (driver->wait_next && wait_ret > driver->wait_next) {
182 *delayed_usecs = wait_ret - driver->wait_next;
183 }
184 driver->wait_last = wait_ret;
185 driver->wait_next = wait_ret + driver->period_usecs;
186 // driver->engine->transport_cycle_start (driver->engine, wait_ret);
187
188 if (nframes < 0) {
189 *status = 0;
190 return 0;
191 }
192
193 *status = 0;
194 fBeginDateUst = wait_ret;
195
196 // FIXME: this should do something more usefull
197 *delayed_usecs = 0;
198 printExit();
199 return nframes - nframes % driver->period_size;
200 }
201
202 int
203 JackFreebobDriver::freebob_driver_start (freebob_driver_t *driver)
204 {
205 int retval = 0;
206
207 #ifdef FREEBOB_DRIVER_WITH_MIDI
208 if (driver->midi_handle) {
209 if ((retval = freebob_driver_midi_start(driver->midi_handle))) {
210 printError("Could not start MIDI threads");
211 return retval;
212 }
213 }
214 #endif
215
216 if ((retval = freebob_streaming_start(driver->dev))) {
217 printError("Could not start streaming threads");
218 #ifdef FREEBOB_DRIVER_WITH_MIDI
219 if (driver->midi_handle) {
220 freebob_driver_midi_stop(driver->midi_handle);
221 }
222 #endif
223 return retval;
224 }
225
226 return 0;
227 }
228
229 int
230 JackFreebobDriver::freebob_driver_stop (freebob_driver_t *driver)
231 {
232 int retval = 0;
233
234 #ifdef FREEBOB_DRIVER_WITH_MIDI
235 if (driver->midi_handle) {
236 if ((retval = freebob_driver_midi_stop(driver->midi_handle))) {
237 printError("Could not stop MIDI threads");
238 return retval;
239 }
240 }
241 #endif
242 if ((retval = freebob_streaming_stop(driver->dev))) {
243 printError("Could not stop streaming threads");
244 return retval;
245 }
246
247 return 0;
248 }
249
250 int
251 JackFreebobDriver::freebob_driver_restart (freebob_driver_t *driver)
252 {
253 if (Stop())
254 return -1;
255 return Start();
256 }
257
258 int
259 JackFreebobDriver::SetBufferSize (jack_nframes_t nframes)
260 {
261 printError("Buffer size change requested but not supported!!!");
262
263 /*
264 driver->period_size = nframes;
265 driver->period_usecs =
266 (jack_time_t) floor ((((float) nframes) / driver->sample_rate)
267 * 1000000.0f);
268 */
269
270 /* tell the engine to change its buffer size */
271 //driver->engine->set_buffer_size (driver->engine, nframes);
272
273 return -1; // unsupported
274 }
275
276 typedef void (*JackDriverFinishFunction) (jack_driver_t *);
277
278 freebob_driver_t *
279 JackFreebobDriver::freebob_driver_new (char *name,
280 freebob_jack_settings_t *params)
281 {
282 freebob_driver_t *driver;
283
284 assert(params);
285
286 if (freebob_get_api_version() != 1) {
287 printMessage("Incompatible libfreebob version! (%s)", freebob_get_version());
288 return NULL;
289 }
290
291 printMessage("Starting Freebob backend (%s)", freebob_get_version());
292
293 driver = (freebob_driver_t*)calloc (1, sizeof (freebob_driver_t));
294
295 /* Setup the jack interfaces */
296 jack_driver_nt_init ((jack_driver_nt_t *) driver);
297
298 /* driver->nt_attach = (JackDriverNTAttachFunction) freebob_driver_attach;
299 driver->nt_detach = (JackDriverNTDetachFunction) freebob_driver_detach;
300 driver->nt_start = (JackDriverNTStartFunction) freebob_driver_start;
301 driver->nt_stop = (JackDriverNTStopFunction) freebob_driver_stop;
302 driver->nt_run_cycle = (JackDriverNTRunCycleFunction) freebob_driver_run_cycle;
303 driver->null_cycle = (JackDriverNullCycleFunction) freebob_driver_null_cycle;
304 driver->write = (JackDriverReadFunction) freebob_driver_write;
305 driver->read = (JackDriverReadFunction) freebob_driver_read;
306 driver->nt_bufsize = (JackDriverNTBufSizeFunction) freebob_driver_bufsize;
307 */
308
309 /* copy command line parameter contents to the driver structure */
310 memcpy(&driver->settings, params, sizeof(freebob_jack_settings_t));
311
312 /* prepare all parameters */
313 driver->sample_rate = params->sample_rate;
314 driver->period_size = params->period_size;
315 fBeginDateUst = 0;
316
317 driver->period_usecs =
318 (jack_time_t) floor ((((float) driver->period_size) * 1000000.0f) / driver->sample_rate);
319
320 // driver->client = client;
321 driver->engine = NULL;
322
323 memset(&driver->device_options, 0, sizeof(driver->device_options));
324 driver->device_options.sample_rate = params->sample_rate;
325 driver->device_options.period_size = params->period_size;
326 driver->device_options.nb_buffers = params->buffer_size;
327 driver->device_options.node_id = params->node_id;
328 driver->device_options.port = params->port;
329 driver->capture_frame_latency = params->capture_frame_latency;
330 driver->playback_frame_latency = params->playback_frame_latency;
331
332 if (!params->capture_ports) {
333 driver->device_options.directions |= FREEBOB_IGNORE_CAPTURE;
334 }
335
336 if (!params->playback_ports) {
337 driver->device_options.directions |= FREEBOB_IGNORE_PLAYBACK;
338 }
339
340 debugPrint(DEBUG_LEVEL_STARTUP, " Driver compiled on %s %s", __DATE__, __TIME__);
341 debugPrint(DEBUG_LEVEL_STARTUP, " Created driver %s", name);
342 debugPrint(DEBUG_LEVEL_STARTUP, " period_size: %d", driver->period_size);
343 debugPrint(DEBUG_LEVEL_STARTUP, " period_usecs: %d", driver->period_usecs);
344 debugPrint(DEBUG_LEVEL_STARTUP, " sample rate: %d", driver->sample_rate);
345
346 return (freebob_driver_t *) driver;
347 }
348
349 void
350 JackFreebobDriver::freebob_driver_delete (freebob_driver_t *driver)
351 {
352 free (driver);
353 }
354
355 #ifdef FREEBOB_DRIVER_WITH_MIDI
356 /*
357 * MIDI support
358 */
359
360 // the thread that will queue the midi events from the seq to the stream buffers
361
362 void *
363 JackFreebobDriver::freebob_driver_midi_queue_thread(void *arg)
364 {
365 freebob_driver_midi_handle_t *m = (freebob_driver_midi_handle_t *)arg;
366 assert(m);
367 snd_seq_event_t *ev;
368 unsigned char work_buffer[MIDI_TRANSMIT_BUFFER_SIZE];
369 int bytes_to_send;
370 int b;
371 int i;
372
373 printMessage("MIDI queue thread started");
374
375 while (1) {
376 // get next event, if one is present
377 while ((snd_seq_event_input(m->seq_handle, &ev) > 0)) {
378 // get the port this event is originated from
379 freebob_midi_port_t *port = NULL;
380 for (i = 0;i < m->nb_output_ports;i++) {
381 if (m->output_ports[i]->seq_port_nr == ev->dest.port) {
382 port = m->output_ports[i];
383 break;
384 }
385 }
386
387 if (!port) {
388 printError(" Could not find target port for event: dst=%d src=%d", ev->dest.port, ev->source.port);
389 break;
390 }
391
392 // decode it to the work buffer
393 if ((bytes_to_send = snd_midi_event_decode ( port->parser,
394 work_buffer,
395 MIDI_TRANSMIT_BUFFER_SIZE,
396 ev)) < 0) { // failed
397 printError(" Error decoding event for port %d (errcode=%d)", port->seq_port_nr, bytes_to_send);
398 bytes_to_send = 0;
399 //return -1;
400 }
401
402 for (b = 0;b < bytes_to_send;b++) {
403 freebob_sample_t tmp_event = work_buffer[b];
404 if (freebob_streaming_write(m->dev, port->stream_nr, &tmp_event, 1) < 1) {
405 printError(" Midi send buffer overrun");
406 }
407 }
408 }
409
410 // sleep for some time
411 usleep(MIDI_THREAD_SLEEP_TIME_USECS);
412 }
413 return NULL;
414 }
415
416 // the dequeue thread (maybe we need one thread per stream)
417 void *
418 JackFreebobDriver::freebob_driver_midi_dequeue_thread (void *arg)
419 {
420 freebob_driver_midi_handle_t *m = (freebob_driver_midi_handle_t *)arg;
421
422 int i;
423 int s;
424 int samples_read;
425
426 assert(m);
427
428 while (1) {
429 // read incoming events
430
431 for (i = 0;i < m->nb_input_ports;i++) {
432 unsigned int buff[64];
433 freebob_midi_port_t *port = m->input_ports[i];
434 if (!port) {
435 printError(" something went wrong when setting up the midi input port map (%d)", i);
436 }
437
438 do {
439 samples_read = freebob_streaming_read(m->dev, port->stream_nr, buff, 64);
440
441 for (s = 0;s < samples_read;s++) {
442 unsigned int *byte = (buff + s) ;
443 snd_seq_event_t ev;
444 if ((snd_midi_event_encode_byte(port->parser, (*byte) & 0xFF, &ev)) > 0) {
445 // a midi message is complete, send it out to ALSA
446 snd_seq_ev_set_subs(&ev);
447 snd_seq_ev_set_direct(&ev);
448 snd_seq_ev_set_source(&ev, port->seq_port_nr);
449 snd_seq_event_output_direct(port->seq_handle, &ev);
450 }
451 }
452 } while (samples_read > 0);
453 }
454
455 // sleep for some time
456 usleep(MIDI_THREAD_SLEEP_TIME_USECS);
457 }
458 return NULL;
459 }
460
461 freebob_driver_midi_handle_t *
462 JackFreebobDriver::freebob_driver_midi_init(freebob_driver_t *driver)
463 {
464 char buf[256];
465 channel_t chn;
466 int nchannels;
467 int i = 0;
468
469 freebob_device_t *dev = driver->dev;
470 assert(dev);
471
472 freebob_driver_midi_handle_t *m = calloc(1, sizeof(freebob_driver_midi_handle_t));
473 if (!m) {
474 printError("not enough memory to create midi structure");
475 return NULL;
476 }
477
478 if (snd_seq_open(&m->seq_handle, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK) < 0) {
479 printError("Error opening ALSA sequencer.");
480 free(m);
481 return NULL;
482 }
483
484 snd_seq_set_client_name(m->seq_handle, "FreeBoB Jack MIDI");
485
486 // find out the number of midi in/out ports we need to setup
487 nchannels = freebob_streaming_get_nb_capture_streams(dev);
488 m->nb_input_ports = 0;
489
490 for (chn = 0; chn < nchannels; chn++) {
491 if (freebob_streaming_get_capture_stream_type(dev, chn) == freebob_stream_type_midi) {
492 m->nb_input_ports++;
493 }
494 }
495
496 m->input_ports = calloc(m->nb_input_ports, sizeof(freebob_midi_port_t *));
497 if (!m->input_ports) {
498 printError("not enough memory to create midi structure");
499 free(m);
500 return NULL;
501 }
502
503 i = 0;
504 for (chn = 0; chn < nchannels; chn++) {
505 if (freebob_streaming_get_capture_stream_type(dev, chn) == freebob_stream_type_midi) {
506 m->input_ports[i] = calloc(1, sizeof(freebob_midi_port_t));
507 if (!m->input_ports[i]) {
508 // fixme
509 printError("Could not allocate memory for seq port");
510 continue;
511 }
512
513 freebob_streaming_get_capture_stream_name(dev, chn, buf, sizeof(buf));
514 printMessage("Register MIDI IN port %s", buf);
515
516 m->input_ports[i]->seq_port_nr = snd_seq_create_simple_port(m->seq_handle, buf,
517 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,
518 SND_SEQ_PORT_TYPE_MIDI_GENERIC);
519
520 if (m->input_ports[i]->seq_port_nr < 0) {
521 printError("Could not create seq port");
522 m->input_ports[i]->stream_nr = -1;
523 m->input_ports[i]->seq_port_nr = -1;
524 } else {
525 m->input_ports[i]->stream_nr = chn;
526 m->input_ports[i]->seq_handle = m->seq_handle;
527 if (snd_midi_event_new ( ALSA_SEQ_BUFF_SIZE, &(m->input_ports[i]->parser)) < 0) {
528 printError("could not init parser for MIDI IN port %d", i);
529 m->input_ports[i]->stream_nr = -1;
530 m->input_ports[i]->seq_port_nr = -1;
531 }
532 }
533
534 i++;
535 }
536 }
537
538 // playback
539 nchannels = freebob_streaming_get_nb_playback_streams(dev);
540
541 m->nb_output_ports = 0;
542
543 for (chn = 0; chn < nchannels; chn++) {
544 if (freebob_streaming_get_playback_stream_type(dev, chn) == freebob_stream_type_midi) {
545 m->nb_output_ports++;
546 }
547 }
548
549 m->output_ports = calloc(m->nb_output_ports, sizeof(freebob_midi_port_t *));
550 if (!m->output_ports) {
551 printError("not enough memory to create midi structure");
552 for (i = 0; i < m->nb_input_ports; i++) {
553 free(m->input_ports[i]);
554 }
555 free(m->input_ports);
556 free(m);
557 return NULL;
558 }
559
560 i = 0;
561 for (chn = 0; chn < nchannels; chn++) {
562 if (freebob_streaming_get_playback_stream_type(dev, chn) == freebob_stream_type_midi) {
563 m->output_ports[i] = calloc(1, sizeof(freebob_midi_port_t));
564 if (!m->output_ports[i]) {
565 // fixme
566 printError("Could not allocate memory for seq port");
567 continue;
568 }
569
570 freebob_streaming_get_playback_stream_name(dev, chn, buf, sizeof(buf));
571 printMessage("Register MIDI OUT port %s", buf);
572
573 m->output_ports[i]->seq_port_nr = snd_seq_create_simple_port(m->seq_handle, buf,
574 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
575 SND_SEQ_PORT_TYPE_MIDI_GENERIC);
576
577 if (m->output_ports[i]->seq_port_nr < 0) {
578 printError("Could not create seq port");
579 m->output_ports[i]->stream_nr = -1;
580 m->output_ports[i]->seq_port_nr = -1;
581 } else {
582 m->output_ports[i]->stream_nr = chn;
583 m->output_ports[i]->seq_handle = m->seq_handle;
584 if (snd_midi_event_new ( ALSA_SEQ_BUFF_SIZE, &(m->output_ports[i]->parser)) < 0) {
585 printError("could not init parser for MIDI OUT port %d", i);
586 m->output_ports[i]->stream_nr = -1;
587 m->output_ports[i]->seq_port_nr = -1;
588 }
589 }
590
591 i++;
592 }
593 }
594
595 m->dev = dev;
596 m->driver = driver;
597 return m;
598 }
599
600 int
601 JackFreebobDriver::freebob_driver_midi_start (freebob_driver_midi_handle_t *m)
602 {
603 assert(m);
604 // start threads
605
606 m->queue_thread_realtime = (m->driver->engine->control->real_time ? 1 : 0);
607 m->queue_thread_priority =
608 m->driver->engine->control->client_priority +
609 FREEBOB_RT_PRIORITY_MIDI_RELATIVE;
610
611 if (m->queue_thread_priority > 98) {
612 m->queue_thread_priority = 98;
613 }
614 if (m->queue_thread_realtime) {
615 printMessage("MIDI threads running with Realtime scheduling, priority %d",
616 m->queue_thread_priority);
617 } else {
618 printMessage("MIDI threads running without Realtime scheduling");
619 }
620
621 if (jack_client_create_thread(NULL, &m->queue_thread, m->queue_thread_priority, m->queue_thread_realtime, freebob_driver_midi_queue_thread, (void *)m)) {
622 printError(" cannot create midi queueing thread");
623 return -1;
624 }
625
626 if (jack_client_create_thread(NULL, &m->dequeue_thread, m->queue_thread_priority, m->queue_thread_realtime, freebob_driver_midi_dequeue_thread, (void *)m)) {
627 printError(" cannot create midi dequeueing thread");
628 return -1;
629 }
630 return 0;
631 }
632
633 int
634 JackFreebobDriver::freebob_driver_midi_stop (freebob_driver_midi_handle_t *m)
635 {
636 assert(m);
637
638 pthread_cancel (m->queue_thread);
639 pthread_join (m->queue_thread, NULL);
640
641 pthread_cancel (m->dequeue_thread);
642 pthread_join (m->dequeue_thread, NULL);
643 return 0;
644 }
645
646 void
647 JackFreebobDriver::freebob_driver_midi_finish (freebob_driver_midi_handle_t *m)
648 {
649 assert(m);
650
651 int i;
652 // TODO: add state info here, if not stopped then stop
653
654 for (i = 0;i < m->nb_input_ports;i++) {
655 free(m->input_ports[i]);
656 }
657 free(m->input_ports);
658
659 for (i = 0;i < m->nb_output_ports;i++) {
660 free(m->output_ports[i]);
661 }
662 free(m->output_ports);
663 free(m);
664 }
665 #endif
666
667 int JackFreebobDriver::Attach()
668 {
669 JackPort* port;
670 jack_port_id_t port_index;
671
672 char buf[REAL_JACK_PORT_NAME_SIZE];
673 char portname[REAL_JACK_PORT_NAME_SIZE];
674 jack_latency_range_t range;
675
676 freebob_driver_t* driver = (freebob_driver_t*)fDriver;
677
678 jack_log("JackFreebobDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
679
680 g_verbose = (fEngineControl->fVerbose ? 1 : 0);
681 driver->device_options.verbose = (fEngineControl->fVerbose ? 1 : 0);
682
683 /* packetizer thread options */
684 driver->device_options.realtime = (fEngineControl->fRealTime ? 1 : 0);
685
686 driver->device_options.packetizer_priority = fEngineControl->fServerPriority +
687 FREEBOB_RT_PRIORITY_PACKETIZER_RELATIVE;
688 if (driver->device_options.packetizer_priority > 98) {
689 driver->device_options.packetizer_priority = 98;
690 }
691
692 // initialize the thread
693 driver->dev = freebob_streaming_init(&driver->device_info, driver->device_options);
694
695 if (!driver->dev) {
696 printError("FREEBOB: Error creating virtual device");
697 return -1;
698 }
699
700 #ifdef FREEBOB_DRIVER_WITH_MIDI
701 driver->midi_handle = freebob_driver_midi_init(driver);
702 if (!driver->midi_handle) {
703 printError("-----------------------------------------------------------");
704 printError("Error creating midi device!");
705 printError("FreeBob will run without MIDI support.");
706 printError("Consult the above error messages to solve the problem. ");
707 printError("-----------------------------------------------------------\n\n");
708 }
709 #endif
710
711 if (driver->device_options.realtime) {
712 printMessage("Streaming thread running with Realtime scheduling, priority %d",
713 driver->device_options.packetizer_priority);
714 } else {
715 printMessage("Streaming thread running without Realtime scheduling");
716 }
717
718 /* ports */
719
720 // capture
721 driver->capture_nchannels = freebob_streaming_get_nb_capture_streams(driver->dev);
722 driver->capture_nchannels_audio = 0;
723
724 for (unsigned int i = 0; i < driver->capture_nchannels; i++) {
725
726 freebob_streaming_get_capture_stream_name(driver->dev, i, portname, sizeof(portname));
727 snprintf(buf, sizeof(buf), "%s:%s", fClientControl.fName, portname);
728
729 if (freebob_streaming_get_capture_stream_type(driver->dev, i) != freebob_stream_type_audio) {
730 printMessage ("Don't register capture port %s", buf);
731 } else {
732 printMessage ("Registering capture port %s", buf);
733
734 if (fEngine->PortRegister(fClientControl.fRefNum, buf,
735 JACK_DEFAULT_AUDIO_TYPE,
736 CaptureDriverFlags,
737 fEngineControl->fBufferSize, &port_index) < 0) {
738 jack_error("driver: cannot register port for %s", buf);
739 return -1;
740 }
741 port = fGraphManager->GetPort(port_index);
742 range.min = range.max = driver->period_size + driver->capture_frame_latency;
743 port->SetLatencyRange(JackCaptureLatency, &range);
744 fCapturePortList[i] = port_index;
745 jack_log("JackFreebobDriver::Attach fCapturePortList[i] %ld ", port_index);
746 driver->capture_nchannels_audio++;
747 }
748 }
749
750 // playback
751 driver->playback_nchannels = freebob_streaming_get_nb_playback_streams(driver->dev);
752 driver->playback_nchannels_audio = 0;
753
754 for (unsigned int i = 0; i < driver->playback_nchannels; i++) {
755
756 freebob_streaming_get_playback_stream_name(driver->dev, i, portname, sizeof(portname));
757 snprintf(buf, sizeof(buf), "%s:%s", fClientControl.fName, portname);
758
759 if (freebob_streaming_get_playback_stream_type(driver->dev, i) != freebob_stream_type_audio) {
760 printMessage ("Don't register playback port %s", buf);
761 } else {
762 printMessage ("Registering playback port %s", buf);
763 if (fEngine->PortRegister(fClientControl.fRefNum, buf,
764 JACK_DEFAULT_AUDIO_TYPE,
765 PlaybackDriverFlags,
766 fEngineControl->fBufferSize, &port_index) < 0) {
767 jack_error("driver: cannot register port for %s", buf);
768 return -1;
769 }
770 port = fGraphManager->GetPort(port_index);
771 // Add one buffer more latency if "async" mode is used...
772 range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency;
773 port->SetLatencyRange(JackPlaybackLatency, &range);
774 fPlaybackPortList[i] = port_index;
775 jack_log("JackFreebobDriver::Attach fPlaybackPortList[i] %ld ", port_index);
776 driver->playback_nchannels_audio++;
777 }
778 }
779
780 fCaptureChannels = driver->capture_nchannels_audio;
781 fPlaybackChannels = driver->playback_nchannels_audio;
782
783 assert(fCaptureChannels < DRIVER_PORT_NUM);
784 assert(fPlaybackChannels < DRIVER_PORT_NUM);
785
786 // this makes no sense...
787 assert(fCaptureChannels + fPlaybackChannels > 0);
788 return 0;
789 }
790
791 int JackFreebobDriver::Detach()
792 {
793 freebob_driver_t* driver = (freebob_driver_t*)fDriver;
794 jack_log("JackFreebobDriver::Detach");
795
796 // finish the libfreebob streaming
797 freebob_streaming_finish(driver->dev);
798 driver->dev = NULL;
799
800 #ifdef FREEBOB_DRIVER_WITH_MIDI
801 if (driver->midi_handle) {
802 freebob_driver_midi_finish(driver->midi_handle);
803 }
804 driver->midi_handle = NULL;
805 #endif
806
807 return JackAudioDriver::Detach(); // Generic JackAudioDriver Detach
808 }
809
810 int JackFreebobDriver::Open(freebob_jack_settings_t *params)
811 {
812 // Generic JackAudioDriver Open
813 if (JackAudioDriver::Open(
814 params->period_size, params->sample_rate,
815 params->playback_ports, params->playback_ports,
816 0, 0, 0, "", "",
817 params->capture_frame_latency, params->playback_frame_latency) != 0) {
818 return -1;
819 }
820
821 fDriver = (jack_driver_t *)freebob_driver_new ((char*)"freebob_pcm", params);
822
823 if (fDriver) {
824 // FreeBoB driver may have changed the in/out values
825 fCaptureChannels = ((freebob_driver_t *)fDriver)->capture_nchannels_audio;
826 fPlaybackChannels = ((freebob_driver_t *)fDriver)->playback_nchannels_audio;
827 return 0;
828 } else {
829 JackAudioDriver::Close();
830 return -1;
831 }
832 }
833
834 int JackFreebobDriver::Close()
835 {
836 // Generic audio driver close
837 int res = JackAudioDriver::Close();
838
839 freebob_driver_delete((freebob_driver_t*)fDriver);
840 return res;
841 }
842
843 int JackFreebobDriver::Start()
844 {
845 int res = JackAudioDriver::Start();
846 if (res >= 0) {
847 res = freebob_driver_start((freebob_driver_t *)fDriver);
848 if (res < 0) {
849 JackAudioDriver::Stop();
850 }
851 }
852 return res;
853 }
854
855 int JackFreebobDriver::Stop()
856 {
857 int res = freebob_driver_stop((freebob_driver_t *)fDriver);
858 if (JackAudioDriver::Stop() < 0) {
859 res = -1;
860 }
861 return res;
862 }
863
864 int JackFreebobDriver::Read()
865 {
866 printEnter();
867
868 /* Taken from freebob_driver_run_cycle */
869 freebob_driver_t* driver = (freebob_driver_t*)fDriver;
870 int wait_status = 0;
871 fDelayedUsecs = 0.f;
872
873 retry:
874
875 jack_nframes_t nframes = freebob_driver_wait (driver, -1, &wait_status,
876 &fDelayedUsecs);
877
878 if ((wait_status < 0)) {
879 printError( "wait status < 0! (= %d)", wait_status);
880 return -1;
881 }
882
883 if (nframes == 0) {
884 /* we detected an xrun and restarted: notify
885 * clients about the delay.
886 */
887 jack_log("FreeBoB XRun");
888 NotifyXRun(fBeginDateUst, fDelayedUsecs);
889 goto retry; /* recoverable error*/
890 }
891
892 if (nframes != fEngineControl->fBufferSize)
893 jack_log("JackFreebobDriver::Read warning nframes = %ld", nframes);
894
895 // Has to be done before read
896 JackDriver::CycleIncTime();
897
898 printExit();
899 return freebob_driver_read((freebob_driver_t *)fDriver, fEngineControl->fBufferSize);
900 }
901
902 int JackFreebobDriver::Write()
903 {
904 printEnter();
905 int res = freebob_driver_write((freebob_driver_t *)fDriver, fEngineControl->fBufferSize);
906 printExit();
907 return res;
908 }
909
910 void
911 JackFreebobDriver::jack_driver_init (jack_driver_t *driver)
912 {
913 memset (driver, 0, sizeof (*driver));
914
915 driver->attach = 0;
916 driver->detach = 0;
917 driver->write = 0;
918 driver->read = 0;
919 driver->null_cycle = 0;
920 driver->bufsize = 0;
921 driver->start = 0;
922 driver->stop = 0;
923 }
924
925 void
926 JackFreebobDriver::jack_driver_nt_init (jack_driver_nt_t * driver)
927 {
928 memset (driver, 0, sizeof (*driver));
929
930 jack_driver_init ((jack_driver_t *) driver);
931
932 driver->attach = 0;
933 driver->detach = 0;
934 driver->bufsize = 0;
935 driver->stop = 0;
936 driver->start = 0;
937
938 driver->nt_bufsize = 0;
939 driver->nt_start = 0;
940 driver->nt_stop = 0;
941 driver->nt_attach = 0;
942 driver->nt_detach = 0;
943 driver->nt_run_cycle = 0;
944 }
945
946 } // end of namespace
947
948 #ifdef __cplusplus
949 extern "C"
950 {
951 #endif
952
953 const jack_driver_desc_t *
954 driver_get_descriptor () {
955 jack_driver_desc_t * desc;
956 jack_driver_desc_filler_t filler;
957 jack_driver_param_value_t value;
958
959 desc = jack_driver_descriptor_construct("freebob", JackDriverMaster, "Linux FreeBob API based audio backend", &filler);
960
961 strcpy(value.str, "hw:0");
962 jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "The FireWire device to use. Format is: 'hw:port[,node]'.", NULL);
963
964 value.ui = 1024;
965 jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
966
967 value.ui = 3;
968 jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of periods of playback latency", NULL);
969
970 value.ui = 48000U;
971 jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
972
973 value.i = 0;
974 jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamBool, &value, NULL, "Provide capture ports.", NULL);
975 jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamBool, &value, NULL, "Provide playback ports.", NULL);
976
977 value.i = 1;
978 jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports.", NULL);
979
980 value.ui = 0;
981 jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency (frames)", NULL);
982 jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency (frames)", NULL);
983
984 value.ui = 0;
985 jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "Number of input channels to provide (note: currently ignored)", NULL);
986 jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "Number of output channels to provide (note: currently ignored)", NULL);
987
988 return desc;
989 }
990
991 Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) {
992 unsigned int port = 0;
993 unsigned int node_id = -1;
994 int nbitems;
995
996 const JSList * node;
997 const jack_driver_param_t * param;
998
999 freebob_jack_settings_t cmlparams;
1000
1001 const char *device_name = "hw:0";
1002
1003 cmlparams.period_size_set = 0;
1004 cmlparams.sample_rate_set = 0;
1005 cmlparams.buffer_size_set = 0;
1006 cmlparams.port_set = 0;
1007 cmlparams.node_id_set = 0;
1008
1009 /* default values */
1010 cmlparams.period_size = 1024;
1011 cmlparams.sample_rate = 48000;
1012 cmlparams.buffer_size = 3;
1013 cmlparams.port = 0;
1014 cmlparams.node_id = -1;
1015 cmlparams.playback_ports = 0;
1016 cmlparams.capture_ports = 0;
1017 cmlparams.playback_frame_latency = 0;
1018 cmlparams.capture_frame_latency = 0;
1019
1020 for (node = params; node; node = jack_slist_next (node)) {
1021 param = (jack_driver_param_t *) node->data;
1022
1023 switch (param->character) {
1024 case 'd':
1025 device_name = param->value.str;
1026 break;
1027 case 'p':
1028 cmlparams.period_size = param->value.ui;
1029 cmlparams.period_size_set = 1;
1030 break;
1031 case 'n':
1032 cmlparams.buffer_size = param->value.ui;
1033 cmlparams.buffer_size_set = 1;
1034 break;
1035 case 'r':
1036 cmlparams.sample_rate = param->value.ui;
1037 cmlparams.sample_rate_set = 1;
1038 break;
1039 case 'C':
1040 cmlparams.capture_ports = 1;
1041 break;
1042 case 'P':
1043 cmlparams.playback_ports = 1;
1044 break;
1045 case 'D':
1046 cmlparams.capture_ports = 1;
1047 cmlparams.playback_ports = 1;
1048 break;
1049 case 'I':
1050 cmlparams.capture_frame_latency = param->value.ui;
1051 break;
1052 case 'O':
1053 cmlparams.playback_frame_latency = param->value.ui;
1054 break;
1055 // ignore these for now
1056 case 'i':
1057 break;
1058 case 'o':
1059 break;
1060 }
1061 }
1062
1063 /* duplex is the default */
1064 if (!cmlparams.playback_ports && !cmlparams.capture_ports) {
1065 cmlparams.playback_ports = TRUE;
1066 cmlparams.capture_ports = TRUE;
1067 }
1068
1069 nbitems = sscanf(device_name, "hw:%u,%u", &port, &node_id);
1070 if (nbitems < 2) {
1071 nbitems = sscanf(device_name, "hw:%u", &port);
1072
1073 if (nbitems < 1) {
1074 printError("device (-d) argument not valid\n");
1075 return NULL;
1076 } else {
1077 cmlparams.port = port;
1078 cmlparams.port_set = 1;
1079
1080 cmlparams.node_id = -1;
1081 cmlparams.node_id_set = 0;
1082 }
1083 } else {
1084 cmlparams.port = port;
1085 cmlparams.port_set = 1;
1086
1087 cmlparams.node_id = node_id;
1088 cmlparams.node_id_set = 1;
1089 }
1090
1091 jack_error("Freebob using Firewire port %d, node %d", cmlparams.port, cmlparams.node_id);
1092
1093 Jack::JackFreebobDriver* freebob_driver = new Jack::JackFreebobDriver("system", "freebob_pcm", engine, table);
1094 Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(freebob_driver);
1095 // Special open for FreeBoB driver...
1096 if (freebob_driver->Open(&cmlparams) == 0) {
1097 return threaded_driver;
1098 } else {
1099 delete threaded_driver; // Delete the decorated driver
1100 return NULL;
1101 }
1102 }
1103
1104 #ifdef __cplusplus
1105 }
1106 #endif
1107
1108
Jack::JackThreadedDriver
The base class for threaded drivers using a "decorator" pattern. Threaded drivers are used with block...
Definition: JackThreadedDriver.h:34
Jack::JackLockedEngine
Locked Engine, access to methods is serialized using a mutex.
Definition: JackLockedEngine.h:78
jack_driver_param_value_t
Definition: driver_interface.h:64
Jack::JackPosixSemaphore
Inter process synchronization using POSIX semaphore.
Definition: JackPosixSemaphore.h:36
_jack_driver_nt
Definition: driver.h:275
Jack::JackFreebobDriver
The FreeBoB driver.
Definition: JackFreebobDriver.h:38
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
_jack_latency_range::min
jack_nframes_t min
Definition: types.h:270
_jack_driver
Definition: driver.h:87
_jack_latency_range
Definition: types.h:265
_jack_latency_range::max
jack_nframes_t max
Definition: types.h:274
_freebob_jack_settings
Definition: freebob_driver.h:134
_freebob_driver
Definition: freebob_driver.h:199
jack_client_create_thread
LIB_EXPORT int jack_client_create_thread(jack_client_t *client, jack_native_thread_t *thread, int priority, int realtime, thread_routine routine, void *arg)
Definition: JackAPI.cpp:1745
jack_driver_desc_filler_t
Definition: driver_interface.h:142
Jack::JackDriverClientInterface
The base interface for drivers clients.
Definition: JackDriver.h:114
jack_driver_param_t
Definition: driver_interface.h:125
_JSList
Definition: linux/alsa/jslist.h:35
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
jack_driver_desc_t
Definition: driver_interface.h:132