Jack2  1.9.9
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 
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;
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 
The base class for threaded drivers using a &quot;decorator&quot; pattern. Threaded drivers are used with block...
Inter process synchronization using using Mach semaphore.
Locked Engine, access to methods is serialized using a mutex.
The FreeBoB driver.
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:91
jack_nframes_t min
Definition: types.h:268
jack_nframes_t max
Definition: types.h:272
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:1695
The base interface for drivers clients.
Definition: JackDriver.h:122
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:107