| 1 |
/* |
|---|
| 2 |
Copyright (C) 2001 Paul Davis |
|---|
| 3 |
Copyright (C) 2004 Grame |
|---|
| 4 |
Copyright (C) 2007 Pieter Palmers |
|---|
| 5 |
Copyright (C) 2009 Devin Anderson |
|---|
| 6 |
|
|---|
| 7 |
This program is free software; you can redistribute it and/or modify |
|---|
| 8 |
it under the terms of the GNU General Public License as published by |
|---|
| 9 |
the Free Software Foundation; either version 2 of the License, or |
|---|
| 10 |
(at your option) any later version. |
|---|
| 11 |
|
|---|
| 12 |
This program is distributed in the hope that it will be useful, |
|---|
| 13 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 |
GNU General Public License for more details. |
|---|
| 16 |
|
|---|
| 17 |
You should have received a copy of the GNU General Public License |
|---|
| 18 |
along with this program; if not, write to the Free Software |
|---|
| 19 |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|---|
| 20 |
|
|---|
| 21 |
*/ |
|---|
| 22 |
|
|---|
| 23 |
#include <iostream> |
|---|
| 24 |
#include <unistd.h> |
|---|
| 25 |
#include <math.h> |
|---|
| 26 |
#include <stdio.h> |
|---|
| 27 |
#include <memory.h> |
|---|
| 28 |
#include <unistd.h> |
|---|
| 29 |
#include <stdlib.h> |
|---|
| 30 |
#include <errno.h> |
|---|
| 31 |
#include <stdarg.h> |
|---|
| 32 |
#include <signal.h> |
|---|
| 33 |
#include <sys/types.h> |
|---|
| 34 |
#include <sys/time.h> |
|---|
| 35 |
#include <regex.h> |
|---|
| 36 |
#include <string.h> |
|---|
| 37 |
|
|---|
| 38 |
#include "JackFFADODriver.h" |
|---|
| 39 |
#include "JackFFADOMidiInputPort.h" |
|---|
| 40 |
#include "JackFFADOMidiOutputPort.h" |
|---|
| 41 |
#include "JackEngineControl.h" |
|---|
| 42 |
#include "JackClientControl.h" |
|---|
| 43 |
#include "JackPort.h" |
|---|
| 44 |
#include "JackGraphManager.h" |
|---|
| 45 |
#include "JackCompilerDeps.h" |
|---|
| 46 |
#include "JackLockedEngine.h" |
|---|
| 47 |
|
|---|
| 48 |
namespace Jack |
|---|
| 49 |
{ |
|---|
| 50 |
|
|---|
| 51 |
#define FIREWIRE_REQUIRED_FFADO_API_VERSION 8 |
|---|
| 52 |
|
|---|
| 53 |
#define jack_get_microseconds GetMicroSeconds |
|---|
| 54 |
|
|---|
| 55 |
int |
|---|
| 56 |
JackFFADODriver::ffado_driver_read (ffado_driver_t * driver, jack_nframes_t nframes) |
|---|
| 57 |
{ |
|---|
| 58 |
channel_t chn; |
|---|
| 59 |
jack_default_audio_sample_t* buf = NULL; |
|---|
| 60 |
|
|---|
| 61 |
printEnter(); |
|---|
| 62 |
for (chn = 0; chn < driver->capture_nchannels; chn++) { |
|---|
| 63 |
// if nothing connected, don't process |
|---|
| 64 |
if (fGraphManager->GetConnectionsNum(fCapturePortList[chn]) == 0) { |
|---|
| 65 |
buf = (jack_default_audio_sample_t*)driver->scratchbuffer; |
|---|
| 66 |
// we always have to specify a valid buffer |
|---|
| 67 |
ffado_streaming_set_capture_stream_buffer(driver->dev, chn, (char *)(buf)); |
|---|
| 68 |
// notify the streaming system that it can (but doesn't have to) skip |
|---|
| 69 |
// this channel |
|---|
| 70 |
ffado_streaming_capture_stream_onoff(driver->dev, chn, 0); |
|---|
| 71 |
} else { |
|---|
| 72 |
if (driver->capture_channels[chn].stream_type == ffado_stream_type_audio) { |
|---|
| 73 |
buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[chn], nframes); |
|---|
| 74 |
|
|---|
| 75 |
/* if the returned buffer is invalid, use the dummy buffer */ |
|---|
| 76 |
if (!buf) buf = (jack_default_audio_sample_t*)driver->scratchbuffer; |
|---|
| 77 |
|
|---|
| 78 |
ffado_streaming_set_capture_stream_buffer(driver->dev, chn, (char *)(buf)); |
|---|
| 79 |
ffado_streaming_capture_stream_onoff(driver->dev, chn, 1); |
|---|
| 80 |
} else if (driver->capture_channels[chn].stream_type == ffado_stream_type_midi) { |
|---|
| 81 |
ffado_streaming_set_capture_stream_buffer(driver->dev, chn, |
|---|
| 82 |
(char *)(driver->capture_channels[chn].midi_buffer)); |
|---|
| 83 |
ffado_streaming_capture_stream_onoff(driver->dev, chn, 1); |
|---|
| 84 |
} else { // always have a valid buffer |
|---|
| 85 |
ffado_streaming_set_capture_stream_buffer(driver->dev, chn, (char *)(driver->scratchbuffer)); |
|---|
| 86 |
// don't process what we don't use |
|---|
| 87 |
ffado_streaming_capture_stream_onoff(driver->dev, chn, 0); |
|---|
| 88 |
} |
|---|
| 89 |
} |
|---|
| 90 |
} |
|---|
| 91 |
|
|---|
| 92 |
/* now transfer the buffers */ |
|---|
| 93 |
ffado_streaming_transfer_capture_buffers(driver->dev); |
|---|
| 94 |
|
|---|
| 95 |
/* process the midi data */ |
|---|
| 96 |
for (chn = 0; chn < driver->capture_nchannels; chn++) { |
|---|
| 97 |
if (driver->capture_channels[chn].stream_type == ffado_stream_type_midi) { |
|---|
| 98 |
JackFFADOMidiInputPort *midi_input = (JackFFADOMidiInputPort *) driver->capture_channels[chn].midi_input; |
|---|
| 99 |
JackMidiBuffer *buffer = (JackMidiBuffer *) fGraphManager->GetBuffer(fCapturePortList[chn], nframes); |
|---|
| 100 |
midi_input->Process(buffer, driver->capture_channels[chn].midi_buffer, nframes); |
|---|
| 101 |
} |
|---|
| 102 |
} |
|---|
| 103 |
|
|---|
| 104 |
printExit(); |
|---|
| 105 |
return 0; |
|---|
| 106 |
} |
|---|
| 107 |
|
|---|
| 108 |
int |
|---|
| 109 |
JackFFADODriver::ffado_driver_write (ffado_driver_t * driver, jack_nframes_t nframes) |
|---|
| 110 |
{ |
|---|
| 111 |
channel_t chn; |
|---|
| 112 |
jack_default_audio_sample_t* buf; |
|---|
| 113 |
printEnter(); |
|---|
| 114 |
|
|---|
| 115 |
driver->process_count++; |
|---|
| 116 |
|
|---|
| 117 |
for (chn = 0; chn < driver->playback_nchannels; chn++) { |
|---|
| 118 |
if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chn]) == 0) { |
|---|
| 119 |
buf = (jack_default_audio_sample_t*)driver->nullbuffer; |
|---|
| 120 |
// we always have to specify a valid buffer |
|---|
| 121 |
ffado_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(buf)); |
|---|
| 122 |
// notify the streaming system that it can (but doesn't have to) skip |
|---|
| 123 |
// this channel |
|---|
| 124 |
ffado_streaming_playback_stream_onoff(driver->dev, chn, 0); |
|---|
| 125 |
} else { |
|---|
| 126 |
if (driver->playback_channels[chn].stream_type == ffado_stream_type_audio) { |
|---|
| 127 |
buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], nframes); |
|---|
| 128 |
/* use the silent buffer if there is no valid jack buffer */ |
|---|
| 129 |
if (!buf) buf = (jack_default_audio_sample_t*)driver->nullbuffer; |
|---|
| 130 |
ffado_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(buf)); |
|---|
| 131 |
ffado_streaming_playback_stream_onoff(driver->dev, chn, 1); |
|---|
| 132 |
} else if (driver->playback_channels[chn].stream_type == ffado_stream_type_midi) { |
|---|
| 133 |
uint32_t *midi_buffer = driver->playback_channels[chn].midi_buffer; |
|---|
| 134 |
memset(midi_buffer, 0, nframes * sizeof(uint32_t)); |
|---|
| 135 |
buf = (jack_default_audio_sample_t *) fGraphManager->GetBuffer(fPlaybackPortList[chn], nframes); |
|---|
| 136 |
ffado_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(midi_buffer)); |
|---|
| 137 |
ffado_streaming_playback_stream_onoff(driver->dev, chn, buf ? 1 : 0); |
|---|
| 138 |
JackFFADOMidiOutputPort *midi_output = (JackFFADOMidiOutputPort *) driver->playback_channels[chn].midi_output; |
|---|
| 139 |
midi_output->Process((JackMidiBuffer *) buf, midi_buffer, nframes); |
|---|
| 140 |
|
|---|
| 141 |
} else { // always have a valid buffer |
|---|
| 142 |
ffado_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(driver->nullbuffer)); |
|---|
| 143 |
ffado_streaming_playback_stream_onoff(driver->dev, chn, 0); |
|---|
| 144 |
} |
|---|
| 145 |
} |
|---|
| 146 |
} |
|---|
| 147 |
ffado_streaming_transfer_playback_buffers(driver->dev); |
|---|
| 148 |
printExit(); |
|---|
| 149 |
return 0; |
|---|
| 150 |
} |
|---|
| 151 |
|
|---|
| 152 |
jack_nframes_t |
|---|
| 153 |
JackFFADODriver::ffado_driver_wait (ffado_driver_t *driver, int extra_fd, int *status, |
|---|
| 154 |
float *delayed_usecs) |
|---|
| 155 |
{ |
|---|
| 156 |
jack_time_t wait_enter; |
|---|
| 157 |
jack_time_t wait_ret; |
|---|
| 158 |
ffado_wait_response response; |
|---|
| 159 |
|
|---|
| 160 |
printEnter(); |
|---|
| 161 |
|
|---|
| 162 |
wait_enter = jack_get_microseconds (); |
|---|
| 163 |
if (wait_enter > driver->wait_next) { |
|---|
| 164 |
/* |
|---|
| 165 |
* This processing cycle was delayed past the |
|---|
| 166 |
* next due interrupt! Do not account this as |
|---|
| 167 |
* a wakeup delay: |
|---|
| 168 |
*/ |
|---|
| 169 |
driver->wait_next = 0; |
|---|
| 170 |
driver->wait_late++; |
|---|
| 171 |
} |
|---|
| 172 |
// *status = -2; interrupt |
|---|
| 173 |
// *status = -3; timeout |
|---|
| 174 |
// *status = -4; extra FD |
|---|
| 175 |
|
|---|
| 176 |
response = ffado_streaming_wait(driver->dev); |
|---|
| 177 |
|
|---|
| 178 |
wait_ret = jack_get_microseconds (); |
|---|
| 179 |
|
|---|
| 180 |
if (driver->wait_next && wait_ret > driver->wait_next) { |
|---|
| 181 |
*delayed_usecs = wait_ret - driver->wait_next; |
|---|
| 182 |
} |
|---|
| 183 |
driver->wait_last = wait_ret; |
|---|
| 184 |
driver->wait_next = wait_ret + driver->period_usecs; |
|---|
| 185 |
// driver->engine->transport_cycle_start (driver->engine, wait_ret); |
|---|
| 186 |
|
|---|
| 187 |
if(response == ffado_wait_ok) { |
|---|
| 188 |
// all good |
|---|
| 189 |
*status = 0; |
|---|
| 190 |
} else if (response == ffado_wait_xrun) { |
|---|
| 191 |
// xrun happened, but it's handled |
|---|
| 192 |
*status = 0; |
|---|
| 193 |
return 0; |
|---|
| 194 |
} else if (response == ffado_wait_error) { |
|---|
| 195 |
// an error happened (unhandled xrun) |
|---|
| 196 |
// this should be fatal |
|---|
| 197 |
jack_error("JackFFADODriver::ffado_driver_wait - unhandled xrun"); |
|---|
| 198 |
*status = -1; |
|---|
| 199 |
return 0; |
|---|
| 200 |
} else if (response == ffado_wait_shutdown) { |
|---|
| 201 |
// ffado requested shutdown (e.g. device unplugged) |
|---|
| 202 |
// this should be fatal |
|---|
| 203 |
jack_error("JackFFADODriver::ffado_driver_wait - shutdown requested " |
|---|
| 204 |
"(device unplugged?)"); |
|---|
| 205 |
*status = -1; |
|---|
| 206 |
return 0; |
|---|
| 207 |
} else { |
|---|
| 208 |
// unknown response code. should be fatal |
|---|
| 209 |
// this should be fatal |
|---|
| 210 |
jack_error("JackFFADODriver::ffado_driver_wait - unexpected error " |
|---|
| 211 |
"code '%d' returned from 'ffado_streaming_wait'", response); |
|---|
| 212 |
*status = -1; |
|---|
| 213 |
return 0; |
|---|
| 214 |
} |
|---|
| 215 |
|
|---|
| 216 |
fBeginDateUst = wait_ret; |
|---|
| 217 |
|
|---|
| 218 |
printExit(); |
|---|
| 219 |
return driver->period_size; |
|---|
| 220 |
} |
|---|
| 221 |
|
|---|
| 222 |
int |
|---|
| 223 |
JackFFADODriver::ffado_driver_start (ffado_driver_t *driver) |
|---|
| 224 |
{ |
|---|
| 225 |
int retval = 0; |
|---|
| 226 |
|
|---|
| 227 |
if ((retval = ffado_streaming_start(driver->dev))) { |
|---|
| 228 |
printError("Could not start streaming threads"); |
|---|
| 229 |
|
|---|
| 230 |
return retval; |
|---|
| 231 |
} |
|---|
| 232 |
return 0; |
|---|
| 233 |
} |
|---|
| 234 |
|
|---|
| 235 |
int |
|---|
| 236 |
JackFFADODriver::ffado_driver_stop (ffado_driver_t *driver) |
|---|
| 237 |
{ |
|---|
| 238 |
int retval = 0; |
|---|
| 239 |
|
|---|
| 240 |
if ((retval = ffado_streaming_stop(driver->dev))) { |
|---|
| 241 |
printError("Could not stop streaming threads"); |
|---|
| 242 |
return retval; |
|---|
| 243 |
} |
|---|
| 244 |
|
|---|
| 245 |
return 0; |
|---|
| 246 |
} |
|---|
| 247 |
|
|---|
| 248 |
int |
|---|
| 249 |
JackFFADODriver::ffado_driver_restart (ffado_driver_t *driver) |
|---|
| 250 |
{ |
|---|
| 251 |
if (Stop()) |
|---|
| 252 |
return -1; |
|---|
| 253 |
return Start(); |
|---|
| 254 |
} |
|---|
| 255 |
|
|---|
| 256 |
int |
|---|
| 257 |
JackFFADODriver::SetBufferSize (jack_nframes_t nframes) |
|---|
| 258 |
{ |
|---|
| 259 |
printError("Buffer size change requested but not supported!!!"); |
|---|
| 260 |
|
|---|
| 261 |
/* |
|---|
| 262 |
driver->period_size = nframes; |
|---|
| 263 |
driver->period_usecs = |
|---|
| 264 |
(jack_time_t) floor ((((float) nframes) / driver->sample_rate) |
|---|
| 265 |
* 1000000.0f); |
|---|
| 266 |
*/ |
|---|
| 267 |
|
|---|
| 268 |
/* tell the engine to change its buffer size */ |
|---|
| 269 |
//driver->engine->set_buffer_size (driver->engine, nframes); |
|---|
| 270 |
|
|---|
| 271 |
return -1; // unsupported |
|---|
| 272 |
} |
|---|
| 273 |
|
|---|
| 274 |
typedef void (*JackDriverFinishFunction) (jack_driver_t *); |
|---|
| 275 |
|
|---|
| 276 |
ffado_driver_t * |
|---|
| 277 |
JackFFADODriver::ffado_driver_new (const char *name, |
|---|
| 278 |
ffado_jack_settings_t *params) |
|---|
| 279 |
{ |
|---|
| 280 |
ffado_driver_t *driver; |
|---|
| 281 |
|
|---|
| 282 |
assert(params); |
|---|
| 283 |
|
|---|
| 284 |
if (ffado_get_api_version() != FIREWIRE_REQUIRED_FFADO_API_VERSION) { |
|---|
| 285 |
printError("Incompatible libffado version! (%s)", ffado_get_version()); |
|---|
| 286 |
return NULL; |
|---|
| 287 |
} |
|---|
| 288 |
|
|---|
| 289 |
printMessage("Starting FFADO backend (%s)", ffado_get_version()); |
|---|
| 290 |
|
|---|
| 291 |
driver = (ffado_driver_t*)calloc (1, sizeof (ffado_driver_t)); |
|---|
| 292 |
|
|---|
| 293 |
/* Setup the jack interfaces */ |
|---|
| 294 |
jack_driver_nt_init ((jack_driver_nt_t *) driver); |
|---|
| 295 |
|
|---|
| 296 |
/* driver->nt_attach = (JackDriverNTAttachFunction) ffado_driver_attach; |
|---|
| 297 |
driver->nt_detach = (JackDriverNTDetachFunction) ffado_driver_detach; |
|---|
| 298 |
driver->nt_start = (JackDriverNTStartFunction) ffado_driver_start; |
|---|
| 299 |
driver->nt_stop = (JackDriverNTStopFunction) ffado_driver_stop; |
|---|
| 300 |
driver->nt_run_cycle = (JackDriverNTRunCycleFunction) ffado_driver_run_cycle; |
|---|
| 301 |
driver->null_cycle = (JackDriverNullCycleFunction) ffado_driver_null_cycle; |
|---|
| 302 |
driver->write = (JackDriverReadFunction) ffado_driver_write; |
|---|
| 303 |
driver->read = (JackDriverReadFunction) ffado_driver_read; |
|---|
| 304 |
driver->nt_bufsize = (JackDriverNTBufSizeFunction) ffado_driver_bufsize; |
|---|
| 305 |
*/ |
|---|
| 306 |
|
|---|
| 307 |
/* copy command line parameter contents to the driver structure */ |
|---|
| 308 |
memcpy(&driver->settings, params, sizeof(ffado_jack_settings_t)); |
|---|
| 309 |
|
|---|
| 310 |
/* prepare all parameters */ |
|---|
| 311 |
driver->sample_rate = params->sample_rate; |
|---|
| 312 |
driver->period_size = params->period_size; |
|---|
| 313 |
fBeginDateUst = 0; |
|---|
| 314 |
|
|---|
| 315 |
driver->period_usecs = |
|---|
| 316 |
(jack_time_t) floor ((((float) driver->period_size) * 1000000.0f) / driver->sample_rate); |
|---|
| 317 |
|
|---|
| 318 |
// driver->client = client; |
|---|
| 319 |
driver->engine = NULL; |
|---|
| 320 |
|
|---|
| 321 |
memset(&driver->device_options, 0, sizeof(driver->device_options)); |
|---|
| 322 |
driver->device_options.sample_rate = params->sample_rate; |
|---|
| 323 |
driver->device_options.period_size = params->period_size; |
|---|
| 324 |
driver->device_options.nb_buffers = params->buffer_size; |
|---|
| 325 |
driver->device_options.verbose = params->verbose_level; |
|---|
| 326 |
driver->capture_frame_latency = params->capture_frame_latency; |
|---|
| 327 |
driver->playback_frame_latency = params->playback_frame_latency; |
|---|
| 328 |
driver->device_options.snoop_mode = params->snoop_mode; |
|---|
| 329 |
|
|---|
| 330 |
debugPrint(DEBUG_LEVEL_STARTUP, " Driver compiled on %s %s", __DATE__, __TIME__); |
|---|
| 331 |
debugPrint(DEBUG_LEVEL_STARTUP, " Created driver %s", name); |
|---|
| 332 |
debugPrint(DEBUG_LEVEL_STARTUP, " period_size: %d", driver->device_options.period_size); |
|---|
| 333 |
debugPrint(DEBUG_LEVEL_STARTUP, " period_usecs: %d", driver->period_usecs); |
|---|
| 334 |
debugPrint(DEBUG_LEVEL_STARTUP, " sample rate: %d", driver->device_options.sample_rate); |
|---|
| 335 |
debugPrint(DEBUG_LEVEL_STARTUP, " verbose level: %d", driver->device_options.verbose); |
|---|
| 336 |
|
|---|
| 337 |
return (ffado_driver_t *) driver; |
|---|
| 338 |
} |
|---|
| 339 |
|
|---|
| 340 |
void |
|---|
| 341 |
JackFFADODriver::ffado_driver_delete (ffado_driver_t *driver) |
|---|
| 342 |
{ |
|---|
| 343 |
free (driver); |
|---|
| 344 |
} |
|---|
| 345 |
|
|---|
| 346 |
int JackFFADODriver::Attach() |
|---|
| 347 |
{ |
|---|
| 348 |
JackPort* port; |
|---|
| 349 |
jack_port_id_t port_index; |
|---|
| 350 |
char buf[REAL_JACK_PORT_NAME_SIZE]; |
|---|
| 351 |
char portname[REAL_JACK_PORT_NAME_SIZE]; |
|---|
| 352 |
jack_latency_range_t range; |
|---|
| 353 |
|
|---|
| 354 |
ffado_driver_t* driver = (ffado_driver_t*)fDriver; |
|---|
| 355 |
|
|---|
| 356 |
jack_log("JackFFADODriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); |
|---|
| 357 |
|
|---|
| 358 |
g_verbose = (fEngineControl->fVerbose ? 1 : 0); |
|---|
| 359 |
|
|---|
| 360 |
/* preallocate some buffers such that they don't have to be allocated |
|---|
| 361 |
in RT context (or from the stack) |
|---|
| 362 |
*/ |
|---|
| 363 |
/* the null buffer is a buffer that contains one period of silence */ |
|---|
| 364 |
driver->nullbuffer = (ffado_sample_t *)calloc(driver->period_size, sizeof(ffado_sample_t)); |
|---|
| 365 |
if (driver->nullbuffer == NULL) { |
|---|
| 366 |
printError("could not allocate memory for null buffer"); |
|---|
| 367 |
return -1; |
|---|
| 368 |
} |
|---|
| 369 |
/* calloc should do this, but it can't hurt to be sure */ |
|---|
| 370 |
memset(driver->nullbuffer, 0, driver->period_size*sizeof(ffado_sample_t)); |
|---|
| 371 |
|
|---|
| 372 |
/* the scratch buffer is a buffer of one period that can be used as dummy memory */ |
|---|
| 373 |
driver->scratchbuffer = (ffado_sample_t *)calloc(driver->period_size, sizeof(ffado_sample_t)); |
|---|
| 374 |
if (driver->scratchbuffer == NULL) { |
|---|
| 375 |
printError("could not allocate memory for scratch buffer"); |
|---|
| 376 |
return -1; |
|---|
| 377 |
} |
|---|
| 378 |
|
|---|
| 379 |
/* packetizer thread options */ |
|---|
| 380 |
driver->device_options.realtime = (fEngineControl->fRealTime ? 1 : 0); |
|---|
| 381 |
|
|---|
| 382 |
driver->device_options.packetizer_priority = fEngineControl->fServerPriority + |
|---|
| 383 |
FFADO_RT_PRIORITY_PACKETIZER_RELATIVE; |
|---|
| 384 |
if (driver->device_options.packetizer_priority > 98) { |
|---|
| 385 |
driver->device_options.packetizer_priority = 98; |
|---|
| 386 |
} |
|---|
| 387 |
|
|---|
| 388 |
// initialize the thread |
|---|
| 389 |
driver->dev = ffado_streaming_init(driver->device_info, driver->device_options); |
|---|
| 390 |
|
|---|
| 391 |
if (!driver->dev) { |
|---|
| 392 |
printError("FFADO: Error creating virtual device"); |
|---|
| 393 |
return -1; |
|---|
| 394 |
} |
|---|
| 395 |
|
|---|
| 396 |
if (driver->device_options.realtime) { |
|---|
| 397 |
printMessage("Streaming thread running with Realtime scheduling, priority %d", |
|---|
| 398 |
driver->device_options.packetizer_priority); |
|---|
| 399 |
} else { |
|---|
| 400 |
printMessage("Streaming thread running without Realtime scheduling"); |
|---|
| 401 |
} |
|---|
| 402 |
|
|---|
| 403 |
ffado_streaming_set_audio_datatype(driver->dev, ffado_audio_datatype_float); |
|---|
| 404 |
|
|---|
| 405 |
/* ports */ |
|---|
| 406 |
|
|---|
| 407 |
// capture |
|---|
| 408 |
driver->capture_nchannels = ffado_streaming_get_nb_capture_streams(driver->dev); |
|---|
| 409 |
driver->capture_channels = (ffado_capture_channel_t *)calloc(driver->capture_nchannels, sizeof(ffado_capture_channel_t)); |
|---|
| 410 |
if (driver->capture_channels == NULL) { |
|---|
| 411 |
printError("could not allocate memory for capture channel list"); |
|---|
| 412 |
return -1; |
|---|
| 413 |
} |
|---|
| 414 |
|
|---|
| 415 |
fCaptureChannels = 0; |
|---|
| 416 |
for (channel_t chn = 0; chn < driver->capture_nchannels; chn++) { |
|---|
| 417 |
ffado_streaming_get_capture_stream_name(driver->dev, chn, portname, sizeof(portname)); |
|---|
| 418 |
|
|---|
| 419 |
driver->capture_channels[chn].stream_type = ffado_streaming_get_capture_stream_type(driver->dev, chn); |
|---|
| 420 |
if (driver->capture_channels[chn].stream_type == ffado_stream_type_audio) { |
|---|
| 421 |
snprintf(buf, sizeof(buf), "firewire_pcm:%s_in", portname); |
|---|
| 422 |
printMessage ("Registering audio capture port %s", buf); |
|---|
| 423 |
if (fEngine->PortRegister(fClientControl.fRefNum, buf, |
|---|
| 424 |
JACK_DEFAULT_AUDIO_TYPE, |
|---|
| 425 |
CaptureDriverFlags, |
|---|
| 426 |
fEngineControl->fBufferSize, &port_index) < 0) { |
|---|
| 427 |
jack_error("driver: cannot register port for %s", buf); |
|---|
| 428 |
return -1; |
|---|
| 429 |
} |
|---|
| 430 |
|
|---|
| 431 |
// setup port parameters |
|---|
| 432 |
if (ffado_streaming_set_capture_stream_buffer(driver->dev, chn, NULL)) { |
|---|
| 433 |
printError(" cannot configure initial port buffer for %s", buf); |
|---|
| 434 |
} |
|---|
| 435 |
ffado_streaming_capture_stream_onoff(driver->dev, chn, 0); |
|---|
| 436 |
|
|---|
| 437 |
port = fGraphManager->GetPort(port_index); |
|---|
| 438 |
range.min = range.max = driver->period_size + driver->capture_frame_latency; |
|---|
| 439 |
port->SetLatencyRange(JackCaptureLatency, &range); |
|---|
| 440 |
// capture port aliases (jackd1 style port names) |
|---|
| 441 |
snprintf(buf, sizeof(buf), "%s:capture_%i", fClientControl.fName, (int) chn + 1); |
|---|
| 442 |
port->SetAlias(buf); |
|---|
| 443 |
fCapturePortList[chn] = port_index; |
|---|
| 444 |
jack_log("JackFFADODriver::Attach fCapturePortList[i] %ld ", port_index); |
|---|
| 445 |
fCaptureChannels++; |
|---|
| 446 |
} else if (driver->capture_channels[chn].stream_type == ffado_stream_type_midi) { |
|---|
| 447 |
snprintf(buf, sizeof(buf), "firewire_pcm:%s_in", portname); |
|---|
| 448 |
printMessage ("Registering midi capture port %s", buf); |
|---|
| 449 |
if (fEngine->PortRegister(fClientControl.fRefNum, buf, |
|---|
| 450 |
JACK_DEFAULT_MIDI_TYPE, |
|---|
| 451 |
CaptureDriverFlags, |
|---|
| 452 |
fEngineControl->fBufferSize, &port_index) < 0) { |
|---|
| 453 |
jack_error("driver: cannot register port for %s", buf); |
|---|
| 454 |
return -1; |
|---|
| 455 |
} |
|---|
| 456 |
|
|---|
| 457 |
// setup port parameters |
|---|
| 458 |
if (ffado_streaming_set_capture_stream_buffer(driver->dev, chn, NULL)) { |
|---|
| 459 |
printError(" cannot configure initial port buffer for %s", buf); |
|---|
| 460 |
} |
|---|
| 461 |
if (ffado_streaming_capture_stream_onoff(driver->dev, chn, 0)) { |
|---|
| 462 |
printError(" cannot enable port %s", buf); |
|---|
| 463 |
} |
|---|
| 464 |
|
|---|
| 465 |
driver->capture_channels[chn].midi_input = new JackFFADOMidiInputPort(); |
|---|
| 466 |
// setup the midi buffer |
|---|
| 467 |
driver->capture_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); |
|---|
| 468 |
|
|---|
| 469 |
port = fGraphManager->GetPort(port_index); |
|---|
| 470 |
range.min = range.max = driver->period_size + driver->capture_frame_latency; |
|---|
| 471 |
port->SetLatencyRange(JackCaptureLatency, &range); |
|---|
| 472 |
fCapturePortList[chn] = port_index; |
|---|
| 473 |
jack_log("JackFFADODriver::Attach fCapturePortList[i] %ld ", port_index); |
|---|
| 474 |
fCaptureChannels++; |
|---|
| 475 |
} else { |
|---|
| 476 |
printMessage ("Don't register capture port %s", portname); |
|---|
| 477 |
} |
|---|
| 478 |
} |
|---|
| 479 |
|
|---|
| 480 |
// playback |
|---|
| 481 |
driver->playback_nchannels = ffado_streaming_get_nb_playback_streams(driver->dev); |
|---|
| 482 |
driver->playback_channels = (ffado_playback_channel_t *)calloc(driver->playback_nchannels, sizeof(ffado_playback_channel_t)); |
|---|
| 483 |
if (driver->playback_channels == NULL) { |
|---|
| 484 |
printError("could not allocate memory for playback channel list"); |
|---|
| 485 |
return -1; |
|---|
| 486 |
} |
|---|
| 487 |
|
|---|
| 488 |
fPlaybackChannels = 0; |
|---|
| 489 |
for (channel_t chn = 0; chn < driver->playback_nchannels; chn++) { |
|---|
| 490 |
ffado_streaming_get_playback_stream_name(driver->dev, chn, portname, sizeof(portname)); |
|---|
| 491 |
|
|---|
| 492 |
driver->playback_channels[chn].stream_type = ffado_streaming_get_playback_stream_type(driver->dev, chn); |
|---|
| 493 |
|
|---|
| 494 |
if (driver->playback_channels[chn].stream_type == ffado_stream_type_audio) { |
|---|
| 495 |
snprintf(buf, sizeof(buf), "firewire_pcm:%s_out", portname); |
|---|
| 496 |
printMessage ("Registering audio playback port %s", buf); |
|---|
| 497 |
if (fEngine->PortRegister(fClientControl.fRefNum, buf, |
|---|
| 498 |
JACK_DEFAULT_AUDIO_TYPE, |
|---|
| 499 |
PlaybackDriverFlags, |
|---|
| 500 |
fEngineControl->fBufferSize, &port_index) < 0) { |
|---|
| 501 |
jack_error("driver: cannot register port for %s", buf); |
|---|
| 502 |
return -1; |
|---|
| 503 |
} |
|---|
| 504 |
|
|---|
| 505 |
// setup port parameters |
|---|
| 506 |
if (ffado_streaming_set_playback_stream_buffer(driver->dev, chn, NULL)) { |
|---|
| 507 |
printError(" cannot configure initial port buffer for %s", buf); |
|---|
| 508 |
} |
|---|
| 509 |
if (ffado_streaming_playback_stream_onoff(driver->dev, chn, 0)) { |
|---|
| 510 |
printError(" cannot enable port %s", buf); |
|---|
| 511 |
} |
|---|
| 512 |
|
|---|
| 513 |
port = fGraphManager->GetPort(port_index); |
|---|
| 514 |
// Add one buffer more latency if "async" mode is used... |
|---|
| 515 |
range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency; |
|---|
| 516 |
port->SetLatencyRange(JackPlaybackLatency, &range); |
|---|
| 517 |
// playback port aliases (jackd1 style port names) |
|---|
| 518 |
snprintf(buf, sizeof(buf), "%s:playback_%i", fClientControl.fName, (int) chn + 1); |
|---|
| 519 |
port->SetAlias(buf); |
|---|
| 520 |
fPlaybackPortList[chn] = port_index; |
|---|
| 521 |
jack_log("JackFFADODriver::Attach fPlaybackPortList[i] %ld ", port_index); |
|---|
| 522 |
fPlaybackChannels++; |
|---|
| 523 |
} else if (driver->playback_channels[chn].stream_type == ffado_stream_type_midi) { |
|---|
| 524 |
snprintf(buf, sizeof(buf), "firewire_pcm:%s_out", portname); |
|---|
| 525 |
printMessage ("Registering midi playback port %s", buf); |
|---|
| 526 |
|
|---|
| 527 |
if (fEngine->PortRegister(fClientControl.fRefNum, buf, |
|---|
| 528 |
JACK_DEFAULT_MIDI_TYPE, |
|---|
| 529 |
PlaybackDriverFlags, |
|---|
| 530 |
fEngineControl->fBufferSize, &port_index) < 0) { |
|---|
| 531 |
jack_error("driver: cannot register port for %s", buf); |
|---|
| 532 |
return -1; |
|---|
| 533 |
} |
|---|
| 534 |
|
|---|
| 535 |
// setup port parameters |
|---|
| 536 |
if (ffado_streaming_set_playback_stream_buffer(driver->dev, chn, NULL)) { |
|---|
| 537 |
printError(" cannot configure initial port buffer for %s", buf); |
|---|
| 538 |
} |
|---|
| 539 |
if (ffado_streaming_playback_stream_onoff(driver->dev, chn, 0)) { |
|---|
| 540 |
printError(" cannot enable port %s", buf); |
|---|
| 541 |
} |
|---|
| 542 |
// setup the midi buffer |
|---|
| 543 |
|
|---|
| 544 |
// This constructor optionally accepts arguments for the |
|---|
| 545 |
// non-realtime buffer size and the realtime buffer size. Ideally, |
|---|
| 546 |
// these would become command-line options for the FFADO driver. |
|---|
| 547 |
driver->playback_channels[chn].midi_output = new JackFFADOMidiOutputPort(); |
|---|
| 548 |
|
|---|
| 549 |
driver->playback_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); |
|---|
| 550 |
|
|---|
| 551 |
port = fGraphManager->GetPort(port_index); |
|---|
| 552 |
range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency; |
|---|
| 553 |
port->SetLatencyRange(JackPlaybackLatency, &range); |
|---|
| 554 |
fPlaybackPortList[chn] = port_index; |
|---|
| 555 |
jack_log("JackFFADODriver::Attach fPlaybackPortList[i] %ld ", port_index); |
|---|
| 556 |
fPlaybackChannels++; |
|---|
| 557 |
} else { |
|---|
| 558 |
printMessage ("Don't register playback port %s", portname); |
|---|
| 559 |
} |
|---|
| 560 |
} |
|---|
| 561 |
|
|---|
| 562 |
assert(fCaptureChannels < DRIVER_PORT_NUM); |
|---|
| 563 |
assert(fPlaybackChannels < DRIVER_PORT_NUM); |
|---|
| 564 |
|
|---|
| 565 |
if (ffado_streaming_prepare(driver->dev)) { |
|---|
| 566 |
printError("Could not prepare streaming device!"); |
|---|
| 567 |
return -1; |
|---|
| 568 |
} |
|---|
| 569 |
|
|---|
| 570 |
// this makes no sense... |
|---|
| 571 |
assert(fCaptureChannels + fPlaybackChannels > 0); |
|---|
| 572 |
return 0; |
|---|
| 573 |
} |
|---|
| 574 |
|
|---|
| 575 |
int JackFFADODriver::Detach() |
|---|
| 576 |
{ |
|---|
| 577 |
channel_t chn; |
|---|
| 578 |
ffado_driver_t* driver = (ffado_driver_t*)fDriver; |
|---|
| 579 |
jack_log("JackFFADODriver::Detach"); |
|---|
| 580 |
|
|---|
| 581 |
// finish the libfreebob streaming |
|---|
| 582 |
ffado_streaming_finish(driver->dev); |
|---|
| 583 |
driver->dev = NULL; |
|---|
| 584 |
|
|---|
| 585 |
// free all internal buffers |
|---|
| 586 |
for (chn = 0; chn < driver->capture_nchannels; chn++) { |
|---|
| 587 |
if (driver->capture_channels[chn].midi_buffer) |
|---|
| 588 |
free(driver->capture_channels[chn].midi_buffer); |
|---|
| 589 |
if (driver->capture_channels[chn].midi_input) |
|---|
| 590 |
delete ((JackFFADOMidiInputPort *) (driver->capture_channels[chn].midi_input)); |
|---|
| 591 |
} |
|---|
| 592 |
free(driver->capture_channels); |
|---|
| 593 |
|
|---|
| 594 |
for (chn = 0; chn < driver->playback_nchannels; chn++) { |
|---|
| 595 |
if (driver->playback_channels[chn].midi_buffer) |
|---|
| 596 |
free(driver->playback_channels[chn].midi_buffer); |
|---|
| 597 |
if (driver->playback_channels[chn].midi_output) |
|---|
| 598 |
delete ((JackFFADOMidiOutputPort *) (driver->playback_channels[chn].midi_output)); |
|---|
| 599 |
} |
|---|
| 600 |
free(driver->playback_channels); |
|---|
| 601 |
|
|---|
| 602 |
free(driver->nullbuffer); |
|---|
| 603 |
free(driver->scratchbuffer); |
|---|
| 604 |
|
|---|
| 605 |
return JackAudioDriver::Detach(); // Generic JackAudioDriver Detach |
|---|
| 606 |
} |
|---|
| 607 |
|
|---|
| 608 |
int JackFFADODriver::Open(ffado_jack_settings_t *params) |
|---|
| 609 |
{ |
|---|
| 610 |
// Generic JackAudioDriver Open |
|---|
| 611 |
if (JackAudioDriver::Open( |
|---|
| 612 |
params->period_size, params->sample_rate, |
|---|
| 613 |
params->playback_ports, params->playback_ports, |
|---|
| 614 |
0, 0, 0, "", "", |
|---|
| 615 |
params->capture_frame_latency, params->playback_frame_latency) != 0) { |
|---|
| 616 |
return -1; |
|---|
| 617 |
} |
|---|
| 618 |
|
|---|
| 619 |
fDriver = (jack_driver_t *)ffado_driver_new ("ffado_pcm", params); |
|---|
| 620 |
|
|---|
| 621 |
if (fDriver) { |
|---|
| 622 |
// FFADO driver may have changed the in/out values |
|---|
| 623 |
//fCaptureChannels = ((ffado_driver_t *)fDriver)->capture_nchannels_audio; |
|---|
| 624 |
//fPlaybackChannels = ((ffado_driver_t *)fDriver)->playback_nchannels_audio; |
|---|
| 625 |
return 0; |
|---|
| 626 |
} else { |
|---|
| 627 |
JackAudioDriver::Close(); |
|---|
| 628 |
return -1; |
|---|
| 629 |
} |
|---|
| 630 |
} |
|---|
| 631 |
|
|---|
| 632 |
int JackFFADODriver::Close() |
|---|
| 633 |
{ |
|---|
| 634 |
// Generic audio driver close |
|---|
| 635 |
int res = JackAudioDriver::Close(); |
|---|
| 636 |
|
|---|
| 637 |
ffado_driver_delete((ffado_driver_t*)fDriver); |
|---|
| 638 |
return res; |
|---|
| 639 |
} |
|---|
| 640 |
|
|---|
| 641 |
int JackFFADODriver::Start() |
|---|
| 642 |
{ |
|---|
| 643 |
int res = JackAudioDriver::Start(); |
|---|
| 644 |
if (res >= 0) { |
|---|
| 645 |
res = ffado_driver_start((ffado_driver_t *)fDriver); |
|---|
| 646 |
if (res < 0) { |
|---|
| 647 |
JackAudioDriver::Stop(); |
|---|
| 648 |
} |
|---|
| 649 |
} |
|---|
| 650 |
return res; |
|---|
| 651 |
} |
|---|
| 652 |
|
|---|
| 653 |
int JackFFADODriver::Stop() |
|---|
| 654 |
{ |
|---|
| 655 |
int res = ffado_driver_stop((ffado_driver_t *)fDriver); |
|---|
| 656 |
if (JackAudioDriver::Stop() < 0) { |
|---|
| 657 |
res = -1; |
|---|
| 658 |
} |
|---|
| 659 |
return res; |
|---|
| 660 |
} |
|---|
| 661 |
|
|---|
| 662 |
int JackFFADODriver::Read() |
|---|
| 663 |
{ |
|---|
| 664 |
printEnter(); |
|---|
| 665 |
|
|---|
| 666 |
/* Taken from ffado_driver_run_cycle */ |
|---|
| 667 |
ffado_driver_t* driver = (ffado_driver_t*)fDriver; |
|---|
| 668 |
int wait_status = 0; |
|---|
| 669 |
fDelayedUsecs = 0.f; |
|---|
| 670 |
|
|---|
| 671 |
retry: |
|---|
| 672 |
|
|---|
| 673 |
jack_nframes_t nframes = ffado_driver_wait(driver, -1, &wait_status, |
|---|
| 674 |
&fDelayedUsecs); |
|---|
| 675 |
|
|---|
| 676 |
if ((wait_status < 0)) { |
|---|
| 677 |
printError( "wait status < 0! (= %d)", wait_status); |
|---|
| 678 |
return -1; |
|---|
| 679 |
} |
|---|
| 680 |
|
|---|
| 681 |
if (nframes == 0) { |
|---|
| 682 |
/* we detected an xrun and restarted: notify |
|---|
| 683 |
* clients about the delay. |
|---|
| 684 |
*/ |
|---|
| 685 |
jack_log("FFADO XRun"); |
|---|
| 686 |
NotifyXRun(fBeginDateUst, fDelayedUsecs); |
|---|
| 687 |
goto retry; /* recoverable error*/ |
|---|
| 688 |
} |
|---|
| 689 |
|
|---|
| 690 |
if (nframes != fEngineControl->fBufferSize) |
|---|
| 691 |
jack_log("JackFFADODriver::Read warning nframes = %ld", nframes); |
|---|
| 692 |
|
|---|
| 693 |
// Has to be done before read |
|---|
| 694 |
JackDriver::CycleIncTime(); |
|---|
| 695 |
|
|---|
| 696 |
printExit(); |
|---|
| 697 |
return ffado_driver_read((ffado_driver_t *)fDriver, fEngineControl->fBufferSize); |
|---|
| 698 |
} |
|---|
| 699 |
|
|---|
| 700 |
int JackFFADODriver::Write() |
|---|
| 701 |
{ |
|---|
| 702 |
printEnter(); |
|---|
| 703 |
int res = ffado_driver_write((ffado_driver_t *)fDriver, fEngineControl->fBufferSize); |
|---|
| 704 |
printExit(); |
|---|
| 705 |
return res; |
|---|
| 706 |
} |
|---|
| 707 |
|
|---|
| 708 |
void |
|---|
| 709 |
JackFFADODriver::jack_driver_init (jack_driver_t *driver) |
|---|
| 710 |
{ |
|---|
| 711 |
memset (driver, 0, sizeof (*driver)); |
|---|
| 712 |
|
|---|
| 713 |
driver->attach = 0; |
|---|
| 714 |
driver->detach = 0; |
|---|
| 715 |
driver->write = 0; |
|---|
| 716 |
driver->read = 0; |
|---|
| 717 |
driver->null_cycle = 0; |
|---|
| 718 |
driver->bufsize = 0; |
|---|
| 719 |
driver->start = 0; |
|---|
| 720 |
driver->stop = 0; |
|---|
| 721 |
} |
|---|
| 722 |
|
|---|
| 723 |
void |
|---|
| 724 |
JackFFADODriver::jack_driver_nt_init (jack_driver_nt_t * driver) |
|---|
| 725 |
{ |
|---|
| 726 |
memset (driver, 0, sizeof (*driver)); |
|---|
| 727 |
|
|---|
| 728 |
jack_driver_init ((jack_driver_t *) driver); |
|---|
| 729 |
|
|---|
| 730 |
driver->attach = 0; |
|---|
| 731 |
driver->detach = 0; |
|---|
| 732 |
driver->bufsize = 0; |
|---|
| 733 |
driver->stop = 0; |
|---|
| 734 |
driver->start = 0; |
|---|
| 735 |
|
|---|
| 736 |
driver->nt_bufsize = 0; |
|---|
| 737 |
driver->nt_start = 0; |
|---|
| 738 |
driver->nt_stop = 0; |
|---|
| 739 |
driver->nt_attach = 0; |
|---|
| 740 |
driver->nt_detach = 0; |
|---|
| 741 |
driver->nt_run_cycle = 0; |
|---|
| 742 |
} |
|---|
| 743 |
|
|---|
| 744 |
} // end of namespace |
|---|
| 745 |
|
|---|
| 746 |
|
|---|
| 747 |
#ifdef __cplusplus |
|---|
| 748 |
extern "C" |
|---|
| 749 |
{ |
|---|
| 750 |
#endif |
|---|
| 751 |
|
|---|
| 752 |
SERVER_EXPORT const jack_driver_desc_t * |
|---|
| 753 |
driver_get_descriptor () { |
|---|
| 754 |
jack_driver_desc_t * desc; |
|---|
| 755 |
jack_driver_desc_filler_t filler; |
|---|
| 756 |
jack_driver_param_value_t value; |
|---|
| 757 |
|
|---|
| 758 |
desc = jack_driver_descriptor_construct("firewire", JackDriverMaster, "Linux FFADO API based audio backend", &filler); |
|---|
| 759 |
|
|---|
| 760 |
strcpy(value.str, "hw:0"); |
|---|
| 761 |
jack_driver_descriptor_add_parameter( |
|---|
| 762 |
desc, |
|---|
| 763 |
&filler, |
|---|
| 764 |
"device", |
|---|
| 765 |
'd', |
|---|
| 766 |
JackDriverParamString, |
|---|
| 767 |
&value, |
|---|
| 768 |
NULL, |
|---|
| 769 |
"The FireWire device to use.", |
|---|
| 770 |
"The FireWire device to use. Please consult the FFADO documentation for more info."); |
|---|
| 771 |
|
|---|
| 772 |
value.ui = 1024; |
|---|
| 773 |
jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL); |
|---|
| 774 |
|
|---|
| 775 |
value.ui = 3; |
|---|
| 776 |
jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of periods of playback latency", NULL); |
|---|
| 777 |
|
|---|
| 778 |
value.ui = 48000U; |
|---|
| 779 |
jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL); |
|---|
| 780 |
|
|---|
| 781 |
value.i = 0; |
|---|
| 782 |
jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamBool, &value, NULL, "Provide capture ports.", NULL); |
|---|
| 783 |
jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamBool, &value, NULL, "Provide playback ports.", NULL); |
|---|
| 784 |
|
|---|
| 785 |
value.i = 1; |
|---|
| 786 |
jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports.", NULL); |
|---|
| 787 |
|
|---|
| 788 |
value.ui = 0; |
|---|
| 789 |
jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency (frames)", NULL); |
|---|
| 790 |
jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency (frames)", NULL); |
|---|
| 791 |
|
|---|
| 792 |
value.ui = 0; |
|---|
| 793 |
jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "Number of input channels to provide (note: currently ignored)", NULL); |
|---|
| 794 |
jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "Number of output channels to provide (note: currently ignored)", NULL); |
|---|
| 795 |
|
|---|
| 796 |
value.ui = 3; |
|---|
| 797 |
jack_driver_descriptor_add_parameter(desc, &filler, "verbose", 'v', JackDriverParamUInt, &value, NULL, "libffado verbose level", NULL); |
|---|
| 798 |
|
|---|
| 799 |
value.i = 0; |
|---|
| 800 |
jack_driver_descriptor_add_parameter(desc, &filler, "snoop", 'X', JackDriverParamBool, &value, NULL, "Snoop firewire traffic", NULL); |
|---|
| 801 |
|
|---|
| 802 |
return desc; |
|---|
| 803 |
} |
|---|
| 804 |
|
|---|
| 805 |
SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) { |
|---|
| 806 |
const JSList * node; |
|---|
| 807 |
const jack_driver_param_t * param; |
|---|
| 808 |
|
|---|
| 809 |
ffado_jack_settings_t cmlparams; |
|---|
| 810 |
|
|---|
| 811 |
char *device_name=(char*)"hw:0"; |
|---|
| 812 |
|
|---|
| 813 |
cmlparams.period_size_set = 0; |
|---|
| 814 |
cmlparams.sample_rate_set = 0; |
|---|
| 815 |
cmlparams.buffer_size_set = 0; |
|---|
| 816 |
|
|---|
| 817 |
/* default values */ |
|---|
| 818 |
cmlparams.period_size = 1024; |
|---|
| 819 |
cmlparams.sample_rate = 48000; |
|---|
| 820 |
cmlparams.buffer_size = 3; |
|---|
| 821 |
cmlparams.playback_ports = 0; |
|---|
| 822 |
cmlparams.capture_ports = 0; |
|---|
| 823 |
cmlparams.playback_frame_latency = 0; |
|---|
| 824 |
cmlparams.capture_frame_latency = 0; |
|---|
| 825 |
|
|---|
| 826 |
cmlparams.verbose_level = 0; |
|---|
| 827 |
|
|---|
| 828 |
cmlparams.slave_mode = 0; |
|---|
| 829 |
cmlparams.snoop_mode = 0; |
|---|
| 830 |
cmlparams.device_info = NULL; |
|---|
| 831 |
|
|---|
| 832 |
for (node = params; node; node = jack_slist_next (node)) { |
|---|
| 833 |
param = (jack_driver_param_t *) node->data; |
|---|
| 834 |
|
|---|
| 835 |
switch (param->character) { |
|---|
| 836 |
case 'd': |
|---|
| 837 |
device_name = const_cast<char*>(param->value.str); |
|---|
| 838 |
break; |
|---|
| 839 |
case 'p': |
|---|
| 840 |
cmlparams.period_size = param->value.ui; |
|---|
| 841 |
cmlparams.period_size_set = 1; |
|---|
| 842 |
break; |
|---|
| 843 |
case 'n': |
|---|
| 844 |
cmlparams.buffer_size = param->value.ui; |
|---|
| 845 |
cmlparams.buffer_size_set = 1; |
|---|
| 846 |
break; |
|---|
| 847 |
case 'r': |
|---|
| 848 |
cmlparams.sample_rate = param->value.ui; |
|---|
| 849 |
cmlparams.sample_rate_set = 1; |
|---|
| 850 |
break; |
|---|
| 851 |
case 'i': |
|---|
| 852 |
cmlparams.capture_ports = param->value.ui; |
|---|
| 853 |
break; |
|---|
| 854 |
case 'o': |
|---|
| 855 |
cmlparams.playback_ports = param->value.ui; |
|---|
| 856 |
break; |
|---|
| 857 |
case 'I': |
|---|
| 858 |
cmlparams.capture_frame_latency = param->value.ui; |
|---|
| 859 |
break; |
|---|
| 860 |
case 'O': |
|---|
| 861 |
cmlparams.playback_frame_latency = param->value.ui; |
|---|
| 862 |
break; |
|---|
| 863 |
case 'x': |
|---|
| 864 |
cmlparams.slave_mode = param->value.ui; |
|---|
| 865 |
break; |
|---|
| 866 |
case 'X': |
|---|
| 867 |
cmlparams.snoop_mode = param->value.i; |
|---|
| 868 |
break; |
|---|
| 869 |
case 'v': |
|---|
| 870 |
cmlparams.verbose_level = param->value.ui; |
|---|
| 871 |
} |
|---|
| 872 |
} |
|---|
| 873 |
|
|---|
| 874 |
/* duplex is the default */ |
|---|
| 875 |
if (!cmlparams.playback_ports && !cmlparams.capture_ports) { |
|---|
| 876 |
cmlparams.playback_ports = 1; |
|---|
| 877 |
cmlparams.capture_ports = 1; |
|---|
| 878 |
} |
|---|
| 879 |
|
|---|
| 880 |
// temporary |
|---|
| 881 |
cmlparams.device_info = device_name; |
|---|
| 882 |
|
|---|
| 883 |
Jack::JackFFADODriver* ffado_driver = new Jack::JackFFADODriver("system", "firewire_pcm", engine, table); |
|---|
| 884 |
Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(ffado_driver); |
|---|
| 885 |
// Special open for FFADO driver... |
|---|
| 886 |
if (ffado_driver->Open(&cmlparams) == 0) { |
|---|
| 887 |
return threaded_driver; |
|---|
| 888 |
} else { |
|---|
| 889 |
delete threaded_driver; // Delete the decorated driver |
|---|
| 890 |
return NULL; |
|---|
| 891 |
} |
|---|
| 892 |
} |
|---|
| 893 |
|
|---|
| 894 |
#ifdef __cplusplus |
|---|
| 895 |
} |
|---|
| 896 |
#endif |
|---|
| 897 |
|
|---|
| 898 |
|
|---|