1 |
/* |
---|
2 |
* FireWire Backend for Jack |
---|
3 |
* using FFADO |
---|
4 |
* FFADO = Firewire (pro-)audio for linux |
---|
5 |
* |
---|
6 |
* http://ffado.sf.net |
---|
7 |
* http://jackit.sf.net |
---|
8 |
* |
---|
9 |
* Copyright (C) 2005-2007 Pieter Palmers |
---|
10 |
* |
---|
11 |
* This program is free software; you can redistribute it and/or modify |
---|
12 |
* it under the terms of the GNU General Public License as published by |
---|
13 |
* the Free Software Foundation; either version 2 of the License, or |
---|
14 |
* (at your option) any later version. |
---|
15 |
* |
---|
16 |
* This program is distributed in the hope that it will be useful, |
---|
17 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
18 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
19 |
* GNU General Public License for more details. |
---|
20 |
* |
---|
21 |
* You should have received a copy of the GNU General Public License |
---|
22 |
* along with this program; if not, write to the Free Software |
---|
23 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
24 |
*/ |
---|
25 |
|
---|
26 |
/* |
---|
27 |
* Main Jack driver entry routines |
---|
28 |
* |
---|
29 |
*/ |
---|
30 |
|
---|
31 |
#include <math.h> |
---|
32 |
#include <stdio.h> |
---|
33 |
#include <memory.h> |
---|
34 |
#include <unistd.h> |
---|
35 |
#include <stdlib.h> |
---|
36 |
#include <errno.h> |
---|
37 |
#include <stdarg.h> |
---|
38 |
#include <sys/mman.h> |
---|
39 |
|
---|
40 |
#include <jack/types.h> |
---|
41 |
#include <jack/internal.h> |
---|
42 |
#include <jack/engine.h> |
---|
43 |
#include <sysdeps/time.h> |
---|
44 |
|
---|
45 |
#include "ffado_driver.h" |
---|
46 |
|
---|
47 |
#define SAMPLE_MAX_24BIT 8388608.0f |
---|
48 |
#define SAMPLE_MAX_16BIT 32768.0f |
---|
49 |
|
---|
50 |
static int ffado_driver_stop (ffado_driver_t *driver); |
---|
51 |
|
---|
52 |
#ifdef FFADO_DRIVER_WITH_ASEQ_MIDI |
---|
53 |
static ffado_driver_midi_handle_t *ffado_driver_midi_init(ffado_driver_t *driver); |
---|
54 |
static void ffado_driver_midi_finish (ffado_driver_midi_handle_t *m); |
---|
55 |
static int ffado_driver_midi_start (ffado_driver_midi_handle_t *m); |
---|
56 |
static int ffado_driver_midi_stop (ffado_driver_midi_handle_t *m); |
---|
57 |
#endif |
---|
58 |
|
---|
59 |
// enable verbose messages |
---|
60 |
static int g_verbose=0; |
---|
61 |
|
---|
62 |
static int |
---|
63 |
ffado_driver_attach (ffado_driver_t *driver) |
---|
64 |
{ |
---|
65 |
char buf[64]; |
---|
66 |
channel_t chn; |
---|
67 |
jack_port_t *port; |
---|
68 |
int port_flags; |
---|
69 |
|
---|
70 |
g_verbose=driver->engine->verbose; |
---|
71 |
driver->device_options.verbose=g_verbose; |
---|
72 |
|
---|
73 |
driver->engine->set_buffer_size (driver->engine, driver->period_size); |
---|
74 |
driver->engine->set_sample_rate (driver->engine, driver->sample_rate); |
---|
75 |
|
---|
76 |
/* packetizer thread options */ |
---|
77 |
driver->device_options.realtime=(driver->engine->control->real_time? 1 : 0); |
---|
78 |
|
---|
79 |
driver->device_options.packetizer_priority=driver->engine->control->client_priority + |
---|
80 |
FFADO_RT_PRIORITY_PACKETIZER_RELATIVE; |
---|
81 |
if (driver->device_options.packetizer_priority>98) { |
---|
82 |
driver->device_options.packetizer_priority=98; |
---|
83 |
} |
---|
84 |
|
---|
85 |
driver->dev=ffado_streaming_init(&driver->device_info,driver->device_options); |
---|
86 |
|
---|
87 |
if(!driver->dev) { |
---|
88 |
printError("Error creating FFADO streaming device"); |
---|
89 |
return -1; |
---|
90 |
} |
---|
91 |
|
---|
92 |
#ifdef FFADO_DRIVER_WITH_ASEQ_MIDI |
---|
93 |
driver->midi_handle=ffado_driver_midi_init(driver); |
---|
94 |
if(!driver->midi_handle) { |
---|
95 |
printError("-----------------------------------------------------------"); |
---|
96 |
printError("Error creating midi device!"); |
---|
97 |
printError("The FireWire backend will run without MIDI support."); |
---|
98 |
printError("Consult the above error messages to solve the problem. "); |
---|
99 |
printError("-----------------------------------------------------------\n\n"); |
---|
100 |
} |
---|
101 |
#endif |
---|
102 |
|
---|
103 |
if (driver->device_options.realtime) { |
---|
104 |
printMessage("Streaming thread running with Realtime scheduling, priority %d", |
---|
105 |
driver->device_options.packetizer_priority); |
---|
106 |
} else { |
---|
107 |
printMessage("Streaming thread running without Realtime scheduling"); |
---|
108 |
} |
---|
109 |
|
---|
110 |
/* ports */ |
---|
111 |
port_flags = JackPortIsOutput|JackPortIsPhysical|JackPortIsTerminal; |
---|
112 |
|
---|
113 |
driver->capture_nchannels=ffado_streaming_get_nb_capture_streams(driver->dev); |
---|
114 |
|
---|
115 |
for (chn = 0; chn < driver->capture_nchannels; chn++) { |
---|
116 |
|
---|
117 |
ffado_streaming_get_capture_stream_name(driver->dev, chn, buf, sizeof(buf) - 1); |
---|
118 |
|
---|
119 |
if(ffado_streaming_get_capture_stream_type(driver->dev, chn) != ffado_stream_type_audio) { |
---|
120 |
printMessage ("Don't register capture port %s", buf); |
---|
121 |
|
---|
122 |
// we have to add a NULL entry in the list to be able to loop over the channels in the read/write routines |
---|
123 |
driver->capture_ports = |
---|
124 |
jack_slist_append (driver->capture_ports, NULL); |
---|
125 |
} else { |
---|
126 |
printMessage ("Registering capture port %s", buf); |
---|
127 |
if ((port = jack_port_register (driver->client, buf, |
---|
128 |
JACK_DEFAULT_AUDIO_TYPE, |
---|
129 |
port_flags, 0)) == NULL) { |
---|
130 |
printError (" cannot register port for %s", buf); |
---|
131 |
break; |
---|
132 |
} |
---|
133 |
driver->capture_ports = |
---|
134 |
jack_slist_append (driver->capture_ports, port); |
---|
135 |
// setup port parameters |
---|
136 |
if(ffado_streaming_set_capture_buffer_type(driver->dev, chn, ffado_buffer_type_float)) { |
---|
137 |
printError(" cannot set port buffer type for %s", buf); |
---|
138 |
} |
---|
139 |
if (ffado_streaming_set_capture_stream_buffer(driver->dev, chn, NULL)) { |
---|
140 |
printError(" cannot configure initial port buffer for %s", buf); |
---|
141 |
} |
---|
142 |
if(ffado_streaming_capture_stream_onoff(driver->dev, chn, 1)) { |
---|
143 |
printError(" cannot enable port %s", buf); |
---|
144 |
} |
---|
145 |
} |
---|
146 |
// jack_port_set_latency (port, driver->period_size); |
---|
147 |
|
---|
148 |
} |
---|
149 |
|
---|
150 |
port_flags = JackPortIsInput|JackPortIsPhysical|JackPortIsTerminal; |
---|
151 |
|
---|
152 |
driver->playback_nchannels=ffado_streaming_get_nb_playback_streams(driver->dev); |
---|
153 |
|
---|
154 |
for (chn = 0; chn < driver->playback_nchannels; chn++) { |
---|
155 |
|
---|
156 |
ffado_streaming_get_playback_stream_name(driver->dev, chn, buf, sizeof(buf) - 1); |
---|
157 |
|
---|
158 |
if(ffado_streaming_get_playback_stream_type(driver->dev, chn) != ffado_stream_type_audio) { |
---|
159 |
printMessage ("Don't register playback port %s", buf); |
---|
160 |
|
---|
161 |
// we have to add a NULL entry in the list to be able to loop over the channels in the read/write routines |
---|
162 |
driver->playback_ports = |
---|
163 |
jack_slist_append (driver->playback_ports, NULL); |
---|
164 |
} else { |
---|
165 |
printMessage ("Registering playback port %s", buf); |
---|
166 |
if ((port = jack_port_register (driver->client, buf, |
---|
167 |
JACK_DEFAULT_AUDIO_TYPE, |
---|
168 |
port_flags, 0)) == NULL) { |
---|
169 |
printError(" cannot register port for %s", buf); |
---|
170 |
break; |
---|
171 |
} |
---|
172 |
driver->playback_ports = |
---|
173 |
jack_slist_append (driver->playback_ports, port); |
---|
174 |
|
---|
175 |
// setup port parameters |
---|
176 |
if(ffado_streaming_set_playback_buffer_type(driver->dev, chn, ffado_buffer_type_float)) { |
---|
177 |
printError(" cannot set port buffer type for %s", buf); |
---|
178 |
} |
---|
179 |
if (ffado_streaming_set_playback_stream_buffer(driver->dev, chn, NULL)) { |
---|
180 |
printError(" cannot configure initial port buffer for %s", buf); |
---|
181 |
} |
---|
182 |
if(ffado_streaming_playback_stream_onoff(driver->dev, chn, 1)) { |
---|
183 |
printError(" cannot enable port %s", buf); |
---|
184 |
} |
---|
185 |
} |
---|
186 |
// jack_port_set_latency (port, (driver->period_size * (driver->user_nperiods - 1)) + driver->playback_frame_latency); |
---|
187 |
|
---|
188 |
} |
---|
189 |
|
---|
190 |
if(!ffado_streaming_prepare(driver->dev)) { |
---|
191 |
printError("Could not prepare streaming device!"); |
---|
192 |
return -1; |
---|
193 |
} |
---|
194 |
|
---|
195 |
|
---|
196 |
return jack_activate (driver->client); |
---|
197 |
} |
---|
198 |
|
---|
199 |
static int |
---|
200 |
ffado_driver_detach (ffado_driver_t *driver) |
---|
201 |
{ |
---|
202 |
JSList *node; |
---|
203 |
|
---|
204 |
if (driver->engine == NULL) { |
---|
205 |
return 0; |
---|
206 |
} |
---|
207 |
|
---|
208 |
for (node = driver->capture_ports; node; |
---|
209 |
node = jack_slist_next (node)) { |
---|
210 |
// Don't try to unregister NULL entries added for non-audio |
---|
211 |
// ffado ports by ffado_driver_attach(). |
---|
212 |
if (node->data != NULL) { |
---|
213 |
jack_port_unregister (driver->client, |
---|
214 |
((jack_port_t *) node->data)); |
---|
215 |
} |
---|
216 |
} |
---|
217 |
|
---|
218 |
jack_slist_free (driver->capture_ports); |
---|
219 |
driver->capture_ports = 0; |
---|
220 |
|
---|
221 |
for (node = driver->playback_ports; node; |
---|
222 |
node = jack_slist_next (node)) { |
---|
223 |
if (node->data != NULL) { |
---|
224 |
jack_port_unregister (driver->client, |
---|
225 |
((jack_port_t *) node->data)); |
---|
226 |
} |
---|
227 |
} |
---|
228 |
|
---|
229 |
jack_slist_free (driver->playback_ports); |
---|
230 |
driver->playback_ports = 0; |
---|
231 |
|
---|
232 |
ffado_streaming_finish(driver->dev); |
---|
233 |
driver->dev=NULL; |
---|
234 |
|
---|
235 |
#ifdef FFADO_DRIVER_WITH_ASEQ_MIDI |
---|
236 |
if(driver->midi_handle) { |
---|
237 |
ffado_driver_midi_finish(driver->midi_handle); |
---|
238 |
} |
---|
239 |
driver->midi_handle=NULL; |
---|
240 |
#endif |
---|
241 |
|
---|
242 |
return 0; |
---|
243 |
} |
---|
244 |
|
---|
245 |
static inline void |
---|
246 |
ffado_driver_read_from_channel (ffado_driver_t *driver, |
---|
247 |
channel_t channel, |
---|
248 |
jack_default_audio_sample_t *dst, |
---|
249 |
jack_nframes_t nsamples) |
---|
250 |
{ |
---|
251 |
|
---|
252 |
ffado_sample_t buffer[nsamples]; |
---|
253 |
char *src=(char *)buffer; |
---|
254 |
|
---|
255 |
ffado_streaming_read(driver->dev, channel, buffer, nsamples); |
---|
256 |
|
---|
257 |
/* ALERT: signed sign-extension portability !!! */ |
---|
258 |
|
---|
259 |
while (nsamples--) { |
---|
260 |
int x; |
---|
261 |
#if __BYTE_ORDER == __LITTLE_ENDIAN |
---|
262 |
memcpy((char*)&x + 1, src, 3); |
---|
263 |
#elif __BYTE_ORDER == __BIG_ENDIAN |
---|
264 |
memcpy(&x, src, 3); |
---|
265 |
#endif |
---|
266 |
x >>= 8; |
---|
267 |
*dst = x / SAMPLE_MAX_24BIT; |
---|
268 |
dst++; |
---|
269 |
src += sizeof(ffado_sample_t); |
---|
270 |
} |
---|
271 |
|
---|
272 |
} |
---|
273 |
|
---|
274 |
static int |
---|
275 |
ffado_driver_read (ffado_driver_t * driver, jack_nframes_t nframes) |
---|
276 |
{ |
---|
277 |
jack_default_audio_sample_t* buf; |
---|
278 |
channel_t chn; |
---|
279 |
JSList *node; |
---|
280 |
jack_port_t* port; |
---|
281 |
|
---|
282 |
ffado_sample_t nullbuffer[nframes]; |
---|
283 |
|
---|
284 |
ffado_streaming_stream_type stream_type; |
---|
285 |
|
---|
286 |
printEnter(); |
---|
287 |
|
---|
288 |
for (chn = 0, node = driver->capture_ports; node; node = jack_slist_next (node), chn++) { |
---|
289 |
stream_type = ffado_streaming_get_capture_stream_type(driver->dev, chn); |
---|
290 |
if(stream_type == ffado_stream_type_audio) { |
---|
291 |
port = (jack_port_t *) node->data; |
---|
292 |
|
---|
293 |
buf = jack_port_get_buffer (port, nframes); |
---|
294 |
if(!buf) buf=(jack_default_audio_sample_t*)nullbuffer; |
---|
295 |
|
---|
296 |
ffado_streaming_set_capture_stream_buffer(driver->dev, chn, (char *)(buf)); |
---|
297 |
} |
---|
298 |
} |
---|
299 |
|
---|
300 |
// now transfer the buffers |
---|
301 |
ffado_streaming_transfer_capture_buffers(driver->dev); |
---|
302 |
|
---|
303 |
printExit(); |
---|
304 |
|
---|
305 |
return 0; |
---|
306 |
|
---|
307 |
} |
---|
308 |
|
---|
309 |
static inline void |
---|
310 |
ffado_driver_write_to_channel (ffado_driver_t *driver, |
---|
311 |
channel_t channel, |
---|
312 |
jack_default_audio_sample_t *buf, |
---|
313 |
jack_nframes_t nsamples) |
---|
314 |
{ |
---|
315 |
long long y; |
---|
316 |
ffado_sample_t buffer[nsamples]; |
---|
317 |
unsigned int i=0; |
---|
318 |
char *dst=(char *)buffer; |
---|
319 |
|
---|
320 |
// convert from float to integer |
---|
321 |
for(;i<nsamples;i++) { |
---|
322 |
y = (long long)(*buf * SAMPLE_MAX_24BIT); |
---|
323 |
|
---|
324 |
if (y > (INT_MAX >> 8 )) { |
---|
325 |
y = (INT_MAX >> 8); |
---|
326 |
} else if (y < (INT_MIN >> 8 )) { |
---|
327 |
y = (INT_MIN >> 8 ); |
---|
328 |
} |
---|
329 |
#if __BYTE_ORDER == __LITTLE_ENDIAN |
---|
330 |
memcpy (dst, &y, 3); |
---|
331 |
#elif __BYTE_ORDER == __BIG_ENDIAN |
---|
332 |
memcpy (dst, (char *)&y + 5, 3); |
---|
333 |
#endif |
---|
334 |
dst += sizeof(ffado_sample_t); |
---|
335 |
buf++; |
---|
336 |
} |
---|
337 |
|
---|
338 |
// write to the ffado streaming device |
---|
339 |
ffado_streaming_write(driver->dev, channel, buffer, nsamples); |
---|
340 |
|
---|
341 |
} |
---|
342 |
|
---|
343 |
static int |
---|
344 |
ffado_driver_write (ffado_driver_t * driver, jack_nframes_t nframes) |
---|
345 |
{ |
---|
346 |
channel_t chn; |
---|
347 |
JSList *node; |
---|
348 |
jack_default_audio_sample_t* buf; |
---|
349 |
|
---|
350 |
jack_port_t *port; |
---|
351 |
|
---|
352 |
ffado_streaming_stream_type stream_type; |
---|
353 |
|
---|
354 |
ffado_sample_t nullbuffer[nframes]; |
---|
355 |
|
---|
356 |
memset(&nullbuffer,0,nframes*sizeof(ffado_sample_t)); |
---|
357 |
|
---|
358 |
printEnter(); |
---|
359 |
|
---|
360 |
driver->process_count++; |
---|
361 |
|
---|
362 |
assert(driver->dev); |
---|
363 |
|
---|
364 |
if (driver->engine->freewheeling) { |
---|
365 |
return 0; |
---|
366 |
} |
---|
367 |
|
---|
368 |
for (chn = 0, node = driver->playback_ports; node; node = jack_slist_next (node), chn++) { |
---|
369 |
stream_type=ffado_streaming_get_playback_stream_type(driver->dev, chn); |
---|
370 |
if(stream_type == ffado_stream_type_audio) { |
---|
371 |
port = (jack_port_t *) node->data; |
---|
372 |
|
---|
373 |
buf = jack_port_get_buffer (port, nframes); |
---|
374 |
if(!buf) buf=(jack_default_audio_sample_t*)nullbuffer; |
---|
375 |
|
---|
376 |
ffado_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(buf)); |
---|
377 |
} |
---|
378 |
} |
---|
379 |
|
---|
380 |
ffado_streaming_transfer_playback_buffers(driver->dev); |
---|
381 |
|
---|
382 |
printExit(); |
---|
383 |
|
---|
384 |
return 0; |
---|
385 |
} |
---|
386 |
|
---|
387 |
//static inline jack_nframes_t |
---|
388 |
static jack_nframes_t |
---|
389 |
ffado_driver_wait (ffado_driver_t *driver, int extra_fd, int *status, |
---|
390 |
float *delayed_usecs) |
---|
391 |
{ |
---|
392 |
int nframes; |
---|
393 |
jack_time_t wait_enter; |
---|
394 |
jack_time_t wait_ret; |
---|
395 |
|
---|
396 |
printEnter(); |
---|
397 |
|
---|
398 |
wait_enter = jack_get_microseconds (); |
---|
399 |
if (wait_enter > driver->wait_next) { |
---|
400 |
/* |
---|
401 |
* This processing cycle was delayed past the |
---|
402 |
* next due interrupt! Do not account this as |
---|
403 |
* a wakeup delay: |
---|
404 |
*/ |
---|
405 |
driver->wait_next = 0; |
---|
406 |
driver->wait_late++; |
---|
407 |
} |
---|
408 |
// *status = -2; interrupt |
---|
409 |
// *status = -3; timeout |
---|
410 |
// *status = -4; extra FD |
---|
411 |
|
---|
412 |
nframes=ffado_streaming_wait(driver->dev); |
---|
413 |
|
---|
414 |
wait_ret = jack_get_microseconds (); |
---|
415 |
|
---|
416 |
if (driver->wait_next && wait_ret > driver->wait_next) { |
---|
417 |
*delayed_usecs = wait_ret - driver->wait_next; |
---|
418 |
} |
---|
419 |
driver->wait_last = wait_ret; |
---|
420 |
driver->wait_next = wait_ret + driver->period_usecs; |
---|
421 |
driver->engine->transport_cycle_start (driver->engine, wait_ret); |
---|
422 |
|
---|
423 |
// transfer the streaming buffers |
---|
424 |
// we now do this in the read/write functions |
---|
425 |
// ffado_streaming_transfer_buffers(driver->dev); |
---|
426 |
|
---|
427 |
if (nframes < 0) { |
---|
428 |
*status=0; |
---|
429 |
|
---|
430 |
return 0; |
---|
431 |
//nframes=driver->period_size; //debug |
---|
432 |
} |
---|
433 |
|
---|
434 |
*status = 0; |
---|
435 |
driver->last_wait_ust = wait_ret; |
---|
436 |
|
---|
437 |
// FIXME: this should do something more usefull |
---|
438 |
*delayed_usecs = 0; |
---|
439 |
|
---|
440 |
printExit(); |
---|
441 |
|
---|
442 |
return nframes - nframes % driver->period_size; |
---|
443 |
|
---|
444 |
} |
---|
445 |
|
---|
446 |
static int |
---|
447 |
ffado_driver_run_cycle (ffado_driver_t *driver) |
---|
448 |
{ |
---|
449 |
jack_engine_t *engine = driver->engine; |
---|
450 |
int wait_status=0; |
---|
451 |
float delayed_usecs=0.0; |
---|
452 |
|
---|
453 |
jack_nframes_t nframes = ffado_driver_wait (driver, -1, |
---|
454 |
&wait_status, &delayed_usecs); |
---|
455 |
|
---|
456 |
if ((wait_status < 0)) { |
---|
457 |
printError( "wait status < 0! (= %d)",wait_status); |
---|
458 |
return -1; |
---|
459 |
} |
---|
460 |
|
---|
461 |
if ((nframes == 0)) { |
---|
462 |
/* we detected an xrun and restarted: notify |
---|
463 |
* clients about the delay. */ |
---|
464 |
printMessage("xrun detected"); |
---|
465 |
engine->delay (engine, delayed_usecs); |
---|
466 |
return 0; |
---|
467 |
} |
---|
468 |
|
---|
469 |
return engine->run_cycle (engine, nframes, delayed_usecs); |
---|
470 |
|
---|
471 |
} |
---|
472 |
/* |
---|
473 |
* in a null cycle we should discard the input and write silence to the outputs |
---|
474 |
*/ |
---|
475 |
static int |
---|
476 |
ffado_driver_null_cycle (ffado_driver_t* driver, jack_nframes_t nframes) |
---|
477 |
{ |
---|
478 |
channel_t chn; |
---|
479 |
JSList *node; |
---|
480 |
snd_pcm_sframes_t nwritten; |
---|
481 |
|
---|
482 |
ffado_streaming_stream_type stream_type; |
---|
483 |
|
---|
484 |
jack_default_audio_sample_t buff[nframes]; |
---|
485 |
jack_default_audio_sample_t* buffer=(jack_default_audio_sample_t*)buff; |
---|
486 |
|
---|
487 |
printEnter(); |
---|
488 |
|
---|
489 |
memset(buffer,0,nframes*sizeof(jack_default_audio_sample_t)); |
---|
490 |
|
---|
491 |
assert(driver->dev); |
---|
492 |
|
---|
493 |
if (driver->engine->freewheeling) { |
---|
494 |
return 0; |
---|
495 |
} |
---|
496 |
|
---|
497 |
// write silence to buffer |
---|
498 |
nwritten = 0; |
---|
499 |
|
---|
500 |
for (chn = 0, node = driver->playback_ports; node; node = jack_slist_next (node), chn++) { |
---|
501 |
stream_type=ffado_streaming_get_playback_stream_type(driver->dev, chn); |
---|
502 |
|
---|
503 |
if(stream_type == ffado_stream_type_audio) { |
---|
504 |
ffado_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(buffer)); |
---|
505 |
} |
---|
506 |
} |
---|
507 |
|
---|
508 |
ffado_streaming_transfer_playback_buffers(driver->dev); |
---|
509 |
|
---|
510 |
// read & discard from input ports |
---|
511 |
for (chn = 0, node = driver->capture_ports; node; node = jack_slist_next (node), chn++) { |
---|
512 |
stream_type=ffado_streaming_get_capture_stream_type(driver->dev, chn); |
---|
513 |
if(stream_type == ffado_stream_type_audio) { |
---|
514 |
ffado_streaming_set_capture_stream_buffer(driver->dev, chn, (char *)(buffer)); |
---|
515 |
} |
---|
516 |
} |
---|
517 |
|
---|
518 |
// now transfer the buffers |
---|
519 |
ffado_streaming_transfer_capture_buffers(driver->dev); |
---|
520 |
|
---|
521 |
printExit(); |
---|
522 |
return 0; |
---|
523 |
} |
---|
524 |
|
---|
525 |
static int |
---|
526 |
ffado_driver_start (ffado_driver_t *driver) |
---|
527 |
{ |
---|
528 |
int retval=0; |
---|
529 |
|
---|
530 |
#ifdef FFADO_DRIVER_WITH_ASEQ_MIDI |
---|
531 |
if(driver->midi_handle) { |
---|
532 |
if((retval=ffado_driver_midi_start(driver->midi_handle))) { |
---|
533 |
printError("Could not start MIDI threads"); |
---|
534 |
return retval; |
---|
535 |
} |
---|
536 |
} |
---|
537 |
#endif |
---|
538 |
|
---|
539 |
if((retval=ffado_streaming_start(driver->dev))) { |
---|
540 |
printError("Could not start streaming threads"); |
---|
541 |
#ifdef FFADO_DRIVER_WITH_ASEQ_MIDI |
---|
542 |
if(driver->midi_handle) { |
---|
543 |
ffado_driver_midi_stop(driver->midi_handle); |
---|
544 |
} |
---|
545 |
#endif |
---|
546 |
return retval; |
---|
547 |
} |
---|
548 |
|
---|
549 |
return 0; |
---|
550 |
|
---|
551 |
} |
---|
552 |
|
---|
553 |
static int |
---|
554 |
ffado_driver_stop (ffado_driver_t *driver) |
---|
555 |
{ |
---|
556 |
int retval=0; |
---|
557 |
|
---|
558 |
#ifdef FFADO_DRIVER_WITH_ASEQ_MIDI |
---|
559 |
if(driver->midi_handle) { |
---|
560 |
if((retval=ffado_driver_midi_stop(driver->midi_handle))) { |
---|
561 |
printError("Could not stop MIDI threads"); |
---|
562 |
return retval; |
---|
563 |
} |
---|
564 |
} |
---|
565 |
#endif |
---|
566 |
if((retval=ffado_streaming_stop(driver->dev))) { |
---|
567 |
printError("Could not stop streaming threads"); |
---|
568 |
return retval; |
---|
569 |
} |
---|
570 |
|
---|
571 |
return 0; |
---|
572 |
} |
---|
573 |
|
---|
574 |
|
---|
575 |
static int |
---|
576 |
ffado_driver_bufsize (ffado_driver_t* driver, jack_nframes_t nframes) |
---|
577 |
{ |
---|
578 |
printError("Buffer size change requested but not supported!!!"); |
---|
579 |
|
---|
580 |
/* |
---|
581 |
driver->period_size = nframes; |
---|
582 |
driver->period_usecs = |
---|
583 |
(jack_time_t) floor ((((float) nframes) / driver->sample_rate) |
---|
584 |
* 1000000.0f); |
---|
585 |
*/ |
---|
586 |
|
---|
587 |
/* tell the engine to change its buffer size */ |
---|
588 |
//driver->engine->set_buffer_size (driver->engine, nframes); |
---|
589 |
|
---|
590 |
return -1; // unsupported |
---|
591 |
} |
---|
592 |
|
---|
593 |
typedef void (*JackDriverFinishFunction) (jack_driver_t *); |
---|
594 |
|
---|
595 |
ffado_driver_t * |
---|
596 |
ffado_driver_new (jack_client_t * client, |
---|
597 |
char *name, |
---|
598 |
ffado_jack_settings_t *params) |
---|
599 |
{ |
---|
600 |
ffado_driver_t *driver; |
---|
601 |
|
---|
602 |
assert(params); |
---|
603 |
|
---|
604 |
if(ffado_get_api_version() != 2) { |
---|
605 |
printError("Incompatible libffado version! (%s)", ffado_get_version()); |
---|
606 |
return NULL; |
---|
607 |
} |
---|
608 |
|
---|
609 |
printMessage("Starting Freebob backend (%s)", ffado_get_version()); |
---|
610 |
|
---|
611 |
driver = calloc (1, sizeof (ffado_driver_t)); |
---|
612 |
|
---|
613 |
/* Setup the jack interfaces */ |
---|
614 |
jack_driver_nt_init ((jack_driver_nt_t *) driver); |
---|
615 |
|
---|
616 |
driver->nt_attach = (JackDriverNTAttachFunction) ffado_driver_attach; |
---|
617 |
driver->nt_detach = (JackDriverNTDetachFunction) ffado_driver_detach; |
---|
618 |
driver->nt_start = (JackDriverNTStartFunction) ffado_driver_start; |
---|
619 |
driver->nt_stop = (JackDriverNTStopFunction) ffado_driver_stop; |
---|
620 |
driver->nt_run_cycle = (JackDriverNTRunCycleFunction) ffado_driver_run_cycle; |
---|
621 |
driver->null_cycle = (JackDriverNullCycleFunction) ffado_driver_null_cycle; |
---|
622 |
driver->write = (JackDriverReadFunction) ffado_driver_write; |
---|
623 |
driver->read = (JackDriverReadFunction) ffado_driver_read; |
---|
624 |
driver->nt_bufsize = (JackDriverNTBufSizeFunction) ffado_driver_bufsize; |
---|
625 |
|
---|
626 |
/* copy command line parameter contents to the driver structure */ |
---|
627 |
memcpy(&driver->settings,params,sizeof(ffado_jack_settings_t)); |
---|
628 |
|
---|
629 |
/* prepare all parameters */ |
---|
630 |
driver->sample_rate = params->sample_rate; |
---|
631 |
driver->period_size = params->period_size; |
---|
632 |
driver->last_wait_ust = 0; |
---|
633 |
|
---|
634 |
driver->period_usecs = |
---|
635 |
(jack_time_t) floor ((((float) driver->period_size) * 1000000.0f) / driver->sample_rate); |
---|
636 |
|
---|
637 |
driver->client = client; |
---|
638 |
driver->engine = NULL; |
---|
639 |
|
---|
640 |
memset(&driver->device_options,0,sizeof(driver->device_options)); |
---|
641 |
driver->device_options.sample_rate=params->sample_rate; |
---|
642 |
driver->device_options.period_size=params->period_size; |
---|
643 |
driver->device_options.nb_buffers=params->buffer_size; |
---|
644 |
driver->device_options.node_id=params->node_id; |
---|
645 |
driver->device_options.port=params->port; |
---|
646 |
driver->device_options.slave_mode=params->slave_mode; |
---|
647 |
driver->device_options.snoop_mode=params->snoop_mode; |
---|
648 |
|
---|
649 |
if(!params->capture_ports) { |
---|
650 |
driver->device_options.directions |= FFADO_IGNORE_CAPTURE; |
---|
651 |
} |
---|
652 |
|
---|
653 |
if(!params->playback_ports) { |
---|
654 |
driver->device_options.directions |= FFADO_IGNORE_PLAYBACK; |
---|
655 |
} |
---|
656 |
|
---|
657 |
debugPrint(DEBUG_LEVEL_STARTUP, " Driver compiled on %s %s", __DATE__, __TIME__); |
---|
658 |
debugPrint(DEBUG_LEVEL_STARTUP, " Created driver %s", name); |
---|
659 |
debugPrint(DEBUG_LEVEL_STARTUP, " period_size: %d", driver->period_size); |
---|
660 |
debugPrint(DEBUG_LEVEL_STARTUP, " period_usecs: %d", driver->period_usecs); |
---|
661 |
debugPrint(DEBUG_LEVEL_STARTUP, " sample rate: %d", driver->sample_rate); |
---|
662 |
|
---|
663 |
return (ffado_driver_t *) driver; |
---|
664 |
|
---|
665 |
} |
---|
666 |
|
---|
667 |
static void |
---|
668 |
ffado_driver_delete (ffado_driver_t *driver) |
---|
669 |
{ |
---|
670 |
jack_driver_nt_finish ((jack_driver_nt_t *) driver); |
---|
671 |
free (driver); |
---|
672 |
} |
---|
673 |
|
---|
674 |
#ifdef FFADO_DRIVER_WITH_ASEQ_MIDI |
---|
675 |
/* |
---|
676 |
* MIDI support |
---|
677 |
*/ |
---|
678 |
|
---|
679 |
// the thread that will queue the midi events from the seq to the stream buffers |
---|
680 |
|
---|
681 |
void * ffado_driver_midi_queue_thread(void *arg) |
---|
682 |
{ |
---|
683 |
ffado_driver_midi_handle_t *m=(ffado_driver_midi_handle_t *)arg; |
---|
684 |
assert(m); |
---|
685 |
snd_seq_event_t *ev; |
---|
686 |
unsigned char work_buffer[MIDI_TRANSMIT_BUFFER_SIZE]; |
---|
687 |
int bytes_to_send; |
---|
688 |
int b; |
---|
689 |
int i; |
---|
690 |
|
---|
691 |
printMessage("MIDI queue thread started"); |
---|
692 |
|
---|
693 |
while(1) { |
---|
694 |
// get next event, if one is present |
---|
695 |
while ((snd_seq_event_input(m->seq_handle, &ev) > 0)) { |
---|
696 |
// get the port this event is originated from |
---|
697 |
ffado_midi_port_t *port=NULL; |
---|
698 |
for (i=0;i<m->nb_output_ports;i++) { |
---|
699 |
if(m->output_ports[i]->seq_port_nr == ev->dest.port) { |
---|
700 |
port=m->output_ports[i]; |
---|
701 |
break; |
---|
702 |
} |
---|
703 |
} |
---|
704 |
|
---|
705 |
if(!port) { |
---|
706 |
printError(" Could not find target port for event: dst=%d src=%d", ev->dest.port, ev->source.port); |
---|
707 |
|
---|
708 |
break; |
---|
709 |
} |
---|
710 |
|
---|
711 |
// decode it to the work buffer |
---|
712 |
if((bytes_to_send = snd_midi_event_decode ( port->parser, |
---|
713 |
work_buffer, |
---|
714 |
MIDI_TRANSMIT_BUFFER_SIZE, |
---|
715 |
ev))<0) |
---|
716 |
{ // failed |
---|
717 |
printError(" Error decoding event for port %d (errcode=%d)", port->seq_port_nr,bytes_to_send); |
---|
718 |
bytes_to_send=0; |
---|
719 |
//return -1; |
---|
720 |
} |
---|
721 |
|
---|
722 |
for(b=0;b<bytes_to_send;b++) { |
---|
723 |
ffado_sample_t tmp_event=work_buffer[b]; |
---|
724 |
if(ffado_streaming_write(m->dev, port->stream_nr, &tmp_event, 1)<1) { |
---|
725 |
printError(" Midi send buffer overrun"); |
---|
726 |
} |
---|
727 |
} |
---|
728 |
|
---|
729 |
} |
---|
730 |
|
---|
731 |
// sleep for some time |
---|
732 |
usleep(MIDI_THREAD_SLEEP_TIME_USECS); |
---|
733 |
} |
---|
734 |
return NULL; |
---|
735 |
} |
---|
736 |
|
---|
737 |
// the dequeue thread (maybe we need one thread per stream) |
---|
738 |
void *ffado_driver_midi_dequeue_thread (void *arg) { |
---|
739 |
ffado_driver_midi_handle_t *m=(ffado_driver_midi_handle_t *)arg; |
---|
740 |
|
---|
741 |
int i; |
---|
742 |
int s; |
---|
743 |
|
---|
744 |
int samples_read; |
---|
745 |
|
---|
746 |
assert(m); |
---|
747 |
|
---|
748 |
while(1) { |
---|
749 |
// read incoming events |
---|
750 |
|
---|
751 |
for (i=0;i<m->nb_input_ports;i++) { |
---|
752 |
unsigned int buff[64]; |
---|
753 |
|
---|
754 |
ffado_midi_port_t *port=m->input_ports[i]; |
---|
755 |
|
---|
756 |
if(!port) { |
---|
757 |
printError(" something went wrong when setting up the midi input port map (%d)",i); |
---|
758 |
} |
---|
759 |
|
---|
760 |
do { |
---|
761 |
samples_read=ffado_streaming_read(m->dev, port->stream_nr, buff, 64); |
---|
762 |
|
---|
763 |
for (s=0;s<samples_read;s++) { |
---|
764 |
unsigned int *byte=(buff+s) ; |
---|
765 |
snd_seq_event_t ev; |
---|
766 |
if ((snd_midi_event_encode_byte(port->parser,(*byte) & 0xFF, &ev)) > 0) { |
---|
767 |
// a midi message is complete, send it out to ALSA |
---|
768 |
snd_seq_ev_set_subs(&ev); |
---|
769 |
snd_seq_ev_set_direct(&ev); |
---|
770 |
snd_seq_ev_set_source(&ev, port->seq_port_nr); |
---|
771 |
snd_seq_event_output_direct(port->seq_handle, &ev); |
---|
772 |
} |
---|
773 |
} |
---|
774 |
} while (samples_read>0); |
---|
775 |
} |
---|
776 |
|
---|
777 |
// sleep for some time |
---|
778 |
usleep(MIDI_THREAD_SLEEP_TIME_USECS); |
---|
779 |
} |
---|
780 |
return NULL; |
---|
781 |
} |
---|
782 |
|
---|
783 |
static ffado_driver_midi_handle_t *ffado_driver_midi_init(ffado_driver_t *driver) { |
---|
784 |
// int err; |
---|
785 |
|
---|
786 |
char buf[256]; |
---|
787 |
channel_t chn; |
---|
788 |
int nchannels; |
---|
789 |
int i=0; |
---|
790 |
|
---|
791 |
ffado_device_t *dev=driver->dev; |
---|
792 |
|
---|
793 |
assert(dev); |
---|
794 |
|
---|
795 |
ffado_driver_midi_handle_t *m=calloc(1,sizeof(ffado_driver_midi_handle_t)); |
---|
796 |
if (!m) { |
---|
797 |
printError("not enough memory to create midi structure"); |
---|
798 |
return NULL; |
---|
799 |
} |
---|
800 |
|
---|
801 |
if (snd_seq_open(&m->seq_handle, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK) < 0) { |
---|
802 |
printError("Error opening ALSA sequencer."); |
---|
803 |
free(m); |
---|
804 |
return NULL; |
---|
805 |
} |
---|
806 |
|
---|
807 |
snd_seq_set_client_name(m->seq_handle, "FreeBoB Jack MIDI"); |
---|
808 |
|
---|
809 |
// find out the number of midi in/out ports we need to setup |
---|
810 |
nchannels=ffado_streaming_get_nb_capture_streams(dev); |
---|
811 |
|
---|
812 |
m->nb_input_ports=0; |
---|
813 |
|
---|
814 |
for (chn = 0; chn < nchannels; chn++) { |
---|
815 |
if(ffado_streaming_get_capture_stream_type(dev, chn) == ffado_stream_type_midi) { |
---|
816 |
m->nb_input_ports++; |
---|
817 |
} |
---|
818 |
} |
---|
819 |
|
---|
820 |
m->input_ports=calloc(m->nb_input_ports,sizeof(ffado_midi_port_t *)); |
---|
821 |
if(!m->input_ports) { |
---|
822 |
printError("not enough memory to create midi structure"); |
---|
823 |
free(m); |
---|
824 |
return NULL; |
---|
825 |
} |
---|
826 |
|
---|
827 |
i=0; |
---|
828 |
for (chn = 0; chn < nchannels; chn++) { |
---|
829 |
if(ffado_streaming_get_capture_stream_type(dev, chn) == ffado_stream_type_midi) { |
---|
830 |
m->input_ports[i]=calloc(1,sizeof(ffado_midi_port_t)); |
---|
831 |
if(!m->input_ports[i]) { |
---|
832 |
// fixme |
---|
833 |
printError("Could not allocate memory for seq port"); |
---|
834 |
continue; |
---|
835 |
} |
---|
836 |
|
---|
837 |
ffado_streaming_get_capture_stream_name(dev, chn, buf, sizeof(buf) - 1); |
---|
838 |
printMessage("Register MIDI IN port %s", buf); |
---|
839 |
|
---|
840 |
m->input_ports[i]->seq_port_nr=snd_seq_create_simple_port(m->seq_handle, buf, |
---|
841 |
SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, |
---|
842 |
SND_SEQ_PORT_TYPE_MIDI_GENERIC); |
---|
843 |
|
---|
844 |
if(m->input_ports[i]->seq_port_nr<0) { |
---|
845 |
printError("Could not create seq port"); |
---|
846 |
m->input_ports[i]->stream_nr=-1; |
---|
847 |
m->input_ports[i]->seq_port_nr=-1; |
---|
848 |
} else { |
---|
849 |
m->input_ports[i]->stream_nr=chn; |
---|
850 |
m->input_ports[i]->seq_handle=m->seq_handle; |
---|
851 |
if (snd_midi_event_new ( ALSA_SEQ_BUFF_SIZE, &(m->input_ports[i]->parser)) < 0) { |
---|
852 |
printError("could not init parser for MIDI IN port %d",i); |
---|
853 |
m->input_ports[i]->stream_nr=-1; |
---|
854 |
m->input_ports[i]->seq_port_nr=-1; |
---|
855 |
} else { |
---|
856 |
if(ffado_streaming_set_capture_buffer_type(dev, chn, ffado_buffer_type_midi)) { |
---|
857 |
printError(" cannot set port buffer type for %s", buf); |
---|
858 |
m->input_ports[i]->stream_nr=-1; |
---|
859 |
m->input_ports[i]->seq_port_nr=-1; |
---|
860 |
} |
---|
861 |
if(ffado_streaming_capture_stream_onoff(dev, chn, 1)) { |
---|
862 |
printError(" cannot enable port %s", buf); |
---|
863 |
m->input_ports[i]->stream_nr=-1; |
---|
864 |
m->input_ports[i]->seq_port_nr=-1; |
---|
865 |
} |
---|
866 |
|
---|
867 |
} |
---|
868 |
} |
---|
869 |
|
---|
870 |
i++; |
---|
871 |
} |
---|
872 |
} |
---|
873 |
|
---|
874 |
// playback |
---|
875 |
nchannels=ffado_streaming_get_nb_playback_streams(dev); |
---|
876 |
|
---|
877 |
m->nb_output_ports=0; |
---|
878 |
|
---|
879 |
for (chn = 0; chn < nchannels; chn++) { |
---|
880 |
if(ffado_streaming_get_playback_stream_type(dev, chn) == ffado_stream_type_midi) { |
---|
881 |
m->nb_output_ports++; |
---|
882 |
} |
---|
883 |
} |
---|
884 |
|
---|
885 |
m->output_ports=calloc(m->nb_output_ports,sizeof(ffado_midi_port_t *)); |
---|
886 |
if(!m->output_ports) { |
---|
887 |
printError("not enough memory to create midi structure"); |
---|
888 |
for (i = 0; i < m->nb_input_ports; i++) { |
---|
889 |
free(m->input_ports[i]); |
---|
890 |
} |
---|
891 |
free(m->input_ports); |
---|
892 |
free(m); |
---|
893 |
return NULL; |
---|
894 |
} |
---|
895 |
|
---|
896 |
i=0; |
---|
897 |
for (chn = 0; chn < nchannels; chn++) { |
---|
898 |
if(ffado_streaming_get_playback_stream_type(dev, chn) == ffado_stream_type_midi) { |
---|
899 |
m->output_ports[i]=calloc(1,sizeof(ffado_midi_port_t)); |
---|
900 |
if(!m->output_ports[i]) { |
---|
901 |
// fixme |
---|
902 |
printError("Could not allocate memory for seq port"); |
---|
903 |
continue; |
---|
904 |
} |
---|
905 |
|
---|
906 |
ffado_streaming_get_playback_stream_name(dev, chn, buf, sizeof(buf) - 1); |
---|
907 |
printMessage("Register MIDI OUT port %s", buf); |
---|
908 |
|
---|
909 |
m->output_ports[i]->seq_port_nr=snd_seq_create_simple_port(m->seq_handle, buf, |
---|
910 |
SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, |
---|
911 |
SND_SEQ_PORT_TYPE_MIDI_GENERIC); |
---|
912 |
|
---|
913 |
|
---|
914 |
if(m->output_ports[i]->seq_port_nr<0) { |
---|
915 |
printError("Could not create seq port"); |
---|
916 |
m->output_ports[i]->stream_nr=-1; |
---|
917 |
m->output_ports[i]->seq_port_nr=-1; |
---|
918 |
} else { |
---|
919 |
m->output_ports[i]->stream_nr=chn; |
---|
920 |
m->output_ports[i]->seq_handle=m->seq_handle; |
---|
921 |
if (snd_midi_event_new ( ALSA_SEQ_BUFF_SIZE, &(m->output_ports[i]->parser)) < 0) { |
---|
922 |
printError("could not init parser for MIDI OUT port %d",i); |
---|
923 |
m->output_ports[i]->stream_nr=-1; |
---|
924 |
m->output_ports[i]->seq_port_nr=-1; |
---|
925 |
} else { |
---|
926 |
if(ffado_streaming_set_playback_buffer_type(dev, chn, ffado_buffer_type_midi)) { |
---|
927 |
printError(" cannot set port buffer type for %s", buf); |
---|
928 |
m->input_ports[i]->stream_nr=-1; |
---|
929 |
m->input_ports[i]->seq_port_nr=-1; |
---|
930 |
} |
---|
931 |
if(ffado_streaming_playback_stream_onoff(dev, chn, 1)) { |
---|
932 |
printError(" cannot enable port %s", buf); |
---|
933 |
m->input_ports[i]->stream_nr=-1; |
---|
934 |
m->input_ports[i]->seq_port_nr=-1; |
---|
935 |
} |
---|
936 |
} |
---|
937 |
} |
---|
938 |
|
---|
939 |
i++; |
---|
940 |
} |
---|
941 |
} |
---|
942 |
|
---|
943 |
m->dev=dev; |
---|
944 |
m->driver=driver; |
---|
945 |
|
---|
946 |
return m; |
---|
947 |
} |
---|
948 |
|
---|
949 |
static int |
---|
950 |
ffado_driver_midi_start (ffado_driver_midi_handle_t *m) |
---|
951 |
{ |
---|
952 |
assert(m); |
---|
953 |
// start threads |
---|
954 |
|
---|
955 |
m->queue_thread_realtime=(m->driver->engine->control->real_time? 1 : 0); |
---|
956 |
m->queue_thread_priority= |
---|
957 |
m->driver->engine->control->client_priority + |
---|
958 |
FFADO_RT_PRIORITY_MIDI_RELATIVE; |
---|
959 |
|
---|
960 |
if (m->queue_thread_priority>98) { |
---|
961 |
m->queue_thread_priority=98; |
---|
962 |
} |
---|
963 |
if (m->queue_thread_realtime) { |
---|
964 |
printMessage("MIDI threads running with Realtime scheduling, priority %d", |
---|
965 |
m->queue_thread_priority); |
---|
966 |
} else { |
---|
967 |
printMessage("MIDI threads running without Realtime scheduling"); |
---|
968 |
} |
---|
969 |
|
---|
970 |
if (jack_client_create_thread(NULL, &m->queue_thread, m->queue_thread_priority, m->queue_thread_realtime, ffado_driver_midi_queue_thread, (void *)m)) { |
---|
971 |
printError(" cannot create midi queueing thread"); |
---|
972 |
return -1; |
---|
973 |
} |
---|
974 |
|
---|
975 |
if (jack_client_create_thread(NULL, &m->dequeue_thread, m->queue_thread_priority, m->queue_thread_realtime, ffado_driver_midi_dequeue_thread, (void *)m)) { |
---|
976 |
printError(" cannot create midi dequeueing thread"); |
---|
977 |
return -1; |
---|
978 |
} |
---|
979 |
return 0; |
---|
980 |
} |
---|
981 |
|
---|
982 |
static int |
---|
983 |
ffado_driver_midi_stop (ffado_driver_midi_handle_t *m) |
---|
984 |
{ |
---|
985 |
assert(m); |
---|
986 |
|
---|
987 |
pthread_cancel (m->queue_thread); |
---|
988 |
pthread_join (m->queue_thread, NULL); |
---|
989 |
|
---|
990 |
pthread_cancel (m->dequeue_thread); |
---|
991 |
pthread_join (m->dequeue_thread, NULL); |
---|
992 |
return 0; |
---|
993 |
|
---|
994 |
} |
---|
995 |
|
---|
996 |
static void |
---|
997 |
ffado_driver_midi_finish (ffado_driver_midi_handle_t *m) |
---|
998 |
{ |
---|
999 |
assert(m); |
---|
1000 |
|
---|
1001 |
int i; |
---|
1002 |
// TODO: add state info here, if not stopped then stop |
---|
1003 |
|
---|
1004 |
for (i=0;i<m->nb_input_ports;i++) { |
---|
1005 |
free(m->input_ports[i]); |
---|
1006 |
|
---|
1007 |
} |
---|
1008 |
free(m->input_ports); |
---|
1009 |
|
---|
1010 |
for (i=0;i<m->nb_output_ports;i++) { |
---|
1011 |
free(m->output_ports[i]); |
---|
1012 |
} |
---|
1013 |
free(m->output_ports); |
---|
1014 |
|
---|
1015 |
free(m); |
---|
1016 |
} |
---|
1017 |
#endif |
---|
1018 |
/* |
---|
1019 |
* dlopen plugin stuff |
---|
1020 |
*/ |
---|
1021 |
|
---|
1022 |
const char driver_client_name[] = "firewire_pcm"; |
---|
1023 |
|
---|
1024 |
const jack_driver_desc_t * |
---|
1025 |
driver_get_descriptor () |
---|
1026 |
{ |
---|
1027 |
jack_driver_desc_t * desc; |
---|
1028 |
jack_driver_param_desc_t * params; |
---|
1029 |
unsigned int i; |
---|
1030 |
|
---|
1031 |
desc = calloc (1, sizeof (jack_driver_desc_t)); |
---|
1032 |
|
---|
1033 |
strcpy (desc->name, "firewire"); |
---|
1034 |
desc->nparams = 8; |
---|
1035 |
|
---|
1036 |
params = calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); |
---|
1037 |
desc->params = params; |
---|
1038 |
|
---|
1039 |
i = 0; |
---|
1040 |
strcpy (params[i].name, "device"); |
---|
1041 |
params[i].character = 'd'; |
---|
1042 |
params[i].type = JackDriverParamString; |
---|
1043 |
strcpy (params[i].value.str, "hw:0"); |
---|
1044 |
strcpy (params[i].short_desc, "The FireWire device to use. Format is: 'hw:port[,node]'."); |
---|
1045 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
1046 |
|
---|
1047 |
i++; |
---|
1048 |
strcpy (params[i].name, "period"); |
---|
1049 |
params[i].character = 'p'; |
---|
1050 |
params[i].type = JackDriverParamUInt; |
---|
1051 |
params[i].value.ui = 1024; |
---|
1052 |
strcpy (params[i].short_desc, "Frames per period"); |
---|
1053 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
1054 |
|
---|
1055 |
i++; |
---|
1056 |
strcpy (params[i].name, "nperiods"); |
---|
1057 |
params[i].character = 'n'; |
---|
1058 |
params[i].type = JackDriverParamUInt; |
---|
1059 |
params[i].value.ui = 3; |
---|
1060 |
strcpy (params[i].short_desc, "Number of periods of playback latency"); |
---|
1061 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
1062 |
|
---|
1063 |
i++; |
---|
1064 |
strcpy (params[i].name, "rate"); |
---|
1065 |
params[i].character = 'r'; |
---|
1066 |
params[i].type = JackDriverParamUInt; |
---|
1067 |
params[i].value.ui = 48000U; |
---|
1068 |
strcpy (params[i].short_desc, "Sample rate"); |
---|
1069 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
1070 |
|
---|
1071 |
i++; |
---|
1072 |
strcpy (params[i].name, "capture"); |
---|
1073 |
params[i].character = 'i'; |
---|
1074 |
params[i].type = JackDriverParamUInt; |
---|
1075 |
params[i].value.ui = 1U; |
---|
1076 |
strcpy (params[i].short_desc, "Provide capture ports."); |
---|
1077 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
1078 |
|
---|
1079 |
i++; |
---|
1080 |
strcpy (params[i].name, "playback"); |
---|
1081 |
params[i].character = 'o'; |
---|
1082 |
params[i].type = JackDriverParamUInt; |
---|
1083 |
params[i].value.ui = 1U; |
---|
1084 |
strcpy (params[i].short_desc, "Provide playback ports."); |
---|
1085 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
1086 |
|
---|
1087 |
i++; |
---|
1088 |
strcpy (params[i].name, "slave"); |
---|
1089 |
params[i].character = 'x'; |
---|
1090 |
params[i].type = JackDriverParamUInt; |
---|
1091 |
params[i].value.ui = 0U; |
---|
1092 |
strcpy (params[i].short_desc, "Act as a BounceDevice slave"); |
---|
1093 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
1094 |
|
---|
1095 |
i++; |
---|
1096 |
strcpy (params[i].name, "slave"); |
---|
1097 |
params[i].character = 'X'; |
---|
1098 |
params[i].type = JackDriverParamUInt; |
---|
1099 |
params[i].value.ui = 0U; |
---|
1100 |
strcpy (params[i].short_desc, "Operate in snoop mode"); |
---|
1101 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
1102 |
|
---|
1103 |
return desc; |
---|
1104 |
} |
---|
1105 |
|
---|
1106 |
|
---|
1107 |
jack_driver_t * |
---|
1108 |
driver_initialize (jack_client_t *client, JSList * params) |
---|
1109 |
{ |
---|
1110 |
jack_driver_t *driver; |
---|
1111 |
|
---|
1112 |
unsigned int port=0; |
---|
1113 |
unsigned int node_id=-1; |
---|
1114 |
int nbitems; |
---|
1115 |
|
---|
1116 |
const JSList * node; |
---|
1117 |
const jack_driver_param_t * param; |
---|
1118 |
|
---|
1119 |
ffado_jack_settings_t cmlparams; |
---|
1120 |
|
---|
1121 |
char *device_name="hw:0"; |
---|
1122 |
|
---|
1123 |
cmlparams.period_size_set=0; |
---|
1124 |
cmlparams.sample_rate_set=0; |
---|
1125 |
cmlparams.buffer_size_set=0; |
---|
1126 |
cmlparams.port_set=0; |
---|
1127 |
cmlparams.node_id_set=0; |
---|
1128 |
|
---|
1129 |
/* default values */ |
---|
1130 |
cmlparams.period_size=1024; |
---|
1131 |
cmlparams.sample_rate=48000; |
---|
1132 |
cmlparams.buffer_size=3; |
---|
1133 |
cmlparams.port=0; |
---|
1134 |
cmlparams.node_id=-1; |
---|
1135 |
cmlparams.playback_ports=1; |
---|
1136 |
cmlparams.capture_ports=1; |
---|
1137 |
cmlparams.slave_mode=0; |
---|
1138 |
cmlparams.snoop_mode=0; |
---|
1139 |
|
---|
1140 |
for (node = params; node; node = jack_slist_next (node)) |
---|
1141 |
{ |
---|
1142 |
param = (jack_driver_param_t *) node->data; |
---|
1143 |
|
---|
1144 |
switch (param->character) |
---|
1145 |
{ |
---|
1146 |
case 'd': |
---|
1147 |
device_name = strdup (param->value.str); |
---|
1148 |
break; |
---|
1149 |
case 'p': |
---|
1150 |
cmlparams.period_size = param->value.ui; |
---|
1151 |
cmlparams.period_size_set = 1; |
---|
1152 |
break; |
---|
1153 |
case 'n': |
---|
1154 |
cmlparams.buffer_size = param->value.ui; |
---|
1155 |
cmlparams.buffer_size_set = 1; |
---|
1156 |
break; |
---|
1157 |
case 'r': |
---|
1158 |
cmlparams.sample_rate = param->value.ui; |
---|
1159 |
cmlparams.sample_rate_set = 1; |
---|
1160 |
break; |
---|
1161 |
case 'i': |
---|
1162 |
cmlparams.capture_ports = param->value.ui; |
---|
1163 |
break; |
---|
1164 |
case 'o': |
---|
1165 |
cmlparams.playback_ports = param->value.ui; |
---|
1166 |
break; |
---|
1167 |
case 'x': |
---|
1168 |
cmlparams.slave_mode = param->value.ui; |
---|
1169 |
break; |
---|
1170 |
case 'X': |
---|
1171 |
cmlparams.snoop_mode = param->value.ui; |
---|
1172 |
break; |
---|
1173 |
} |
---|
1174 |
} |
---|
1175 |
|
---|
1176 |
nbitems=sscanf(device_name,"hw:%u,%u",&port,&node_id); |
---|
1177 |
if (nbitems<2) { |
---|
1178 |
nbitems=sscanf(device_name,"hw:%u",&port); |
---|
1179 |
|
---|
1180 |
if(nbitems < 1) { |
---|
1181 |
free(device_name); |
---|
1182 |
printError("device (-d) argument not valid\n"); |
---|
1183 |
return NULL; |
---|
1184 |
} else { |
---|
1185 |
cmlparams.port = port; |
---|
1186 |
cmlparams.port_set=1; |
---|
1187 |
|
---|
1188 |
cmlparams.node_id = -1; |
---|
1189 |
cmlparams.node_id_set=0; |
---|
1190 |
} |
---|
1191 |
} else { |
---|
1192 |
cmlparams.port = port; |
---|
1193 |
cmlparams.port_set=1; |
---|
1194 |
|
---|
1195 |
cmlparams.node_id = node_id; |
---|
1196 |
cmlparams.node_id_set=1; |
---|
1197 |
} |
---|
1198 |
|
---|
1199 |
jack_error("Freebob using Firewire port %d, node %d",cmlparams.port,cmlparams.node_id); |
---|
1200 |
|
---|
1201 |
driver=(jack_driver_t *)ffado_driver_new (client, "ffado_pcm", &cmlparams); |
---|
1202 |
|
---|
1203 |
return driver; |
---|
1204 |
} |
---|
1205 |
|
---|
1206 |
void |
---|
1207 |
driver_finish (jack_driver_t *driver) |
---|
1208 |
{ |
---|
1209 |
ffado_driver_t *drv=(ffado_driver_t *) driver; |
---|
1210 |
// If jack hasn't called the detach method, do it now. As of jack 0.101.1 |
---|
1211 |
// the detach method was not being called explicitly on closedown, and |
---|
1212 |
// we need it to at least deallocate the iso resources. |
---|
1213 |
if (drv->dev != NULL) |
---|
1214 |
ffado_driver_detach(drv); |
---|
1215 |
ffado_driver_delete (drv); |
---|
1216 |
} |
---|