Jack2 1.9.10
|
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