Jack2  1.9.10
JackFreebobDriver.cpp
00001 /*
00002 Copyright (C) 2001 Paul Davis
00003 Copyright (C) 2004 Grame
00004 Copyright (C) 2007 Pieter Palmers
00005 
00006 This program is free software; you can redistribute it and/or modify
00007 it under the terms of the GNU General Public License as published by
00008 the Free Software Foundation; either version 2 of the License, or
00009 (at your option) any later version.
00010 
00011 This program is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License
00017 along with this program; if not, write to the Free Software
00018 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 
00020 */
00021 
00022 #include <iostream>
00023 #include <unistd.h>
00024 #include <math.h>
00025 #include <stdio.h>
00026 #include <memory.h>
00027 #include <unistd.h>
00028 #include <stdlib.h>
00029 #include <errno.h>
00030 #include <stdarg.h>
00031 #include <signal.h>
00032 #include <sys/types.h>
00033 #include <sys/time.h>
00034 #include <regex.h>
00035 #include <string.h>
00036 
00037 #include "JackFreebobDriver.h"
00038 #include "JackEngineControl.h"
00039 #include "JackClientControl.h"
00040 #include "JackPort.h"
00041 #include "JackGraphManager.h"
00042 #include "JackLockedEngine.h"
00043 
00044 namespace Jack
00045 {
00046 
00047 #define jack_get_microseconds GetMicroSeconds
00048 
00049 #define SAMPLE_MAX_24BIT  8388608.0f
00050 #define SAMPLE_MAX_16BIT  32768.0f
00051 
00052 int
00053 JackFreebobDriver::freebob_driver_read (freebob_driver_t * driver, jack_nframes_t nframes)
00054 {
00055     jack_default_audio_sample_t* buf = NULL;
00056     freebob_sample_t nullbuffer[nframes];
00057     void *addr_of_nullbuffer = (void *)nullbuffer;
00058 
00059     freebob_streaming_stream_type stream_type;
00060 
00061     printEnter();
00062 
00063     // make sure all buffers have a valid buffer if not connected
00064     for (unsigned int i = 0; i < driver->capture_nchannels; i++) {
00065         stream_type = freebob_streaming_get_playback_stream_type(driver->dev, i);
00066         if (stream_type == freebob_stream_type_audio) {
00067             freebob_streaming_set_playback_stream_buffer(driver->dev, i,
00068                     (char *)(nullbuffer), freebob_buffer_type_float);
00069         } else if (stream_type == freebob_stream_type_midi) {
00070             // these should be read/written with the per-stream functions
00071         } else {        // empty other buffers without doing something with them
00072             freebob_streaming_set_playback_stream_buffer(driver->dev, i,
00073                     (char *)(nullbuffer), freebob_buffer_type_uint24);
00074         }
00075     }
00076 
00077     for (int i = 0; i < fCaptureChannels; i++) {
00078         stream_type = freebob_streaming_get_capture_stream_type(driver->dev, i);
00079         if (stream_type == freebob_stream_type_audio) {
00080 
00081             if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) {
00082                 buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[i],  nframes);
00083 
00084                 if (!buf) {
00085                     buf = (jack_default_audio_sample_t *)addr_of_nullbuffer;
00086                 }
00087 
00088                 freebob_streaming_set_capture_stream_buffer(driver->dev, i, (char *)(buf), freebob_buffer_type_float);
00089             }
00090         } else if (stream_type == freebob_stream_type_midi) {
00091             // these should be read/written with the per-stream functions
00092         } else {        // empty other buffers without doing something with them
00093             freebob_streaming_set_capture_stream_buffer(driver->dev, i, (char *)(nullbuffer), freebob_buffer_type_uint24);
00094         }
00095 
00096     }
00097 
00098     // now transfer the buffers
00099     freebob_streaming_transfer_capture_buffers(driver->dev);
00100     printExit();
00101     return 0;
00102 }
00103 
00104 int
00105 JackFreebobDriver::freebob_driver_write (freebob_driver_t * driver, jack_nframes_t nframes)
00106 {
00107     jack_default_audio_sample_t* buf = NULL;
00108 
00109     freebob_streaming_stream_type stream_type;
00110 
00111     freebob_sample_t nullbuffer[nframes];
00112     void *addr_of_nullbuffer = (void*)nullbuffer;
00113 
00114     memset(&nullbuffer, 0, nframes*sizeof(freebob_sample_t));
00115 
00116     printEnter();
00117     driver->process_count++;
00118     assert(driver->dev);
00119 
00120     // make sure all buffers output silence if not connected
00121     for (unsigned int i = 0; i < driver->playback_nchannels; i++) {
00122         stream_type = freebob_streaming_get_playback_stream_type(driver->dev, i);
00123         if (stream_type == freebob_stream_type_audio) {
00124             freebob_streaming_set_playback_stream_buffer(driver->dev, i,
00125                     (char *)(nullbuffer), freebob_buffer_type_float);
00126         } else if (stream_type == freebob_stream_type_midi) {
00127             // these should be read/written with the per-stream functions
00128         } else { // empty other buffers without doing something with them
00129             freebob_streaming_set_playback_stream_buffer(driver->dev, i,
00130                     (char *)(nullbuffer), freebob_buffer_type_uint24);
00131         }
00132     }
00133 
00134     for (int i = 0; i < fPlaybackChannels; i++) {
00135         stream_type = freebob_streaming_get_playback_stream_type(driver->dev, i);
00136         if (stream_type == freebob_stream_type_audio) {
00137             // Ouput ports
00138             if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
00139                 buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[i], nframes);
00140                 if (!buf) {
00141                     buf = (jack_default_audio_sample_t *)addr_of_nullbuffer;
00142                 }
00143                 freebob_streaming_set_playback_stream_buffer(driver->dev, i, (char *)(buf), freebob_buffer_type_float);
00144             }
00145         }
00146     }
00147 
00148     freebob_streaming_transfer_playback_buffers(driver->dev);
00149     printExit();
00150     return 0;
00151 }
00152 
00153 jack_nframes_t
00154 JackFreebobDriver::freebob_driver_wait (freebob_driver_t *driver, int extra_fd, int *status,
00155                                         float *delayed_usecs)
00156 {
00157     int nframes;
00158     jack_time_t wait_enter;
00159     jack_time_t wait_ret;
00160 
00161     printEnter();
00162 
00163     wait_enter = jack_get_microseconds ();
00164     if (wait_enter > driver->wait_next) {
00165         /*
00166                 * This processing cycle was delayed past the
00167                 * next due interrupt!  Do not account this as
00168                 * a wakeup delay:
00169                 */
00170         driver->wait_next = 0;
00171         driver->wait_late++;
00172     }
00173 // *status = -2; interrupt
00174 // *status = -3; timeout
00175 // *status = -4; extra FD
00176 
00177     nframes = freebob_streaming_wait(driver->dev);
00178 
00179     wait_ret = jack_get_microseconds ();
00180 
00181     if (driver->wait_next && wait_ret > driver->wait_next) {
00182         *delayed_usecs = wait_ret - driver->wait_next;
00183     }
00184     driver->wait_last = wait_ret;
00185     driver->wait_next = wait_ret + driver->period_usecs;
00186 //      driver->engine->transport_cycle_start (driver->engine, wait_ret);
00187 
00188     if (nframes < 0) {
00189         *status = 0;
00190         return 0;
00191     }
00192 
00193     *status = 0;
00194     fBeginDateUst = wait_ret;
00195 
00196     // FIXME: this should do something more usefull
00197     *delayed_usecs = 0;
00198     printExit();
00199     return nframes - nframes % driver->period_size;
00200 }
00201 
00202 int
00203 JackFreebobDriver::freebob_driver_start (freebob_driver_t *driver)
00204 {
00205     int retval = 0;
00206 
00207 #ifdef FREEBOB_DRIVER_WITH_MIDI
00208     if (driver->midi_handle) {
00209         if ((retval = freebob_driver_midi_start(driver->midi_handle))) {
00210             printError("Could not start MIDI threads");
00211             return retval;
00212         }
00213     }
00214 #endif
00215 
00216     if ((retval = freebob_streaming_start(driver->dev))) {
00217         printError("Could not start streaming threads");
00218 #ifdef FREEBOB_DRIVER_WITH_MIDI
00219         if (driver->midi_handle) {
00220             freebob_driver_midi_stop(driver->midi_handle);
00221         }
00222 #endif
00223         return retval;
00224     }
00225 
00226     return 0;
00227 }
00228 
00229 int
00230 JackFreebobDriver::freebob_driver_stop (freebob_driver_t *driver)
00231 {
00232     int retval = 0;
00233 
00234 #ifdef FREEBOB_DRIVER_WITH_MIDI
00235     if (driver->midi_handle) {
00236         if ((retval = freebob_driver_midi_stop(driver->midi_handle))) {
00237             printError("Could not stop MIDI threads");
00238             return retval;
00239         }
00240     }
00241 #endif
00242     if ((retval = freebob_streaming_stop(driver->dev))) {
00243         printError("Could not stop streaming threads");
00244         return retval;
00245     }
00246 
00247     return 0;
00248 }
00249 
00250 int
00251 JackFreebobDriver::freebob_driver_restart (freebob_driver_t *driver)
00252 {
00253     if (Stop())
00254         return -1;
00255     return Start();
00256 }
00257 
00258 int
00259 JackFreebobDriver::SetBufferSize (jack_nframes_t nframes)
00260 {
00261     printError("Buffer size change requested but not supported!!!");
00262 
00263     /*
00264     driver->period_size = nframes;
00265     driver->period_usecs =
00266         (jack_time_t) floor ((((float) nframes) / driver->sample_rate)
00267                              * 1000000.0f);
00268     */
00269 
00270     /* tell the engine to change its buffer size */
00271     //driver->engine->set_buffer_size (driver->engine, nframes);
00272 
00273     return -1; // unsupported
00274 }
00275 
00276 typedef void (*JackDriverFinishFunction) (jack_driver_t *);
00277 
00278 freebob_driver_t *
00279 JackFreebobDriver::freebob_driver_new (char *name,
00280                                        freebob_jack_settings_t *params)
00281 {
00282     freebob_driver_t *driver;
00283 
00284     assert(params);
00285 
00286     if (freebob_get_api_version() != 1) {
00287         printMessage("Incompatible libfreebob version! (%s)", freebob_get_version());
00288         return NULL;
00289     }
00290 
00291     printMessage("Starting Freebob backend (%s)", freebob_get_version());
00292 
00293     driver = (freebob_driver_t*)calloc (1, sizeof (freebob_driver_t));
00294 
00295     /* Setup the jack interfaces */
00296     jack_driver_nt_init ((jack_driver_nt_t *) driver);
00297 
00298     /*  driver->nt_attach    = (JackDriverNTAttachFunction)   freebob_driver_attach;
00299         driver->nt_detach    = (JackDriverNTDetachFunction)   freebob_driver_detach;
00300         driver->nt_start     = (JackDriverNTStartFunction)    freebob_driver_start;
00301         driver->nt_stop      = (JackDriverNTStopFunction)     freebob_driver_stop;
00302         driver->nt_run_cycle = (JackDriverNTRunCycleFunction) freebob_driver_run_cycle;
00303         driver->null_cycle   = (JackDriverNullCycleFunction)  freebob_driver_null_cycle;
00304         driver->write        = (JackDriverReadFunction)       freebob_driver_write;
00305         driver->read         = (JackDriverReadFunction)       freebob_driver_read;
00306         driver->nt_bufsize   = (JackDriverNTBufSizeFunction)  freebob_driver_bufsize;
00307     */
00308 
00309     /* copy command line parameter contents to the driver structure */
00310     memcpy(&driver->settings, params, sizeof(freebob_jack_settings_t));
00311 
00312     /* prepare all parameters */
00313     driver->sample_rate = params->sample_rate;
00314     driver->period_size = params->period_size;
00315     fBeginDateUst = 0;
00316 
00317     driver->period_usecs =
00318         (jack_time_t) floor ((((float) driver->period_size) * 1000000.0f) / driver->sample_rate);
00319 
00320 //      driver->client = client;
00321     driver->engine = NULL;
00322 
00323     memset(&driver->device_options, 0, sizeof(driver->device_options));
00324     driver->device_options.sample_rate = params->sample_rate;
00325     driver->device_options.period_size = params->period_size;
00326     driver->device_options.nb_buffers = params->buffer_size;
00327     driver->device_options.node_id = params->node_id;
00328     driver->device_options.port = params->port;
00329     driver->capture_frame_latency = params->capture_frame_latency;
00330     driver->playback_frame_latency = params->playback_frame_latency;
00331 
00332     if (!params->capture_ports) {
00333         driver->device_options.directions |= FREEBOB_IGNORE_CAPTURE;
00334     }
00335 
00336     if (!params->playback_ports) {
00337         driver->device_options.directions |= FREEBOB_IGNORE_PLAYBACK;
00338     }
00339 
00340     debugPrint(DEBUG_LEVEL_STARTUP, " Driver compiled on %s %s", __DATE__, __TIME__);
00341     debugPrint(DEBUG_LEVEL_STARTUP, " Created driver %s", name);
00342     debugPrint(DEBUG_LEVEL_STARTUP, "            period_size: %d", driver->period_size);
00343     debugPrint(DEBUG_LEVEL_STARTUP, "            period_usecs: %d", driver->period_usecs);
00344     debugPrint(DEBUG_LEVEL_STARTUP, "            sample rate: %d", driver->sample_rate);
00345 
00346     return (freebob_driver_t *) driver;
00347 }
00348 
00349 void
00350 JackFreebobDriver::freebob_driver_delete (freebob_driver_t *driver)
00351 {
00352     free (driver);
00353 }
00354 
00355 #ifdef FREEBOB_DRIVER_WITH_MIDI
00356 /*
00357  * MIDI support
00358  */
00359 
00360 // the thread that will queue the midi events from the seq to the stream buffers
00361 
00362 void *
00363 JackFreebobDriver::freebob_driver_midi_queue_thread(void *arg)
00364 {
00365     freebob_driver_midi_handle_t *m = (freebob_driver_midi_handle_t *)arg;
00366     assert(m);
00367     snd_seq_event_t *ev;
00368     unsigned char work_buffer[MIDI_TRANSMIT_BUFFER_SIZE];
00369     int bytes_to_send;
00370     int b;
00371     int i;
00372 
00373     printMessage("MIDI queue thread started");
00374 
00375     while (1) {
00376         // get next event, if one is present
00377         while ((snd_seq_event_input(m->seq_handle, &ev) > 0)) {
00378             // get the port this event is originated from
00379             freebob_midi_port_t *port = NULL;
00380             for (i = 0;i < m->nb_output_ports;i++) {
00381                 if (m->output_ports[i]->seq_port_nr == ev->dest.port) {
00382                     port = m->output_ports[i];
00383                     break;
00384                 }
00385             }
00386 
00387             if (!port) {
00388                 printError(" Could not find target port for event: dst=%d src=%d", ev->dest.port, ev->source.port);
00389                 break;
00390             }
00391 
00392             // decode it to the work buffer
00393             if ((bytes_to_send = snd_midi_event_decode ( port->parser,
00394                                  work_buffer,
00395                                  MIDI_TRANSMIT_BUFFER_SIZE,
00396                                  ev)) < 0) { // failed
00397                 printError(" Error decoding event for port %d (errcode=%d)", port->seq_port_nr, bytes_to_send);
00398                 bytes_to_send = 0;
00399                 //return -1;
00400             }
00401 
00402             for (b = 0;b < bytes_to_send;b++) {
00403                 freebob_sample_t tmp_event = work_buffer[b];
00404                 if (freebob_streaming_write(m->dev, port->stream_nr, &tmp_event, 1) < 1) {
00405                     printError(" Midi send buffer overrun");
00406                 }
00407             }
00408         }
00409 
00410         // sleep for some time
00411         usleep(MIDI_THREAD_SLEEP_TIME_USECS);
00412     }
00413     return NULL;
00414 }
00415 
00416 // the dequeue thread (maybe we need one thread per stream)
00417 void *
00418 JackFreebobDriver::freebob_driver_midi_dequeue_thread (void *arg)
00419 {
00420     freebob_driver_midi_handle_t *m = (freebob_driver_midi_handle_t *)arg;
00421 
00422     int i;
00423     int s;
00424     int samples_read;
00425 
00426     assert(m);
00427 
00428     while (1) {
00429         // read incoming events
00430 
00431         for (i = 0;i < m->nb_input_ports;i++) {
00432             unsigned int buff[64];
00433             freebob_midi_port_t *port = m->input_ports[i];
00434             if (!port) {
00435                 printError(" something went wrong when setting up the midi input port map (%d)", i);
00436             }
00437 
00438             do {
00439                 samples_read = freebob_streaming_read(m->dev, port->stream_nr, buff, 64);
00440 
00441                 for (s = 0;s < samples_read;s++) {
00442                     unsigned int *byte = (buff + s) ;
00443                     snd_seq_event_t ev;
00444                     if ((snd_midi_event_encode_byte(port->parser, (*byte) & 0xFF, &ev)) > 0) {
00445                         // a midi message is complete, send it out to ALSA
00446                         snd_seq_ev_set_subs(&ev);
00447                         snd_seq_ev_set_direct(&ev);
00448                         snd_seq_ev_set_source(&ev, port->seq_port_nr);
00449                         snd_seq_event_output_direct(port->seq_handle, &ev);
00450                     }
00451                 }
00452             } while (samples_read > 0);
00453         }
00454 
00455         // sleep for some time
00456         usleep(MIDI_THREAD_SLEEP_TIME_USECS);
00457     }
00458     return NULL;
00459 }
00460 
00461 freebob_driver_midi_handle_t *
00462 JackFreebobDriver::freebob_driver_midi_init(freebob_driver_t *driver)
00463 {
00464     char buf[256];
00465     channel_t chn;
00466     int nchannels;
00467     int i = 0;
00468 
00469     freebob_device_t *dev = driver->dev;
00470     assert(dev);
00471 
00472     freebob_driver_midi_handle_t *m = calloc(1, sizeof(freebob_driver_midi_handle_t));
00473     if (!m) {
00474         printError("not enough memory to create midi structure");
00475         return NULL;
00476     }
00477 
00478     if (snd_seq_open(&m->seq_handle, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK) < 0) {
00479         printError("Error opening ALSA sequencer.");
00480         free(m);
00481         return NULL;
00482     }
00483 
00484     snd_seq_set_client_name(m->seq_handle, "FreeBoB Jack MIDI");
00485 
00486     // find out the number of midi in/out ports we need to setup
00487     nchannels = freebob_streaming_get_nb_capture_streams(dev);
00488     m->nb_input_ports = 0;
00489 
00490     for (chn = 0; chn < nchannels; chn++) {
00491         if (freebob_streaming_get_capture_stream_type(dev, chn) == freebob_stream_type_midi) {
00492             m->nb_input_ports++;
00493         }
00494     }
00495 
00496     m->input_ports = calloc(m->nb_input_ports, sizeof(freebob_midi_port_t *));
00497     if (!m->input_ports) {
00498         printError("not enough memory to create midi structure");
00499         free(m);
00500         return NULL;
00501     }
00502 
00503     i = 0;
00504     for (chn = 0; chn < nchannels; chn++) {
00505         if (freebob_streaming_get_capture_stream_type(dev, chn) == freebob_stream_type_midi) {
00506             m->input_ports[i] = calloc(1, sizeof(freebob_midi_port_t));
00507             if (!m->input_ports[i]) {
00508                 // fixme
00509                 printError("Could not allocate memory for seq port");
00510                 continue;
00511             }
00512 
00513             freebob_streaming_get_capture_stream_name(dev, chn, buf, sizeof(buf));
00514             printMessage("Register MIDI IN port %s", buf);
00515 
00516             m->input_ports[i]->seq_port_nr = snd_seq_create_simple_port(m->seq_handle, buf,
00517                                              SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,
00518                                              SND_SEQ_PORT_TYPE_MIDI_GENERIC);
00519 
00520             if (m->input_ports[i]->seq_port_nr < 0) {
00521                 printError("Could not create seq port");
00522                 m->input_ports[i]->stream_nr = -1;
00523                 m->input_ports[i]->seq_port_nr = -1;
00524             } else {
00525                 m->input_ports[i]->stream_nr = chn;
00526                 m->input_ports[i]->seq_handle = m->seq_handle;
00527                 if (snd_midi_event_new  ( ALSA_SEQ_BUFF_SIZE, &(m->input_ports[i]->parser)) < 0) {
00528                     printError("could not init parser for MIDI IN port %d", i);
00529                     m->input_ports[i]->stream_nr = -1;
00530                     m->input_ports[i]->seq_port_nr = -1;
00531                 }
00532             }
00533 
00534             i++;
00535         }
00536     }
00537 
00538     // playback
00539     nchannels = freebob_streaming_get_nb_playback_streams(dev);
00540 
00541     m->nb_output_ports = 0;
00542 
00543     for (chn = 0; chn < nchannels; chn++) {
00544         if (freebob_streaming_get_playback_stream_type(dev, chn) == freebob_stream_type_midi) {
00545             m->nb_output_ports++;
00546         }
00547     }
00548 
00549     m->output_ports = calloc(m->nb_output_ports, sizeof(freebob_midi_port_t *));
00550     if (!m->output_ports) {
00551         printError("not enough memory to create midi structure");
00552         for (i = 0; i < m->nb_input_ports; i++) {
00553             free(m->input_ports[i]);
00554         }
00555         free(m->input_ports);
00556         free(m);
00557         return NULL;
00558     }
00559 
00560     i = 0;
00561     for (chn = 0; chn < nchannels; chn++) {
00562         if (freebob_streaming_get_playback_stream_type(dev, chn) == freebob_stream_type_midi) {
00563             m->output_ports[i] = calloc(1, sizeof(freebob_midi_port_t));
00564             if (!m->output_ports[i]) {
00565                 // fixme
00566                 printError("Could not allocate memory for seq port");
00567                 continue;
00568             }
00569 
00570             freebob_streaming_get_playback_stream_name(dev, chn, buf, sizeof(buf));
00571             printMessage("Register MIDI OUT port %s", buf);
00572 
00573             m->output_ports[i]->seq_port_nr = snd_seq_create_simple_port(m->seq_handle, buf,
00574                                               SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
00575                                               SND_SEQ_PORT_TYPE_MIDI_GENERIC);
00576 
00577             if (m->output_ports[i]->seq_port_nr < 0) {
00578                 printError("Could not create seq port");
00579                 m->output_ports[i]->stream_nr = -1;
00580                 m->output_ports[i]->seq_port_nr = -1;
00581             } else {
00582                 m->output_ports[i]->stream_nr = chn;
00583                 m->output_ports[i]->seq_handle = m->seq_handle;
00584                 if (snd_midi_event_new  ( ALSA_SEQ_BUFF_SIZE, &(m->output_ports[i]->parser)) < 0) {
00585                     printError("could not init parser for MIDI OUT port %d", i);
00586                     m->output_ports[i]->stream_nr = -1;
00587                     m->output_ports[i]->seq_port_nr = -1;
00588                 }
00589             }
00590 
00591             i++;
00592         }
00593     }
00594 
00595     m->dev = dev;
00596     m->driver = driver;
00597     return m;
00598 }
00599 
00600 int
00601 JackFreebobDriver::freebob_driver_midi_start (freebob_driver_midi_handle_t *m)
00602 {
00603     assert(m);
00604     // start threads
00605 
00606     m->queue_thread_realtime = (m->driver->engine->control->real_time ? 1 : 0);
00607     m->queue_thread_priority =
00608         m->driver->engine->control->client_priority +
00609         FREEBOB_RT_PRIORITY_MIDI_RELATIVE;
00610 
00611     if (m->queue_thread_priority > 98) {
00612         m->queue_thread_priority = 98;
00613     }
00614     if (m->queue_thread_realtime) {
00615         printMessage("MIDI threads running with Realtime scheduling, priority %d",
00616                      m->queue_thread_priority);
00617     } else {
00618         printMessage("MIDI threads running without Realtime scheduling");
00619     }
00620 
00621     if (jack_client_create_thread(NULL, &m->queue_thread, m->queue_thread_priority, m->queue_thread_realtime, freebob_driver_midi_queue_thread, (void *)m)) {
00622         printError(" cannot create midi queueing thread");
00623         return -1;
00624     }
00625 
00626     if (jack_client_create_thread(NULL, &m->dequeue_thread, m->queue_thread_priority, m->queue_thread_realtime, freebob_driver_midi_dequeue_thread, (void *)m)) {
00627         printError(" cannot create midi dequeueing thread");
00628         return -1;
00629     }
00630     return 0;
00631 }
00632 
00633 int
00634 JackFreebobDriver::freebob_driver_midi_stop (freebob_driver_midi_handle_t *m)
00635 {
00636     assert(m);
00637 
00638     pthread_cancel (m->queue_thread);
00639     pthread_join (m->queue_thread, NULL);
00640 
00641     pthread_cancel (m->dequeue_thread);
00642     pthread_join (m->dequeue_thread, NULL);
00643     return 0;
00644 }
00645 
00646 void
00647 JackFreebobDriver::freebob_driver_midi_finish (freebob_driver_midi_handle_t *m)
00648 {
00649     assert(m);
00650 
00651     int i;
00652     // TODO: add state info here, if not stopped then stop
00653 
00654     for (i = 0;i < m->nb_input_ports;i++) {
00655         free(m->input_ports[i]);
00656     }
00657     free(m->input_ports);
00658 
00659     for (i = 0;i < m->nb_output_ports;i++) {
00660         free(m->output_ports[i]);
00661     }
00662     free(m->output_ports);
00663     free(m);
00664 }
00665 #endif
00666 
00667 int JackFreebobDriver::Attach()
00668 {
00669     JackPort* port;
00670     jack_port_id_t port_index;
00671 
00672     char buf[REAL_JACK_PORT_NAME_SIZE];
00673     char portname[REAL_JACK_PORT_NAME_SIZE];
00674     jack_latency_range_t range;
00675 
00676     freebob_driver_t* driver = (freebob_driver_t*)fDriver;
00677 
00678     jack_log("JackFreebobDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
00679 
00680     g_verbose = (fEngineControl->fVerbose ? 1 : 0);
00681     driver->device_options.verbose = (fEngineControl->fVerbose ? 1 : 0);
00682 
00683     /* packetizer thread options */
00684     driver->device_options.realtime = (fEngineControl->fRealTime ? 1 : 0);
00685 
00686     driver->device_options.packetizer_priority = fEngineControl->fServerPriority +
00687             FREEBOB_RT_PRIORITY_PACKETIZER_RELATIVE;
00688     if (driver->device_options.packetizer_priority > 98) {
00689         driver->device_options.packetizer_priority = 98;
00690     }
00691 
00692     // initialize the thread
00693     driver->dev = freebob_streaming_init(&driver->device_info, driver->device_options);
00694 
00695     if (!driver->dev) {
00696         printError("FREEBOB: Error creating virtual device");
00697         return -1;
00698     }
00699 
00700 #ifdef FREEBOB_DRIVER_WITH_MIDI
00701     driver->midi_handle = freebob_driver_midi_init(driver);
00702     if (!driver->midi_handle) {
00703         printError("-----------------------------------------------------------");
00704         printError("Error creating midi device!");
00705         printError("FreeBob will run without MIDI support.");
00706         printError("Consult the above error messages to solve the problem. ");
00707         printError("-----------------------------------------------------------\n\n");
00708     }
00709 #endif
00710 
00711     if (driver->device_options.realtime) {
00712         printMessage("Streaming thread running with Realtime scheduling, priority %d",
00713                      driver->device_options.packetizer_priority);
00714     } else {
00715         printMessage("Streaming thread running without Realtime scheduling");
00716     }
00717 
00718     /* ports */
00719 
00720     // capture
00721     driver->capture_nchannels = freebob_streaming_get_nb_capture_streams(driver->dev);
00722     driver->capture_nchannels_audio = 0;
00723 
00724     for (unsigned int i = 0; i < driver->capture_nchannels; i++) {
00725 
00726         freebob_streaming_get_capture_stream_name(driver->dev, i, portname, sizeof(portname));
00727         snprintf(buf, sizeof(buf), "%s:%s", fClientControl.fName, portname);
00728 
00729         if (freebob_streaming_get_capture_stream_type(driver->dev, i) != freebob_stream_type_audio) {
00730             printMessage ("Don't register capture port %s", buf);
00731         } else {
00732             printMessage ("Registering capture port %s", buf);
00733 
00734             if (fEngine->PortRegister(fClientControl.fRefNum, buf,
00735                               JACK_DEFAULT_AUDIO_TYPE,
00736                               CaptureDriverFlags,
00737                               fEngineControl->fBufferSize, &port_index) < 0) {
00738                 jack_error("driver: cannot register port for %s", buf);
00739                 return -1;
00740             }
00741             port = fGraphManager->GetPort(port_index);
00742             range.min = range.max = driver->period_size + driver->capture_frame_latency;
00743             port->SetLatencyRange(JackCaptureLatency, &range);
00744             fCapturePortList[i] = port_index;
00745             jack_log("JackFreebobDriver::Attach fCapturePortList[i] %ld ", port_index);
00746             driver->capture_nchannels_audio++;
00747         }
00748     }
00749 
00750     // playback
00751     driver->playback_nchannels = freebob_streaming_get_nb_playback_streams(driver->dev);
00752     driver->playback_nchannels_audio = 0;
00753 
00754     for (unsigned int i = 0; i < driver->playback_nchannels; i++) {
00755 
00756         freebob_streaming_get_playback_stream_name(driver->dev, i, portname, sizeof(portname));
00757         snprintf(buf, sizeof(buf), "%s:%s", fClientControl.fName, portname);
00758 
00759         if (freebob_streaming_get_playback_stream_type(driver->dev, i) != freebob_stream_type_audio) {
00760             printMessage ("Don't register playback port %s", buf);
00761         } else {
00762             printMessage ("Registering playback port %s", buf);
00763             if (fEngine->PortRegister(fClientControl.fRefNum, buf,
00764                               JACK_DEFAULT_AUDIO_TYPE,
00765                               PlaybackDriverFlags,
00766                               fEngineControl->fBufferSize, &port_index) < 0) {
00767                 jack_error("driver: cannot register port for %s", buf);
00768                 return -1;
00769             }
00770             port = fGraphManager->GetPort(port_index);
00771             // Add one buffer more latency if "async" mode is used...
00772             range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency;
00773             port->SetLatencyRange(JackPlaybackLatency, &range);
00774             fPlaybackPortList[i] = port_index;
00775             jack_log("JackFreebobDriver::Attach fPlaybackPortList[i] %ld ", port_index);
00776             driver->playback_nchannels_audio++;
00777         }
00778     }
00779 
00780     fCaptureChannels = driver->capture_nchannels_audio;
00781     fPlaybackChannels = driver->playback_nchannels_audio;
00782 
00783     assert(fCaptureChannels < DRIVER_PORT_NUM);
00784     assert(fPlaybackChannels < DRIVER_PORT_NUM);
00785 
00786     // this makes no sense...
00787     assert(fCaptureChannels + fPlaybackChannels > 0);
00788     return 0;
00789 }
00790 
00791 int JackFreebobDriver::Detach()
00792 {
00793     freebob_driver_t* driver = (freebob_driver_t*)fDriver;
00794     jack_log("JackFreebobDriver::Detach");
00795 
00796     // finish the libfreebob streaming
00797     freebob_streaming_finish(driver->dev);
00798     driver->dev = NULL;
00799 
00800 #ifdef FREEBOB_DRIVER_WITH_MIDI
00801     if (driver->midi_handle) {
00802         freebob_driver_midi_finish(driver->midi_handle);
00803     }
00804     driver->midi_handle = NULL;
00805 #endif
00806 
00807     return JackAudioDriver::Detach();  // Generic JackAudioDriver Detach
00808 }
00809 
00810 int JackFreebobDriver::Open(freebob_jack_settings_t *params)
00811 {
00812     // Generic JackAudioDriver Open
00813     if (JackAudioDriver::Open(
00814                 params->period_size, params->sample_rate,
00815                 params->playback_ports, params->playback_ports,
00816                 0, 0, 0, "", "",
00817                 params->capture_frame_latency, params->playback_frame_latency) != 0) {
00818         return -1;
00819     }
00820 
00821     fDriver = (jack_driver_t *)freebob_driver_new ((char*)"freebob_pcm", params);
00822 
00823     if (fDriver) {
00824         // FreeBoB driver may have changed the in/out values
00825         fCaptureChannels = ((freebob_driver_t *)fDriver)->capture_nchannels_audio;
00826         fPlaybackChannels = ((freebob_driver_t *)fDriver)->playback_nchannels_audio;
00827         return 0;
00828     } else {
00829         JackAudioDriver::Close();
00830         return -1;
00831     }
00832 }
00833 
00834 int JackFreebobDriver::Close()
00835 {
00836     // Generic audio driver close
00837     int res = JackAudioDriver::Close();
00838 
00839     freebob_driver_delete((freebob_driver_t*)fDriver);
00840     return res;
00841 }
00842 
00843 int JackFreebobDriver::Start()
00844 {
00845     int res = JackAudioDriver::Start();
00846     if (res >= 0) {
00847         res = freebob_driver_start((freebob_driver_t *)fDriver);
00848         if (res < 0) {
00849             JackAudioDriver::Stop();
00850         }
00851     }
00852     return res;
00853 }
00854 
00855 int JackFreebobDriver::Stop()
00856 {
00857     int res = freebob_driver_stop((freebob_driver_t *)fDriver);
00858     if (JackAudioDriver::Stop() < 0) {
00859         res = -1;
00860     }
00861     return res;
00862 }
00863 
00864 int JackFreebobDriver::Read()
00865 {
00866     printEnter();
00867 
00868     /* Taken from freebob_driver_run_cycle */
00869     freebob_driver_t* driver = (freebob_driver_t*)fDriver;
00870     int wait_status = 0;
00871     fDelayedUsecs = 0.f;
00872 
00873 retry:
00874 
00875     jack_nframes_t nframes = freebob_driver_wait (driver, -1, &wait_status,
00876                              &fDelayedUsecs);
00877 
00878     if ((wait_status < 0)) {
00879         printError( "wait status < 0! (= %d)", wait_status);
00880         return -1;
00881     }
00882 
00883     if (nframes == 0) {
00884         /* we detected an xrun and restarted: notify
00885          * clients about the delay.
00886          */
00887         jack_log("FreeBoB XRun");
00888         NotifyXRun(fBeginDateUst, fDelayedUsecs);
00889         goto retry; /* recoverable error*/
00890     }
00891 
00892     if (nframes != fEngineControl->fBufferSize)
00893         jack_log("JackFreebobDriver::Read warning nframes = %ld", nframes);
00894 
00895     // Has to be done before read
00896     JackDriver::CycleIncTime();
00897 
00898     printExit();
00899     return freebob_driver_read((freebob_driver_t *)fDriver, fEngineControl->fBufferSize);
00900 }
00901 
00902 int JackFreebobDriver::Write()
00903 {
00904     printEnter();
00905     int res = freebob_driver_write((freebob_driver_t *)fDriver, fEngineControl->fBufferSize);
00906     printExit();
00907     return res;
00908 }
00909 
00910 void
00911 JackFreebobDriver::jack_driver_init (jack_driver_t *driver)
00912 {
00913     memset (driver, 0, sizeof (*driver));
00914 
00915     driver->attach = 0;
00916     driver->detach = 0;
00917     driver->write = 0;
00918     driver->read = 0;
00919     driver->null_cycle = 0;
00920     driver->bufsize = 0;
00921     driver->start = 0;
00922     driver->stop = 0;
00923 }
00924 
00925 void
00926 JackFreebobDriver::jack_driver_nt_init (jack_driver_nt_t * driver)
00927 {
00928     memset (driver, 0, sizeof (*driver));
00929 
00930     jack_driver_init ((jack_driver_t *) driver);
00931 
00932     driver->attach = 0;
00933     driver->detach = 0;
00934     driver->bufsize = 0;
00935     driver->stop = 0;
00936     driver->start = 0;
00937 
00938     driver->nt_bufsize = 0;
00939     driver->nt_start = 0;
00940     driver->nt_stop = 0;
00941     driver->nt_attach = 0;
00942     driver->nt_detach = 0;
00943     driver->nt_run_cycle = 0;
00944 }
00945 
00946 } // end of namespace
00947 
00948 #ifdef __cplusplus
00949 extern "C"
00950 {
00951 #endif
00952 
00953     const jack_driver_desc_t *
00954     driver_get_descriptor () {
00955         jack_driver_desc_t * desc;
00956         jack_driver_desc_filler_t filler;
00957         jack_driver_param_value_t value;
00958 
00959         desc = jack_driver_descriptor_construct("freebob", JackDriverMaster, "Linux FreeBob API based audio backend", &filler);
00960 
00961         strcpy(value.str, "hw:0");
00962         jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "The FireWire device to use. Format is: 'hw:port[,node]'.", NULL);
00963 
00964         value.ui = 1024;
00965         jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
00966 
00967         value.ui = 3;
00968         jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of periods of playback latency", NULL);
00969 
00970         value.ui = 48000U;
00971         jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
00972 
00973         value.i = 0;
00974         jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamBool, &value, NULL, "Provide capture ports.", NULL);
00975         jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamBool, &value, NULL, "Provide playback ports.", NULL);
00976 
00977         value.i = 1;
00978         jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports.", NULL);
00979 
00980         value.ui = 0;
00981         jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency (frames)", NULL);
00982         jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency (frames)", NULL);
00983 
00984         value.ui = 0;
00985         jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "Number of input channels to provide (note: currently ignored)", NULL);
00986         jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "Number of output channels to provide (note: currently ignored)", NULL);
00987 
00988         return desc;
00989     }
00990 
00991     Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) {
00992         unsigned int port = 0;
00993         unsigned int node_id = -1;
00994         int nbitems;
00995 
00996         const JSList * node;
00997         const jack_driver_param_t * param;
00998 
00999         freebob_jack_settings_t cmlparams;
01000 
01001         const char *device_name = "hw:0";
01002 
01003         cmlparams.period_size_set = 0;
01004         cmlparams.sample_rate_set = 0;
01005         cmlparams.buffer_size_set = 0;
01006         cmlparams.port_set = 0;
01007         cmlparams.node_id_set = 0;
01008 
01009         /* default values */
01010         cmlparams.period_size = 1024;
01011         cmlparams.sample_rate = 48000;
01012         cmlparams.buffer_size = 3;
01013         cmlparams.port = 0;
01014         cmlparams.node_id = -1;
01015         cmlparams.playback_ports = 0;
01016         cmlparams.capture_ports = 0;
01017         cmlparams.playback_frame_latency = 0;
01018         cmlparams.capture_frame_latency = 0;
01019 
01020         for (node = params; node; node = jack_slist_next (node)) {
01021             param = (jack_driver_param_t *) node->data;
01022 
01023             switch (param->character) {
01024                 case 'd':
01025                     device_name = param->value.str;
01026                     break;
01027                 case 'p':
01028                     cmlparams.period_size = param->value.ui;
01029                     cmlparams.period_size_set = 1;
01030                     break;
01031                 case 'n':
01032                     cmlparams.buffer_size = param->value.ui;
01033                     cmlparams.buffer_size_set = 1;
01034                     break;
01035                 case 'r':
01036                     cmlparams.sample_rate = param->value.ui;
01037                     cmlparams.sample_rate_set = 1;
01038                     break;
01039                 case 'C':
01040                     cmlparams.capture_ports = 1;
01041                     break;
01042                 case 'P':
01043                     cmlparams.playback_ports = 1;
01044                     break;
01045                 case 'D':
01046                     cmlparams.capture_ports = 1;
01047                     cmlparams.playback_ports = 1;
01048                     break;
01049                 case 'I':
01050                     cmlparams.capture_frame_latency = param->value.ui;
01051                     break;
01052                 case 'O':
01053                     cmlparams.playback_frame_latency = param->value.ui;
01054                     break;
01055                     // ignore these for now
01056                 case 'i':
01057                     break;
01058                 case 'o':
01059                     break;
01060             }
01061         }
01062 
01063         /* duplex is the default */
01064         if (!cmlparams.playback_ports && !cmlparams.capture_ports) {
01065             cmlparams.playback_ports = TRUE;
01066             cmlparams.capture_ports = TRUE;
01067         }
01068 
01069         nbitems = sscanf(device_name, "hw:%u,%u", &port, &node_id);
01070         if (nbitems < 2) {
01071             nbitems = sscanf(device_name, "hw:%u", &port);
01072 
01073             if (nbitems < 1) {
01074                 printError("device (-d) argument not valid\n");
01075                 return NULL;
01076             } else {
01077                 cmlparams.port = port;
01078                 cmlparams.port_set = 1;
01079 
01080                 cmlparams.node_id = -1;
01081                 cmlparams.node_id_set = 0;
01082             }
01083         } else {
01084             cmlparams.port = port;
01085             cmlparams.port_set = 1;
01086 
01087             cmlparams.node_id = node_id;
01088             cmlparams.node_id_set = 1;
01089         }
01090 
01091         jack_error("Freebob using Firewire port %d, node %d", cmlparams.port, cmlparams.node_id);
01092 
01093         Jack::JackFreebobDriver* freebob_driver = new Jack::JackFreebobDriver("system", "freebob_pcm", engine, table);
01094         Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(freebob_driver);
01095         // Special open for FreeBoB driver...
01096         if (freebob_driver->Open(&cmlparams) == 0) {
01097             return threaded_driver;
01098         } else {
01099             delete threaded_driver; // Delete the decorated driver
01100             return NULL;
01101         }
01102     }
01103 
01104 #ifdef __cplusplus
01105 }
01106 #endif
01107 
01108