1 |
/* $Id$ */ |
---|
2 |
|
---|
3 |
/* |
---|
4 |
* FreeBob Streaming API |
---|
5 |
* FreeBob = Firewire (pro-)audio for linux |
---|
6 |
* |
---|
7 |
* http://freebob.sf.net |
---|
8 |
* |
---|
9 |
* Copyright (C) 2005 Pieter Palmers <pieterpalmers@users.sourceforge.net> |
---|
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 |
*/ |
---|
28 |
|
---|
29 |
/* freebob_streaming.c |
---|
30 |
* |
---|
31 |
* Implementation of the FreeBob Streaming API |
---|
32 |
* |
---|
33 |
*/ |
---|
34 |
|
---|
35 |
#include "freebob_streaming.h" |
---|
36 |
#include "freebob_streaming_private.h" |
---|
37 |
#include "freebob_connections.h" |
---|
38 |
#include "freebob_debug.h" |
---|
39 |
|
---|
40 |
/** |
---|
41 |
* Callbacks |
---|
42 |
*/ |
---|
43 |
|
---|
44 |
static enum raw1394_iso_disposition |
---|
45 |
iso_slave_receive_handler(raw1394handle_t handle, unsigned char *data, |
---|
46 |
unsigned int length, unsigned char channel, |
---|
47 |
unsigned char tag, unsigned char sy, unsigned int cycle, |
---|
48 |
unsigned int dropped); |
---|
49 |
|
---|
50 |
static enum raw1394_iso_disposition |
---|
51 |
iso_master_receive_handler(raw1394handle_t handle, unsigned char *data, |
---|
52 |
unsigned int length, unsigned char channel, |
---|
53 |
unsigned char tag, unsigned char sy, unsigned int cycle, |
---|
54 |
unsigned int dropped); |
---|
55 |
|
---|
56 |
static enum raw1394_iso_disposition |
---|
57 |
iso_slave_transmit_handler(raw1394handle_t handle, |
---|
58 |
unsigned char *data, unsigned int *length, |
---|
59 |
unsigned char *tag, unsigned char *sy, |
---|
60 |
int cycle, unsigned int dropped); |
---|
61 |
|
---|
62 |
static enum raw1394_iso_disposition |
---|
63 |
iso_master_transmit_handler(raw1394handle_t handle, |
---|
64 |
unsigned char *data, unsigned int *length, |
---|
65 |
unsigned char *tag, unsigned char *sy, |
---|
66 |
int cycle, unsigned int dropped); |
---|
67 |
|
---|
68 |
|
---|
69 |
freebob_device_t *freebob_streaming_init (freebob_device_info_t *device_info, freebob_options_t options) { |
---|
70 |
int i; |
---|
71 |
int c; |
---|
72 |
int err=0; |
---|
73 |
freebob_device_t* dev=NULL; |
---|
74 |
|
---|
75 |
assert(device_info); |
---|
76 |
|
---|
77 |
printMessage("FreeBob Streaming Device Init\n"); |
---|
78 |
printMessage(" Using FreeBobCtl lib version %s\n",freebobctl_get_version()); |
---|
79 |
printMessage(" Device information:\n"); |
---|
80 |
|
---|
81 |
switch (device_info->location_type) { |
---|
82 |
case freebob_osc: |
---|
83 |
printMessage(" OSC URL: %s\n",device_info->xml_location); |
---|
84 |
break; |
---|
85 |
case freebob_file: |
---|
86 |
printMessage(" XML file: %s\n",device_info->xml_location); |
---|
87 |
break; |
---|
88 |
default: |
---|
89 |
printMessage(" Other location type.\n"); |
---|
90 |
} |
---|
91 |
|
---|
92 |
printMessage(" Device options:\n"); |
---|
93 |
/* driver related setup */ |
---|
94 |
printMessage(" Samplerate : %d\n",options.sample_rate); |
---|
95 |
printMessage(" Period Size : %d\n",options.period_size); |
---|
96 |
printMessage(" Nb Buffers : %d\n",options.nb_buffers); |
---|
97 |
printMessage(" RAW1394 ISO Buffers : %d\n",options.iso_buffers); |
---|
98 |
printMessage(" RAW1394 ISO Prebuffers : %d\n",options.iso_prebuffers); |
---|
99 |
printMessage(" RAW1394 ISO IRQ Interval : %d\n",options.iso_irq_interval); |
---|
100 |
printMessage("\n"); |
---|
101 |
|
---|
102 |
// initialize the freebob_device |
---|
103 |
// allocate memory |
---|
104 |
dev=calloc(1,sizeof(freebob_device_t)); |
---|
105 |
|
---|
106 |
if(!dev) { |
---|
107 |
printError("FREEBOB: cannot allocate memory for dev structure!\n"); |
---|
108 |
return NULL; |
---|
109 |
} |
---|
110 |
|
---|
111 |
// clear the device structure |
---|
112 |
memset(dev,0,sizeof(freebob_device_t)); |
---|
113 |
|
---|
114 |
// copy the arguments to the device structure |
---|
115 |
memcpy(&dev->device_info, device_info, sizeof(freebob_device_info_t)); |
---|
116 |
memcpy(&dev->options, &options, sizeof(freebob_options_t)); |
---|
117 |
|
---|
118 |
// read in the device specification |
---|
119 |
|
---|
120 |
/* load the connections*/ |
---|
121 |
/* |
---|
122 |
* This info should be provided by the Freebob CML application |
---|
123 |
* |
---|
124 |
*/ |
---|
125 |
freebob_connection_info_t *freebobctl_capture_connections=NULL; |
---|
126 |
freebob_connection_info_t *freebobctl_playback_connections=NULL; |
---|
127 |
|
---|
128 |
switch (dev->device_info.location_type) { |
---|
129 |
case freebob_osc: |
---|
130 |
printMessage("Reading from OSC URL: %s\n",dev->device_info.xml_location); |
---|
131 |
freebobctl_capture_connections=freebobctl_get_connection_info_from_osc(dev->device_info.xml_location, 0); |
---|
132 |
freebobctl_playback_connections=freebobctl_get_connection_info_from_osc(dev->device_info.xml_location, 1); |
---|
133 |
break; |
---|
134 |
case freebob_file: |
---|
135 |
printMessage("Reading from XML file: %s\n",dev->device_info.xml_location); |
---|
136 |
freebobctl_capture_connections=freebobctl_get_connection_info_from_xml_file(dev->device_info.xml_location, 0); |
---|
137 |
freebobctl_playback_connections=freebobctl_get_connection_info_from_xml_file(dev->device_info.xml_location, 1); |
---|
138 |
break; |
---|
139 |
default: |
---|
140 |
printError("Faulty location type!\n"); |
---|
141 |
free(dev); |
---|
142 |
return NULL; |
---|
143 |
|
---|
144 |
} |
---|
145 |
|
---|
146 |
if (freebobctl_capture_connections) { |
---|
147 |
dev->nb_connections_capture=freebobctl_capture_connections->nb_connections; |
---|
148 |
// FIXME: |
---|
149 |
//dev->nb_connections_capture=0; |
---|
150 |
} else { |
---|
151 |
dev->nb_connections_capture=0; |
---|
152 |
} |
---|
153 |
|
---|
154 |
if (freebobctl_playback_connections) { |
---|
155 |
dev->nb_connections_playback=freebobctl_playback_connections->nb_connections; |
---|
156 |
// FIXME: |
---|
157 |
// dev->nb_connections_playback=0; |
---|
158 |
} else { |
---|
159 |
dev->nb_connections_playback=0; |
---|
160 |
} |
---|
161 |
|
---|
162 |
dev->nb_connections=dev->nb_connections_playback+dev->nb_connections_capture; |
---|
163 |
/* see if there are any connections */ |
---|
164 |
if (!dev->nb_connections) { |
---|
165 |
printError("No connections specified, bailing out\n"); |
---|
166 |
if(freebobctl_capture_connections) { free(freebobctl_capture_connections); freebobctl_capture_connections=NULL; } |
---|
167 |
if(freebobctl_playback_connections) { free(freebobctl_playback_connections); freebobctl_playback_connections=NULL; } |
---|
168 |
free(dev); |
---|
169 |
|
---|
170 |
return NULL; |
---|
171 |
} |
---|
172 |
|
---|
173 |
dev->connections=calloc(dev->nb_connections_playback+dev->nb_connections_capture, sizeof(freebob_connection_t)); |
---|
174 |
|
---|
175 |
|
---|
176 |
for (c=0;c<dev->nb_connections_capture;c++) { |
---|
177 |
memcpy(&dev->connections[c].spec, freebobctl_capture_connections->connections[c], sizeof(freebob_connection_spec_t)); |
---|
178 |
dev->connections[c].spec.direction=FREEBOB_CAPTURE; |
---|
179 |
} |
---|
180 |
for (c=0;c<dev->nb_connections_playback;c++) { |
---|
181 |
memcpy(&dev->connections[c+dev->nb_connections_capture].spec, freebobctl_playback_connections->connections[c], sizeof(freebob_connection_spec_t)); |
---|
182 |
dev->connections[c+dev->nb_connections_capture].spec.direction=FREEBOB_PLAYBACK; |
---|
183 |
} |
---|
184 |
|
---|
185 |
if(freebobctl_capture_connections) { free(freebobctl_capture_connections); freebobctl_capture_connections=NULL; } |
---|
186 |
if(freebobctl_playback_connections) { free(freebobctl_playback_connections); freebobctl_playback_connections=NULL; } |
---|
187 |
|
---|
188 |
/* Figure out a master connection. |
---|
189 |
* Either it is given in the spec libfreebobctl |
---|
190 |
* Or it is the first connection defined (capture connections first) |
---|
191 |
*/ |
---|
192 |
int master_found=FALSE; |
---|
193 |
|
---|
194 |
for (c=0;c<dev->nb_connections_capture+dev->nb_connections_playback;c++) { |
---|
195 |
if (dev->connections[c].spec.is_master==TRUE) { |
---|
196 |
master_found=TRUE; |
---|
197 |
break; |
---|
198 |
} |
---|
199 |
} |
---|
200 |
|
---|
201 |
if((!master_found) && (dev->nb_connections_capture+dev->nb_connections_playback > 0)) { |
---|
202 |
dev->connections[0].spec.is_master=TRUE; |
---|
203 |
} |
---|
204 |
|
---|
205 |
// initialize all connections |
---|
206 |
for(i=0; i < dev->nb_connections; i++) { |
---|
207 |
freebob_connection_t *connection= &(dev->connections[i]); |
---|
208 |
if ((err=freebob_streaming_init_connection(dev, connection))<0) { |
---|
209 |
printError("FREEBOB: failed to init connection %d\n",i); |
---|
210 |
break; |
---|
211 |
} |
---|
212 |
} |
---|
213 |
|
---|
214 |
if(err) { |
---|
215 |
debugPrint(DEBUG_LEVEL_STARTUP, "Cleaning up connections\n"); |
---|
216 |
|
---|
217 |
// the connection that failed doesn't have to be cleaned |
---|
218 |
i-=1; |
---|
219 |
|
---|
220 |
for(; i >= 0; i--) { |
---|
221 |
freebob_connection_t *connection= &(dev->connections[i]); |
---|
222 |
debugPrint(DEBUG_LEVEL_STARTUP, "Cleaning up connection %d\n",i); |
---|
223 |
if ((freebob_streaming_cleanup_connection(dev, connection))<0) { |
---|
224 |
printError( "Failed to clean connection %d\n",i); |
---|
225 |
} |
---|
226 |
} |
---|
227 |
free(dev->connections); |
---|
228 |
free(dev); |
---|
229 |
return NULL; |
---|
230 |
} |
---|
231 |
|
---|
232 |
return dev; |
---|
233 |
|
---|
234 |
} |
---|
235 |
|
---|
236 |
void freebob_streaming_finish(freebob_device_t *dev) { |
---|
237 |
debugPrint(DEBUG_LEVEL_STARTUP,"Cleaning up connections\n"); |
---|
238 |
unsigned int i; |
---|
239 |
int err=0; |
---|
240 |
|
---|
241 |
// cleanup all connections |
---|
242 |
for(i=0; i < dev->nb_connections; i++) { |
---|
243 |
freebob_connection_t *connection= &(dev->connections[i]); |
---|
244 |
if ((err=freebob_streaming_cleanup_connection(dev, connection))<0) { |
---|
245 |
printError("Failed to cleanup connection %d\n",i); |
---|
246 |
return; |
---|
247 |
} |
---|
248 |
} |
---|
249 |
|
---|
250 |
// free stream structures |
---|
251 |
if(dev->capture_streams) { |
---|
252 |
free(dev->capture_streams); |
---|
253 |
} |
---|
254 |
if(dev->playback_streams) { |
---|
255 |
free(dev->playback_streams); |
---|
256 |
} |
---|
257 |
if(dev->synced_capture_streams) { |
---|
258 |
free(dev->synced_capture_streams); |
---|
259 |
} |
---|
260 |
if(dev->synced_playback_streams) { |
---|
261 |
free(dev->synced_playback_streams); |
---|
262 |
} |
---|
263 |
|
---|
264 |
// cleanup data structures |
---|
265 |
free(dev->connections); |
---|
266 |
free(dev); |
---|
267 |
|
---|
268 |
return; |
---|
269 |
} |
---|
270 |
|
---|
271 |
int freebob_streaming_get_nb_capture_streams(freebob_device_t *dev) { |
---|
272 |
return dev->nb_capture_streams; |
---|
273 |
} |
---|
274 |
|
---|
275 |
int freebob_streaming_get_nb_playback_streams(freebob_device_t *dev) { |
---|
276 |
return dev->nb_playback_streams; |
---|
277 |
} |
---|
278 |
|
---|
279 |
int freebob_streaming_get_capture_stream_name(freebob_device_t *dev, int i, char* buffer, size_t buffersize) { |
---|
280 |
freebob_stream_t *stream; |
---|
281 |
if(i<dev->nb_capture_streams) { |
---|
282 |
stream=*(dev->capture_streams+i); |
---|
283 |
return snprintf (buffer, buffersize, "%s_%d_%d_%d_%s", |
---|
284 |
"cap", (int) stream->parent->spec.port, stream->parent->spec.node & 0x3F, stream->parent->spec.plug, stream->spec.name); |
---|
285 |
} else { |
---|
286 |
return -1; |
---|
287 |
} |
---|
288 |
} |
---|
289 |
|
---|
290 |
int freebob_streaming_get_playback_stream_name(freebob_device_t *dev, int i, char* buffer, size_t buffersize) { |
---|
291 |
freebob_stream_t *stream; |
---|
292 |
if(i<dev->nb_playback_streams) { |
---|
293 |
stream=*(dev->playback_streams+i); |
---|
294 |
return snprintf (buffer, buffersize, "%s_%d_%d_%d_%s", |
---|
295 |
"pbk", (int) stream->parent->spec.port, stream->parent->spec.node & 0x3F, stream->parent->spec.plug, stream->spec.name); |
---|
296 |
} else { |
---|
297 |
return -1; |
---|
298 |
} |
---|
299 |
} |
---|
300 |
|
---|
301 |
freebob_streaming_stream_type freebob_streaming_get_capture_stream_type(freebob_device_t *dev, int i) { |
---|
302 |
freebob_stream_t *stream; |
---|
303 |
if(i<dev->nb_capture_streams) { |
---|
304 |
stream=*(dev->capture_streams+i); |
---|
305 |
switch (stream->spec.format) { |
---|
306 |
case IEC61883_STREAM_TYPE_MBLA: |
---|
307 |
return freebob_audio; |
---|
308 |
case IEC61883_STREAM_TYPE_MIDI: |
---|
309 |
return freebob_midi; |
---|
310 |
case IEC61883_STREAM_TYPE_SPDIF: |
---|
311 |
default: |
---|
312 |
return freebob_unknown; |
---|
313 |
} |
---|
314 |
} else { |
---|
315 |
return freebob_invalid; |
---|
316 |
} |
---|
317 |
} |
---|
318 |
|
---|
319 |
freebob_streaming_stream_type freebob_streaming_get_playback_stream_type(freebob_device_t *dev, int i) { |
---|
320 |
freebob_stream_t *stream; |
---|
321 |
if(i<dev->nb_playback_streams) { |
---|
322 |
stream=*(dev->playback_streams+i); |
---|
323 |
switch (stream->spec.format) { |
---|
324 |
case IEC61883_STREAM_TYPE_MBLA: |
---|
325 |
return freebob_audio; |
---|
326 |
case IEC61883_STREAM_TYPE_MIDI: |
---|
327 |
return freebob_midi; |
---|
328 |
case IEC61883_STREAM_TYPE_SPDIF: |
---|
329 |
default: |
---|
330 |
return freebob_unknown; |
---|
331 |
} |
---|
332 |
} else { |
---|
333 |
return freebob_invalid; |
---|
334 |
} |
---|
335 |
} |
---|
336 |
|
---|
337 |
int freebob_streaming_start_thread(freebob_device_t *dev) { |
---|
338 |
int err; |
---|
339 |
// start the packetizer thread |
---|
340 |
// init the packetizer thread communication semaphores |
---|
341 |
if((err=sem_init(&dev->packetizer.transfer_boundary, 0, 0))) { |
---|
342 |
printError( "Cannot init packet transfer semaphore\n"); |
---|
343 |
return err; |
---|
344 |
} else { |
---|
345 |
debugPrint(DEBUG_LEVEL_STARTUP,"FREEBOB: successfull init of packet transfer semaphore\n"); |
---|
346 |
} |
---|
347 |
|
---|
348 |
// FIXME: packetizer thread |
---|
349 |
dev->packetizer.run=1; |
---|
350 |
|
---|
351 |
if (freebob_streaming_create_thread(&dev->packetizer.transfer_thread, 10, 1, freebob_iso_packet_iterator, (void *)dev)) { |
---|
352 |
printError("FREEBOB: cannot create packet transfer thread"); |
---|
353 |
return -1; |
---|
354 |
} else { |
---|
355 |
debugPrint(DEBUG_LEVEL_STARTUP,"Created packet transfer thread\n"); |
---|
356 |
} |
---|
357 |
return 0; |
---|
358 |
} |
---|
359 |
|
---|
360 |
int freebob_streaming_stop_thread(freebob_device_t *dev) { |
---|
361 |
void *status; |
---|
362 |
|
---|
363 |
debugPrint(DEBUG_LEVEL_STARTUP," Stopping packetizer thread...\n"); |
---|
364 |
dev->packetizer.run=0; |
---|
365 |
|
---|
366 |
//sem_post(&dev->packetizer.transfer_ack); |
---|
367 |
|
---|
368 |
pthread_join (dev->packetizer.transfer_thread, &status); |
---|
369 |
|
---|
370 |
// cleanup semaphores |
---|
371 |
sem_destroy(&dev->packetizer.transfer_boundary); |
---|
372 |
|
---|
373 |
return 0; |
---|
374 |
} |
---|
375 |
|
---|
376 |
|
---|
377 |
int freebob_streaming_start(freebob_device_t *dev) { |
---|
378 |
int err; |
---|
379 |
int i; |
---|
380 |
|
---|
381 |
//SEGFAULT |
---|
382 |
|
---|
383 |
for(i=0; i < dev->nb_connections; i++) { |
---|
384 |
err=0; |
---|
385 |
freebob_connection_t *connection= &(dev->connections[i]); |
---|
386 |
|
---|
387 |
//connection->plug=0; |
---|
388 |
connection->iso.hostplug=-1; |
---|
389 |
|
---|
390 |
// create the CCM PTP connection |
---|
391 |
connection->iso.do_disconnect=0; |
---|
392 |
|
---|
393 |
// start receiving |
---|
394 |
switch (connection->spec.direction) { |
---|
395 |
case FREEBOB_CAPTURE: |
---|
396 |
|
---|
397 |
debugPrint(DEBUG_LEVEL_STARTUP," creating capture connections...\n"); |
---|
398 |
if (connection->spec.iso_channel < 0) { |
---|
399 |
// we need to make the connection ourself |
---|
400 |
debugPrint(DEBUG_LEVEL_STARTUP, "Executing CMP procedure...\n"); |
---|
401 |
|
---|
402 |
connection->iso.iso_channel = iec61883_cmp_connect( |
---|
403 |
connection->raw_handle, |
---|
404 |
connection->spec.node | 0xffc0, |
---|
405 |
&connection->spec.plug, |
---|
406 |
raw1394_get_local_id (connection->raw_handle), |
---|
407 |
&connection->iso.hostplug, |
---|
408 |
&connection->iso.bandwidth); |
---|
409 |
|
---|
410 |
connection->iso.do_disconnect=1; |
---|
411 |
|
---|
412 |
} else { |
---|
413 |
connection->iso.iso_channel=connection->spec.iso_channel; |
---|
414 |
} |
---|
415 |
|
---|
416 |
if (connection->spec.is_master) { //master connection |
---|
417 |
debugPrint(DEBUG_LEVEL_STARTUP, "Init ISO master receive handler on channel %d...\n",connection->iso.iso_channel); |
---|
418 |
debugPrint(DEBUG_LEVEL_STARTUP, " (BUFFER=%d,PACKET_MAX=%d,IRQ=%d)...\n",connection->iso.buffers,AMDTP_MAX_PACKET_SIZE, connection->iso.irq_interval); |
---|
419 |
raw1394_iso_recv_init( |
---|
420 |
connection->raw_handle, |
---|
421 |
iso_master_receive_handler, |
---|
422 |
connection->iso.buffers, |
---|
423 |
AMDTP_MAX_PACKET_SIZE, |
---|
424 |
connection->iso.iso_channel, |
---|
425 |
RAW1394_DMA_BUFFERFILL, |
---|
426 |
connection->iso.irq_interval); |
---|
427 |
|
---|
428 |
dev->sync_master_connection=connection; |
---|
429 |
connection->status.master=NULL; |
---|
430 |
|
---|
431 |
} else { |
---|
432 |
//slave receive connection |
---|
433 |
debugPrint(DEBUG_LEVEL_STARTUP, "Init ISO slave receive handler on channel %d...\n",connection->iso.iso_channel); |
---|
434 |
debugPrint(DEBUG_LEVEL_STARTUP, " (BUFFER=%d,PACKET_MAX=%d,IRQ=%d)...\n", connection->iso.buffers, AMDTP_MAX_PACKET_SIZE, connection->iso.irq_interval); |
---|
435 |
raw1394_iso_recv_init( |
---|
436 |
connection->raw_handle, |
---|
437 |
iso_slave_receive_handler, |
---|
438 |
connection->iso.buffers, |
---|
439 |
AMDTP_MAX_PACKET_SIZE, |
---|
440 |
connection->iso.iso_channel, |
---|
441 |
RAW1394_DMA_BUFFERFILL, |
---|
442 |
connection->iso.irq_interval); |
---|
443 |
} |
---|
444 |
|
---|
445 |
break; |
---|
446 |
case FREEBOB_PLAYBACK: |
---|
447 |
debugPrint(DEBUG_LEVEL_STARTUP," creating playback connections...\n"); |
---|
448 |
|
---|
449 |
if (connection->spec.iso_channel < 0) { // we need to make the connection ourself |
---|
450 |
debugPrint(DEBUG_LEVEL_STARTUP, "Executing CMP procedure...\n"); |
---|
451 |
connection->iso.iso_channel = iec61883_cmp_connect( |
---|
452 |
connection->raw_handle, |
---|
453 |
raw1394_get_local_id (connection->raw_handle), |
---|
454 |
&connection->iso.hostplug, |
---|
455 |
connection->spec.node | 0xffc0, |
---|
456 |
&connection->spec.plug, |
---|
457 |
&connection->iso.bandwidth); |
---|
458 |
|
---|
459 |
connection->iso.do_disconnect=1; |
---|
460 |
} else { |
---|
461 |
connection->iso.iso_channel=connection->spec.iso_channel; |
---|
462 |
} |
---|
463 |
|
---|
464 |
if (connection->spec.is_master) { // master connection |
---|
465 |
debugPrint(DEBUG_LEVEL_STARTUP, "Init ISO master transmit handler on channel %d...\n",connection->iso.iso_channel); |
---|
466 |
debugPrint(DEBUG_LEVEL_STARTUP, " other mode (BUFFER=%d,PACKET_MAX=%d,IRQ=%d)...\n",connection->iso.buffers,AMDTP_MAX_PACKET_SIZE, connection->iso.irq_interval); |
---|
467 |
|
---|
468 |
raw1394_iso_xmit_init( |
---|
469 |
connection->raw_handle, |
---|
470 |
iso_master_transmit_handler, |
---|
471 |
connection->iso.buffers, |
---|
472 |
AMDTP_MAX_PACKET_SIZE, |
---|
473 |
connection->iso.iso_channel, |
---|
474 |
RAW1394_ISO_SPEED_400, |
---|
475 |
connection->iso.irq_interval); |
---|
476 |
|
---|
477 |
dev->sync_master_connection=connection; |
---|
478 |
connection->status.master=NULL; |
---|
479 |
|
---|
480 |
} else { |
---|
481 |
|
---|
482 |
debugPrint(DEBUG_LEVEL_STARTUP, "Init ISO slave transmit handler on channel %d...\n",connection->iso.iso_channel); |
---|
483 |
debugPrint(DEBUG_LEVEL_STARTUP, " (BUFFER=%d,PACKET_MAX=%d,IRQ=%d)...\n",connection->iso.buffers,AMDTP_MAX_PACKET_SIZE, connection->iso.irq_interval); |
---|
484 |
raw1394_iso_xmit_init( |
---|
485 |
connection->raw_handle, |
---|
486 |
iso_slave_transmit_handler, |
---|
487 |
connection->iso.buffers, |
---|
488 |
AMDTP_MAX_PACKET_SIZE, |
---|
489 |
connection->iso.iso_channel, |
---|
490 |
RAW1394_ISO_SPEED_400, |
---|
491 |
connection->iso.irq_interval); |
---|
492 |
} |
---|
493 |
|
---|
494 |
int fdf, syt_interval; |
---|
495 |
// FIXME: |
---|
496 |
int samplerate=dev->options.sample_rate; |
---|
497 |
// int samplerate=connection->spec.samplerate; |
---|
498 |
|
---|
499 |
switch (samplerate) { |
---|
500 |
case 32000: |
---|
501 |
syt_interval = 8; |
---|
502 |
fdf = IEC61883_FDF_SFC_32KHZ; |
---|
503 |
break; |
---|
504 |
case 44100: |
---|
505 |
syt_interval = 8; |
---|
506 |
fdf = IEC61883_FDF_SFC_44K1HZ; |
---|
507 |
break; |
---|
508 |
default: |
---|
509 |
case 48000: |
---|
510 |
syt_interval = 8; |
---|
511 |
fdf = IEC61883_FDF_SFC_48KHZ; |
---|
512 |
break; |
---|
513 |
case 88200: |
---|
514 |
syt_interval = 16; |
---|
515 |
fdf = IEC61883_FDF_SFC_88K2HZ; |
---|
516 |
break; |
---|
517 |
case 96000: |
---|
518 |
syt_interval = 16; |
---|
519 |
fdf = IEC61883_FDF_SFC_96KHZ; |
---|
520 |
break; |
---|
521 |
case 176400: |
---|
522 |
syt_interval = 32; |
---|
523 |
fdf = IEC61883_FDF_SFC_176K4HZ; |
---|
524 |
break; |
---|
525 |
case 192000: |
---|
526 |
syt_interval = 32; |
---|
527 |
fdf = IEC61883_FDF_SFC_192KHZ; |
---|
528 |
break; |
---|
529 |
} |
---|
530 |
|
---|
531 |
iec61883_cip_init ( |
---|
532 |
&connection->status.cip, |
---|
533 |
IEC61883_FMT_AMDTP, |
---|
534 |
fdf, |
---|
535 |
samplerate, |
---|
536 |
connection->spec.dimension, |
---|
537 |
syt_interval); |
---|
538 |
|
---|
539 |
iec61883_cip_set_transmission_mode ( |
---|
540 |
&connection->status.cip, |
---|
541 |
IEC61883_MODE_BLOCKING_EMPTY); |
---|
542 |
|
---|
543 |
break; |
---|
544 |
} |
---|
545 |
|
---|
546 |
if(connection->iso.iso_channel<0) { |
---|
547 |
printError("Could not do CMP for connection %d\n",i); |
---|
548 |
i-=1; |
---|
549 |
while(i>=0) { |
---|
550 |
connection= &(dev->connections[i]); |
---|
551 |
|
---|
552 |
debugPrint(DEBUG_LEVEL_STARTUP, "Shutdown connection %d on channel %d ...\n", i, connection->iso.iso_channel); |
---|
553 |
|
---|
554 |
raw1394_iso_shutdown(connection->raw_handle); |
---|
555 |
|
---|
556 |
if (connection->iso.do_disconnect) { |
---|
557 |
// destroy the CCM PTP connection |
---|
558 |
switch (connection->spec.direction) { |
---|
559 |
case FREEBOB_CAPTURE: |
---|
560 |
iec61883_cmp_disconnect( |
---|
561 |
connection->raw_handle, |
---|
562 |
connection->spec.node | 0xffc0, |
---|
563 |
connection->spec.plug, |
---|
564 |
raw1394_get_local_id (connection->raw_handle), |
---|
565 |
connection->iso.hostplug, |
---|
566 |
connection->iso.iso_channel, |
---|
567 |
connection->iso.bandwidth); |
---|
568 |
|
---|
569 |
break; |
---|
570 |
case FREEBOB_PLAYBACK: |
---|
571 |
iec61883_cmp_disconnect( |
---|
572 |
connection->raw_handle, |
---|
573 |
raw1394_get_local_id (connection->raw_handle), |
---|
574 |
connection->iso.hostplug, |
---|
575 |
connection->spec.node | 0xffc0, |
---|
576 |
connection->spec.plug, |
---|
577 |
connection->iso.iso_channel, |
---|
578 |
connection->iso.bandwidth); |
---|
579 |
|
---|
580 |
break; |
---|
581 |
} |
---|
582 |
} |
---|
583 |
i--; |
---|
584 |
} |
---|
585 |
return -1; |
---|
586 |
} |
---|
587 |
} |
---|
588 |
|
---|
589 |
/* update the sync master pointer for all connections */ |
---|
590 |
debugPrint(DEBUG_LEVEL_STARTUP,"Connection summary:\n"); |
---|
591 |
int sync_masters_present=0; |
---|
592 |
|
---|
593 |
for(i=0; i < dev->nb_connections; i++) { |
---|
594 |
err=0; |
---|
595 |
|
---|
596 |
freebob_connection_t *connection= &(dev->connections[i]); |
---|
597 |
|
---|
598 |
if (connection->spec.direction == FREEBOB_CAPTURE) { |
---|
599 |
debugPrint(DEBUG_LEVEL_STARTUP," Capture : from node %02X.%02d to node %02X.%02d on channel %02d {%p} ", |
---|
600 |
connection->spec.node & ~0xffc0, connection->spec.plug, |
---|
601 |
raw1394_get_local_id (connection->raw_handle) & ~0xffc0, connection->iso.hostplug, |
---|
602 |
connection->iso.iso_channel, connection); |
---|
603 |
} else if (connection->spec.direction == FREEBOB_PLAYBACK) { |
---|
604 |
|
---|
605 |
debugPrint(DEBUG_LEVEL_STARTUP," Playback: from node %02X.%02d to node %02X.%02d on channel %02d {%p} ", |
---|
606 |
raw1394_get_local_id (connection->raw_handle) & ~0xffc0, connection->iso.hostplug, |
---|
607 |
connection->spec.node & ~0xffc0, connection->spec.plug, |
---|
608 |
connection->iso.iso_channel, connection); |
---|
609 |
} |
---|
610 |
|
---|
611 |
if (connection->spec.is_master) { |
---|
612 |
sync_masters_present++; |
---|
613 |
|
---|
614 |
debugPrintShort(DEBUG_LEVEL_STARTUP," [MASTER]"); |
---|
615 |
} else { |
---|
616 |
assert(dev->sync_master_connection); |
---|
617 |
connection->status.master=&dev->sync_master_connection->status; |
---|
618 |
|
---|
619 |
debugPrintShort(DEBUG_LEVEL_STARTUP," [SLAVE]"); |
---|
620 |
} |
---|
621 |
debugPrintShort(DEBUG_LEVEL_STARTUP,"\n"); |
---|
622 |
} |
---|
623 |
|
---|
624 |
if (sync_masters_present == 0) { |
---|
625 |
printError("FREEBOB: no sync master connection present!\n"); |
---|
626 |
// TODO: cleanup |
---|
627 |
//freebob_streaming_stop(driver); |
---|
628 |
return -1; |
---|
629 |
} else if (sync_masters_present > 1) { |
---|
630 |
printError("FREEBOB: too many sync master connections present! (%d)\n",sync_masters_present); |
---|
631 |
// TODO: cleanup |
---|
632 |
//freebob_streaming_stop(driver); |
---|
633 |
return -1; |
---|
634 |
} |
---|
635 |
|
---|
636 |
// put nb_periods*period_size of null frames into the playback buffers |
---|
637 |
if((err=freebob_streaming_prefill_playback_streams(dev))<0) { |
---|
638 |
printError("Could not prefill playback streams.\n"); |
---|
639 |
return err; |
---|
640 |
} |
---|
641 |
|
---|
642 |
debugPrint(DEBUG_LEVEL_STARTUP,"Armed...\n"); |
---|
643 |
|
---|
644 |
freebob_streaming_start_iso(dev); |
---|
645 |
|
---|
646 |
freebob_streaming_start_thread(dev); |
---|
647 |
|
---|
648 |
return 0; |
---|
649 |
|
---|
650 |
} |
---|
651 |
|
---|
652 |
int freebob_streaming_stop(freebob_device_t *dev) { |
---|
653 |
unsigned int i; |
---|
654 |
|
---|
655 |
|
---|
656 |
freebob_streaming_stop_thread(dev); |
---|
657 |
|
---|
658 |
freebob_streaming_stop_iso(dev); |
---|
659 |
|
---|
660 |
// stop ISO xmit/receive |
---|
661 |
for(i=0; i < dev->nb_connections; i++) { |
---|
662 |
freebob_connection_t *connection= &(dev->connections[i]); |
---|
663 |
|
---|
664 |
debugPrint(DEBUG_LEVEL_STARTUP, "Shutdown connection %d on channel %d ...\n", i, connection->iso.iso_channel); |
---|
665 |
|
---|
666 |
raw1394_iso_shutdown(connection->raw_handle); |
---|
667 |
|
---|
668 |
if (connection->iso.do_disconnect) { |
---|
669 |
// destroy the CCM PTP connection |
---|
670 |
switch (connection->spec.direction) { |
---|
671 |
case FREEBOB_CAPTURE: |
---|
672 |
iec61883_cmp_disconnect( |
---|
673 |
connection->raw_handle, |
---|
674 |
connection->spec.node | 0xffc0, |
---|
675 |
connection->spec.plug, |
---|
676 |
raw1394_get_local_id (connection->raw_handle), |
---|
677 |
connection->iso.hostplug, |
---|
678 |
connection->iso.iso_channel, |
---|
679 |
connection->iso.bandwidth); |
---|
680 |
|
---|
681 |
break; |
---|
682 |
case FREEBOB_PLAYBACK: |
---|
683 |
iec61883_cmp_disconnect( |
---|
684 |
connection->raw_handle, |
---|
685 |
raw1394_get_local_id (connection->raw_handle), |
---|
686 |
connection->iso.hostplug, |
---|
687 |
connection->spec.node | 0xffc0, |
---|
688 |
connection->spec.plug, |
---|
689 |
connection->iso.iso_channel, |
---|
690 |
connection->iso.bandwidth); |
---|
691 |
|
---|
692 |
break; |
---|
693 |
} |
---|
694 |
} |
---|
695 |
|
---|
696 |
} |
---|
697 |
return 0; |
---|
698 |
} |
---|
699 |
|
---|
700 |
int freebob_streaming_prefill_playback_streams(freebob_device_t *dev) { |
---|
701 |
int i; |
---|
702 |
int err=0; |
---|
703 |
|
---|
704 |
for(i=0; i < dev->nb_playback_streams; i++) { |
---|
705 |
freebob_stream_t *stream; |
---|
706 |
|
---|
707 |
|
---|
708 |
stream=*(dev->playback_streams+i); |
---|
709 |
|
---|
710 |
assert(stream); |
---|
711 |
err=freebob_streaming_prefill_stream(dev, stream); |
---|
712 |
if (err) { |
---|
713 |
printError("Could not prefill stream %d\n",i); |
---|
714 |
return -1; |
---|
715 |
} |
---|
716 |
} |
---|
717 |
return 0; |
---|
718 |
|
---|
719 |
} |
---|
720 |
|
---|
721 |
int freebob_streaming_reset(freebob_device_t *dev) { |
---|
722 |
/* |
---|
723 |
* Reset means: |
---|
724 |
* 1) Stopping the packetizer thread |
---|
725 |
* 2) Bringing all buffers & connections into a know state |
---|
726 |
* - Clear all capture buffers |
---|
727 |
* - Put nb_periods*period_size of null frames into the playback buffers |
---|
728 |
* 3) Restarting the packetizer thread |
---|
729 |
*/ |
---|
730 |
|
---|
731 |
unsigned long i; |
---|
732 |
int err; |
---|
733 |
assert(dev); |
---|
734 |
|
---|
735 |
if((err=freebob_streaming_stop_thread(dev))<0) { |
---|
736 |
printError("Could not stop packetizer thread.\n"); |
---|
737 |
return err; |
---|
738 |
} |
---|
739 |
|
---|
740 |
//freebob_streaming_stop_iso(dev); |
---|
741 |
|
---|
742 |
// check if the packetizer is stopped |
---|
743 |
assert(!dev->packetizer.run); |
---|
744 |
|
---|
745 |
// reset all connections |
---|
746 |
for(i=0; i < dev->nb_connections; i++) { |
---|
747 |
freebob_connection_t *connection= &(dev->connections[i]); |
---|
748 |
freebob_streaming_reset_connection(dev,connection); |
---|
749 |
} |
---|
750 |
|
---|
751 |
// put nb_periods*period_size of null frames into the playback buffers |
---|
752 |
if((err=freebob_streaming_prefill_playback_streams(dev))<0) { |
---|
753 |
printError("Could not prefill playback streams.\n"); |
---|
754 |
return err; |
---|
755 |
} |
---|
756 |
|
---|
757 |
// clear the xrun flag |
---|
758 |
dev->xrun_detected=FALSE; |
---|
759 |
|
---|
760 |
//freebob_streaming_start_iso(dev); |
---|
761 |
|
---|
762 |
if((err=freebob_streaming_start_thread(dev))<0) { |
---|
763 |
printError("Could not start packetizer thread.\n"); |
---|
764 |
return err; |
---|
765 |
} |
---|
766 |
|
---|
767 |
|
---|
768 |
return 0; |
---|
769 |
} |
---|
770 |
|
---|
771 |
int freebob_streaming_xrun_recovery(freebob_device_t *dev) { |
---|
772 |
freebob_streaming_reset(dev); |
---|
773 |
dev->xrun_count++; |
---|
774 |
|
---|
775 |
return 0; |
---|
776 |
} |
---|
777 |
|
---|
778 |
int freebob_streaming_wait(freebob_device_t *dev) { |
---|
779 |
int ret; |
---|
780 |
|
---|
781 |
// Wait for packetizer thread to signal a period completion |
---|
782 |
sem_wait(&dev->packetizer.transfer_boundary); |
---|
783 |
|
---|
784 |
// acknowledge the reception of the period |
---|
785 |
//sem_post(&dev->packetizer.transfer_ack); |
---|
786 |
|
---|
787 |
if(dev->xrun_detected) { |
---|
788 |
// notify the driver of the underrun and the delay |
---|
789 |
ret=-freebob_streaming_xrun_recovery(dev); |
---|
790 |
} else { |
---|
791 |
ret=dev->options.period_size; |
---|
792 |
} |
---|
793 |
|
---|
794 |
return ret; |
---|
795 |
} |
---|
796 |
|
---|
797 |
int freebob_streaming_write(freebob_device_t *dev, int i, freebob_sample_t *buffer, int nsamples) { |
---|
798 |
int retval; |
---|
799 |
|
---|
800 |
freebob_stream_t *stream; |
---|
801 |
assert(i<dev->nb_playback_streams); |
---|
802 |
|
---|
803 |
stream=*(dev->playback_streams+i); |
---|
804 |
assert(stream); |
---|
805 |
|
---|
806 |
retval=freebob_ringbuffer_write(stream->buffer,(char *)buffer,nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t); |
---|
807 |
|
---|
808 |
return retval; |
---|
809 |
} |
---|
810 |
|
---|
811 |
int freebob_streaming_read(freebob_device_t *dev, int i, freebob_sample_t *buffer, int nsamples) { |
---|
812 |
int retval; |
---|
813 |
|
---|
814 |
freebob_stream_t *stream; |
---|
815 |
assert(i<dev->nb_capture_streams); |
---|
816 |
|
---|
817 |
stream=*(dev->capture_streams+i); |
---|
818 |
assert(stream); |
---|
819 |
// fprintf(stderr,"rb read [%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, retval); |
---|
820 |
|
---|
821 |
retval=freebob_ringbuffer_read(stream->buffer, (char *)buffer, nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t); |
---|
822 |
|
---|
823 |
// fprintf(stderr,"rb read1 [%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, retval); |
---|
824 |
|
---|
825 |
return retval; |
---|
826 |
} |
---|
827 |
|
---|
828 |
pthread_t freebob_streaming_get_packetizer_thread(freebob_device_t *dev) { |
---|
829 |
return dev->packetizer.transfer_thread; |
---|
830 |
} |
---|
831 |
|
---|
832 |
/* --------------------- * |
---|
833 |
* PRIVATE STUFF * |
---|
834 |
* --------------------- */ |
---|
835 |
|
---|
836 |
|
---|
837 |
unsigned int freebob_streaming_register_generic_stream(freebob_stream_t *stream, freebob_stream_t ***oldset, unsigned int set_size) { |
---|
838 |
int i; |
---|
839 |
int found=0; |
---|
840 |
unsigned int new_set_size; |
---|
841 |
|
---|
842 |
freebob_stream_t **new_streams=calloc(set_size+1,sizeof(freebob_stream_t *)); |
---|
843 |
freebob_stream_t **set=*oldset; |
---|
844 |
|
---|
845 |
for (i=0;i<set_size;i++) { |
---|
846 |
*(new_streams+i)=*(set+i); |
---|
847 |
if(*(set+i)==stream) { |
---|
848 |
printError("FREEBOB: stream already registered\n"); |
---|
849 |
found=1; |
---|
850 |
} |
---|
851 |
} |
---|
852 |
if (!found) { |
---|
853 |
*(new_streams+set_size)=stream; |
---|
854 |
new_set_size=set_size+1; |
---|
855 |
|
---|
856 |
free(*oldset); |
---|
857 |
*oldset=new_streams; |
---|
858 |
} else { |
---|
859 |
free(new_streams); |
---|
860 |
new_set_size=set_size; |
---|
861 |
} |
---|
862 |
return new_set_size; |
---|
863 |
|
---|
864 |
} |
---|
865 |
|
---|
866 |
void freebob_streaming_register_capture_stream(freebob_device_t *dev, freebob_stream_t *stream) { |
---|
867 |
dev->nb_capture_streams= |
---|
868 |
freebob_streaming_register_generic_stream( |
---|
869 |
stream, |
---|
870 |
&dev->capture_streams, |
---|
871 |
dev->nb_capture_streams); |
---|
872 |
if (stream->spec.format==IEC61883_STREAM_TYPE_MBLA) { |
---|
873 |
dev->nb_synced_capture_streams= |
---|
874 |
freebob_streaming_register_generic_stream( |
---|
875 |
stream, |
---|
876 |
&dev->synced_capture_streams, |
---|
877 |
dev->nb_synced_capture_streams); |
---|
878 |
} |
---|
879 |
} |
---|
880 |
|
---|
881 |
void freebob_streaming_register_playback_stream(freebob_device_t *dev, freebob_stream_t *stream) { |
---|
882 |
dev->nb_playback_streams= |
---|
883 |
freebob_streaming_register_generic_stream( |
---|
884 |
stream, |
---|
885 |
&dev->playback_streams, |
---|
886 |
dev->nb_playback_streams); |
---|
887 |
if (stream->spec.format==IEC61883_STREAM_TYPE_MBLA) { |
---|
888 |
dev->nb_synced_playback_streams= |
---|
889 |
freebob_streaming_register_generic_stream( |
---|
890 |
stream, |
---|
891 |
&dev->synced_playback_streams, |
---|
892 |
dev->nb_synced_playback_streams); |
---|
893 |
} |
---|
894 |
} |
---|
895 |
|
---|
896 |
static inline int |
---|
897 |
freebob_streaming_period_complete (freebob_device_t *dev) { |
---|
898 |
unsigned long i; |
---|
899 |
//unsigned int period_boundary_bytes=dev->options.period_size*sizeof(freebob_sample_t); |
---|
900 |
|
---|
901 |
assert(dev); |
---|
902 |
|
---|
903 |
for(i=0; i < dev->nb_connections; i++) { |
---|
904 |
freebob_connection_t *connection= &(dev->connections[i]); |
---|
905 |
if (connection->status.frames_left > 0) { |
---|
906 |
return FALSE; |
---|
907 |
} |
---|
908 |
} |
---|
909 |
return TRUE; |
---|
910 |
|
---|
911 |
#if 0 |
---|
912 |
for(i=0; i < dev->nb_synced_capture_streams; i++) { |
---|
913 |
assert(dev->synced_capture_streams); |
---|
914 |
assert(dev->synced_capture_streams[i]); |
---|
915 |
|
---|
916 |
/* We check if there is more than one period of samples in the buffer. |
---|
917 |
* if not the period isn't complete yet. |
---|
918 |
*/ |
---|
919 |
if (freebob_ringbuffer_read_space(dev->synced_capture_streams[i]->buffer) < period_boundary_bytes) { |
---|
920 |
return FALSE; |
---|
921 |
} |
---|
922 |
} |
---|
923 |
|
---|
924 |
for(i=0; i < dev->nb_synced_playback_streams; i++) { |
---|
925 |
assert(dev->synced_playback_streams); |
---|
926 |
assert(dev->synced_playback_streams[i]); |
---|
927 |
//FIXME: check this! |
---|
928 |
/* We check if there is still one period of samples in the output buffer. |
---|
929 |
* if so, the period isn't complete yet. |
---|
930 |
*/ |
---|
931 |
if (freebob_ringbuffer_read_space(dev->synced_playback_streams[i]->buffer) > period_boundary_bytes) { |
---|
932 |
return FALSE; |
---|
933 |
} |
---|
934 |
} |
---|
935 |
return TRUE; |
---|
936 |
#endif |
---|
937 |
} |
---|
938 |
|
---|
939 |
static inline void |
---|
940 |
freebob_streaming_period_reset (freebob_device_t *dev) { |
---|
941 |
// unsigned long i; |
---|
942 |
//unsigned int period_boundary_bytes=dev->options.period_size*sizeof(freebob_sample_t); |
---|
943 |
unsigned long i; |
---|
944 |
//unsigned int period_boundary_bytes=dev->options.period_size*sizeof(freebob_sample_t); |
---|
945 |
printEnter(); |
---|
946 |
assert(dev); |
---|
947 |
|
---|
948 |
for(i=0; i < dev->nb_connections; i++) { |
---|
949 |
freebob_connection_t *connection= &(dev->connections[i]); |
---|
950 |
connection->status.frames_left+=dev->options.period_size; |
---|
951 |
} |
---|
952 |
printExit(); |
---|
953 |
return; |
---|
954 |
} |
---|
955 |
|
---|
956 |
static inline int |
---|
957 |
freebob_streaming_xrun_detected (freebob_device_t *dev, freebob_connection_t **connections, int nb_connections) { |
---|
958 |
int i; |
---|
959 |
|
---|
960 |
for(i=0; i < nb_connections; i++) { |
---|
961 |
assert((connections[i])); |
---|
962 |
if (connections[i]->status.xruns>0) { |
---|
963 |
return TRUE; |
---|
964 |
} |
---|
965 |
} |
---|
966 |
return FALSE; |
---|
967 |
} |
---|
968 |
|
---|
969 |
int freebob_streaming_start_iso(freebob_device_t *dev) { |
---|
970 |
int err; |
---|
971 |
unsigned int c; |
---|
972 |
|
---|
973 |
// start ISO xmit/receive |
---|
974 |
for(c=0; c < dev->nb_connections; c++) { |
---|
975 |
err=0; |
---|
976 |
freebob_connection_t *connection= &(dev->connections[c]); |
---|
977 |
if (connection->spec.direction == FREEBOB_CAPTURE) { |
---|
978 |
debugPrint(DEBUG_LEVEL_STARTUP, "Start ISO receive for connection %d on channel %d ...\n", c, connection->iso.iso_channel); |
---|
979 |
|
---|
980 |
err = raw1394_iso_recv_start( |
---|
981 |
connection->raw_handle, |
---|
982 |
0, // connection->iso.startcycle, |
---|
983 |
-1,//IEC61883_TAG_WITH_CIP, |
---|
984 |
0); |
---|
985 |
|
---|
986 |
if (err) { |
---|
987 |
printError("FREEBOB: couldn't start receiving: %s\n", |
---|
988 |
strerror (errno)); |
---|
989 |
// TODO: cleanup |
---|
990 |
return err; |
---|
991 |
} |
---|
992 |
|
---|
993 |
} else if (connection->spec.direction == FREEBOB_PLAYBACK) { |
---|
994 |
debugPrintWithTimeStamp(DEBUG_LEVEL_STARTUP, "Start ISO transmit for connection %d on channel %d\n", c, connection->iso.iso_channel); |
---|
995 |
|
---|
996 |
err=raw1394_iso_xmit_start( |
---|
997 |
connection->raw_handle, |
---|
998 |
12, // connection->iso.startcycle, |
---|
999 |
connection->iso.prebuffers); |
---|
1000 |
|
---|
1001 |
if (err) { |
---|
1002 |
printError("FREEBOB: couldn't start transmitting: %s\n", |
---|
1003 |
strerror (errno)); |
---|
1004 |
// TODO: cleanup |
---|
1005 |
return err; |
---|
1006 |
} |
---|
1007 |
} |
---|
1008 |
} |
---|
1009 |
return 0; |
---|
1010 |
} |
---|
1011 |
|
---|
1012 |
int freebob_streaming_stop_iso(freebob_device_t *dev) { |
---|
1013 |
unsigned int c; |
---|
1014 |
// stop ISO xmit/receive |
---|
1015 |
for(c=0; c < dev->nb_connections; c++) { |
---|
1016 |
freebob_connection_t *connection= &(dev->connections[c]); |
---|
1017 |
|
---|
1018 |
debugPrintWithTimeStamp(DEBUG_LEVEL_STARTUP, "Stop connection %d on channel %d ...\n", c, connection->iso.iso_channel); |
---|
1019 |
|
---|
1020 |
raw1394_iso_stop(connection->raw_handle); |
---|
1021 |
} |
---|
1022 |
return 0; |
---|
1023 |
} |
---|
1024 |
|
---|
1025 |
/* |
---|
1026 |
* The thread responsible for packet iteration |
---|
1027 |
*/ |
---|
1028 |
|
---|
1029 |
void * freebob_iso_packet_iterator(void *arg) |
---|
1030 |
{ |
---|
1031 |
|
---|
1032 |
freebob_device_t * dev=(freebob_device_t *) arg; |
---|
1033 |
int err; |
---|
1034 |
int cycle=0; |
---|
1035 |
unsigned int c; |
---|
1036 |
int underrun_detected=0; |
---|
1037 |
|
---|
1038 |
freebob_connection_t *connection=NULL; |
---|
1039 |
|
---|
1040 |
assert(dev); |
---|
1041 |
assert(dev->sync_master_connection); |
---|
1042 |
assert(dev->connections); |
---|
1043 |
|
---|
1044 |
debugPrint(DEBUG_LEVEL_STARTUP, "Entering packetizer thread...\n"); |
---|
1045 |
|
---|
1046 |
//freebob_streaming_start_iso(dev); |
---|
1047 |
|
---|
1048 |
// when starting the thread, we should wait with iterating the slave connections |
---|
1049 |
// until the master connection has processed some samples, because the devices |
---|
1050 |
// tend to start with a stream of no-data packets, leading to xruns on slave |
---|
1051 |
// transmit, leading to multiple restarts of the thread, which doesn't work correctly (yet) |
---|
1052 |
debugPrint(DEBUG_LEVEL_STARTUP, "Waiting for the sync master...\n"); |
---|
1053 |
|
---|
1054 |
connection=dev->sync_master_connection; |
---|
1055 |
while(connection->status.events==0) { |
---|
1056 |
err=0; |
---|
1057 |
|
---|
1058 |
// get a packet on the sync master connection |
---|
1059 |
err=raw1394_loop_iterate(connection->raw_handle); |
---|
1060 |
|
---|
1061 |
if (err == -1) { |
---|
1062 |
printError("Possible raw1394 error: %s on sync master connection: %d\n", |
---|
1063 |
strerror (errno),connection->spec.id); |
---|
1064 |
|
---|
1065 |
dev->packetizer.status = -2; |
---|
1066 |
dev->packetizer.retval = 0; |
---|
1067 |
break; |
---|
1068 |
} |
---|
1069 |
|
---|
1070 |
// detect underruns on the sync master connection |
---|
1071 |
if (freebob_streaming_xrun_detected(dev,&connection,1)) { |
---|
1072 |
printError("Xrun on sync master connection %d\n", connection->spec.id); |
---|
1073 |
underrun_detected=TRUE; |
---|
1074 |
break; // we can exit as the underrun handler will flush the buffers anyway |
---|
1075 |
} |
---|
1076 |
} |
---|
1077 |
|
---|
1078 |
debugPrint(DEBUG_LEVEL_STARTUP, "Go Go Go!!!\n"); |
---|
1079 |
|
---|
1080 |
//sem_post(&dev->packetizer.transfer_ack); |
---|
1081 |
|
---|
1082 |
while (dev->packetizer.run && !underrun_detected) { |
---|
1083 |
//sem_wait(&dev->packetizer.transfer_ack); |
---|
1084 |
|
---|
1085 |
freebob_streaming_period_reset(dev); |
---|
1086 |
|
---|
1087 |
while(( !freebob_streaming_period_complete(dev) |
---|
1088 |
&& !underrun_detected |
---|
1089 |
&& (dev->packetizer.run))) { |
---|
1090 |
err=0; |
---|
1091 |
|
---|
1092 |
// this makes sure the sync_master finishes before the others finish |
---|
1093 |
connection=dev->sync_master_connection; |
---|
1094 |
if (connection->status.frames_left > 0) { |
---|
1095 |
// process a packet on the sync master connection |
---|
1096 |
err=raw1394_loop_iterate(connection->raw_handle); |
---|
1097 |
|
---|
1098 |
if (err == -1) { |
---|
1099 |
printError("Possible raw1394 error: %s on sync master connection: %d\n", |
---|
1100 |
strerror (errno),connection->spec.id); |
---|
1101 |
|
---|
1102 |
dev->packetizer.status = -2; |
---|
1103 |
dev->packetizer.retval = 0; |
---|
1104 |
break; |
---|
1105 |
} |
---|
1106 |
|
---|
1107 |
// detect underruns on the sync master connection |
---|
1108 |
if (freebob_streaming_xrun_detected(dev,&connection,1)) { |
---|
1109 |
printError("Xrun on sync master connection %d\n", connection->spec.id); |
---|
1110 |
underrun_detected=TRUE; |
---|
1111 |
break; // we can exit as the underrun handler will flush the buffers anyway |
---|
1112 |
} |
---|
1113 |
} |
---|
1114 |
// now iterate on the slave connections |
---|
1115 |
|
---|
1116 |
for(c=0; c<dev->nb_connections; c++) { |
---|
1117 |
|
---|
1118 |
connection = &(dev->connections[c]); |
---|
1119 |
|
---|
1120 |
// skip the sync master and the connections that are finished |
---|
1121 |
if ((connection == dev->sync_master_connection) || (connection->status.frames_left <= 0)) |
---|
1122 |
continue; |
---|
1123 |
|
---|
1124 |
err=raw1394_loop_iterate(connection->raw_handle); |
---|
1125 |
|
---|
1126 |
if (err == -1) { |
---|
1127 |
printError("Possible raw1394 error: %s on connection: %d\n", |
---|
1128 |
strerror (errno),connection->spec.id); |
---|
1129 |
dev->packetizer.status = -2; |
---|
1130 |
dev->packetizer.retval = 0; |
---|
1131 |
} |
---|
1132 |
|
---|
1133 |
// detect underruns |
---|
1134 |
if (freebob_streaming_xrun_detected(dev,&connection,1)) { |
---|
1135 |
printError("Xrun on slave connection %d\n", connection->spec.id); |
---|
1136 |
underrun_detected=TRUE; |
---|
1137 |
break; // we can exit as the underrun handler will flush the buffers anyway |
---|
1138 |
} |
---|
1139 |
} |
---|
1140 |
|
---|
1141 |
cycle++; |
---|
1142 |
} |
---|
1143 |
|
---|
1144 |
if(underrun_detected) { |
---|
1145 |
dev->xrun_detected=TRUE; |
---|
1146 |
//underrun_detected=0; |
---|
1147 |
} |
---|
1148 |
|
---|
1149 |
// notify the waiting thread |
---|
1150 |
#ifdef DEBUG |
---|
1151 |
debugPrint(DEBUG_LEVEL_HANDLERS, "Post semaphore "); |
---|
1152 |
for(c=0; c<dev->nb_connections; c++) { |
---|
1153 |
connection = &(dev->connections[c]); |
---|
1154 |
debugPrintShort(DEBUG_LEVEL_HANDLERS,"[%d: %d]",c,connection->status.frames_left); |
---|
1155 |
} |
---|
1156 |
debugPrintShort(DEBUG_LEVEL_HANDLERS,"\n"); |
---|
1157 |
#endif |
---|
1158 |
sem_post(&dev->packetizer.transfer_boundary); |
---|
1159 |
|
---|
1160 |
|
---|
1161 |
#ifdef DEBUG |
---|
1162 |
// update the packet counter |
---|
1163 |
if((dev->sync_master_connection->status.packets - dev->sync_master_connection->status.total_packets_prev) > 1024*4) { |
---|
1164 |
// if(1) { |
---|
1165 |
unsigned int i; |
---|
1166 |
debugPrintShort(DEBUG_LEVEL_PACKETCOUNTER,"\r -> "); |
---|
1167 |
|
---|
1168 |
for(i=0; i < dev->nb_connections; i++) { |
---|
1169 |
freebob_connection_t *connection= &(dev->connections[i]); |
---|
1170 |
assert(connection); |
---|
1171 |
|
---|
1172 |
/* Debug info format: |
---|
1173 |
* [direction, packetcount, bufferfill, packetdrop |
---|
1174 |
*/ |
---|
1175 |
debugPrintShort(DEBUG_LEVEL_PACKETCOUNTER,"[%s, %02d, %12d, %4d, (%04d)]", |
---|
1176 |
(connection->spec.direction==FREEBOB_CAPTURE ? "C" : "P"), |
---|
1177 |
connection->status.fdf, |
---|
1178 |
connection->status.packets, |
---|
1179 |
connection->status.dropped, |
---|
1180 |
freebob_ringbuffer_read_space(connection->streams[0].buffer)/sizeof(freebob_sample_t) |
---|
1181 |
); |
---|
1182 |
} |
---|
1183 |
|
---|
1184 |
debugPrintShort(DEBUG_LEVEL_PACKETCOUNTER," XRUNS (%4d)",dev->xrun_count); |
---|
1185 |
fflush (stderr); |
---|
1186 |
|
---|
1187 |
dev->sync_master_connection->status.total_packets_prev=dev->sync_master_connection->status.packets; |
---|
1188 |
} |
---|
1189 |
|
---|
1190 |
#endif |
---|
1191 |
|
---|
1192 |
} |
---|
1193 |
|
---|
1194 |
//freebob_streaming_stop_iso(dev); |
---|
1195 |
|
---|
1196 |
debugPrint(DEBUG_LEVEL_STARTUP, "Exiting packetizer thread...\n"); |
---|
1197 |
|
---|
1198 |
|
---|
1199 |
pthread_exit (0); |
---|
1200 |
} |
---|
1201 |
|
---|
1202 |
static int freebob_am824_recv(char *data, |
---|
1203 |
int nevents, unsigned int dbc, |
---|
1204 |
freebob_connection_t *connection); |
---|
1205 |
|
---|
1206 |
static int freebob_am824_xmit(char *data, |
---|
1207 |
int nevents, unsigned int dbc, |
---|
1208 |
freebob_connection_t *connection); |
---|
1209 |
|
---|
1210 |
/** |
---|
1211 |
* ISO send/receive callback handlers |
---|
1212 |
*/ |
---|
1213 |
|
---|
1214 |
static enum raw1394_iso_disposition |
---|
1215 |
iso_master_receive_handler(raw1394handle_t handle, unsigned char *data, |
---|
1216 |
unsigned int length, unsigned char channel, |
---|
1217 |
unsigned char tag, unsigned char sy, unsigned int cycle, |
---|
1218 |
unsigned int dropped) |
---|
1219 |
{ |
---|
1220 |
enum raw1394_iso_disposition retval=RAW1394_ISO_OK; |
---|
1221 |
|
---|
1222 |
int xrun=0; |
---|
1223 |
|
---|
1224 |
freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle); |
---|
1225 |
assert(connection); |
---|
1226 |
|
---|
1227 |
struct iec61883_packet *packet = (struct iec61883_packet *) data; |
---|
1228 |
assert(packet); |
---|
1229 |
|
---|
1230 |
// FIXME: dropped packets are very bad when transmitting and the other side is sync'ing on that! |
---|
1231 |
//connection->status.packets+=dropped; |
---|
1232 |
connection->status.dropped+=dropped; |
---|
1233 |
|
---|
1234 |
if((packet->fdf) != 0xFF && (packet->dbs>0) && (length>=2*sizeof(quadlet_t))) { |
---|
1235 |
unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs; |
---|
1236 |
|
---|
1237 |
// add the data payload to the ringbuffer |
---|
1238 |
xrun= freebob_am824_recv(data + 8, nevents, packet->dbc, connection); |
---|
1239 |
|
---|
1240 |
if(xrun) { |
---|
1241 |
printError("MASTER RCV: Buffer overrun!\n"); |
---|
1242 |
connection->status.xruns++; |
---|
1243 |
retval=RAW1394_ISO_DEFER; |
---|
1244 |
} else { |
---|
1245 |
retval=RAW1394_ISO_OK; |
---|
1246 |
} |
---|
1247 |
|
---|
1248 |
// keep track of the total amount of events received |
---|
1249 |
connection->status.events+=nevents; |
---|
1250 |
|
---|
1251 |
connection->status.fdf=packet->fdf; |
---|
1252 |
|
---|
1253 |
} else { |
---|
1254 |
// discard packet |
---|
1255 |
// can be important for sync though |
---|
1256 |
} |
---|
1257 |
|
---|
1258 |
// one packet received |
---|
1259 |
connection->status.packets++; |
---|
1260 |
if(packet->dbs) { |
---|
1261 |
debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL, |
---|
1262 |
"MASTER RCV: %08d, CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %6d\n", |
---|
1263 |
cycle, |
---|
1264 |
channel, packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, length, |
---|
1265 |
((length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped); |
---|
1266 |
} |
---|
1267 |
|
---|
1268 |
if( (!(connection->status.packets % 4)) || (connection->status.frames_left<=0)) { |
---|
1269 |
retval=RAW1394_ISO_DEFER; |
---|
1270 |
} |
---|
1271 |
|
---|
1272 |
return retval; |
---|
1273 |
} |
---|
1274 |
|
---|
1275 |
static enum raw1394_iso_disposition |
---|
1276 |
iso_slave_transmit_handler(raw1394handle_t handle, |
---|
1277 |
unsigned char *data, unsigned int *length, |
---|
1278 |
unsigned char *tag, unsigned char *sy, |
---|
1279 |
int cycle, unsigned int dropped) |
---|
1280 |
{ |
---|
1281 |
freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle); |
---|
1282 |
assert(connection); |
---|
1283 |
|
---|
1284 |
struct iec61883_packet *packet = (struct iec61883_packet *) data; |
---|
1285 |
assert(packet); |
---|
1286 |
assert(length); |
---|
1287 |
assert(tag); |
---|
1288 |
assert(sy); |
---|
1289 |
|
---|
1290 |
// construct the packet cip |
---|
1291 |
int nevents = iec61883_cip_fill_header (handle, &connection->status.cip, packet); |
---|
1292 |
int xrun=0; |
---|
1293 |
int nsamples=0; |
---|
1294 |
|
---|
1295 |
enum raw1394_iso_disposition retval = RAW1394_ISO_OK; |
---|
1296 |
|
---|
1297 |
// debug |
---|
1298 |
if(packet->fdf != 0xFF) { |
---|
1299 |
connection->status.fdf=packet->fdf; |
---|
1300 |
} |
---|
1301 |
|
---|
1302 |
if (nevents > 0) { |
---|
1303 |
nsamples = nevents; |
---|
1304 |
} |
---|
1305 |
else { |
---|
1306 |
if (connection->status.cip.mode == IEC61883_MODE_BLOCKING_EMPTY) { |
---|
1307 |
nsamples = 0; |
---|
1308 |
} |
---|
1309 |
else { |
---|
1310 |
nsamples = connection->status.cip.syt_interval; |
---|
1311 |
} |
---|
1312 |
} |
---|
1313 |
|
---|
1314 |
// dropped packets are very bad when transmitting and the other side is sync'ing on that! |
---|
1315 |
//connection->status.packets+=dropped; |
---|
1316 |
connection->status.dropped += dropped; |
---|
1317 |
|
---|
1318 |
if (nsamples > 0) { |
---|
1319 |
// read the data payload from the ringbuffer |
---|
1320 |
xrun=freebob_am824_xmit(data+8, nsamples, packet->dbc, connection); |
---|
1321 |
} |
---|
1322 |
|
---|
1323 |
if (xrun) { |
---|
1324 |
printError("SLAVE XMT: Buffer underrun!\n"); |
---|
1325 |
connection->status.xruns++; |
---|
1326 |
retval=RAW1394_ISO_DEFER; |
---|
1327 |
nsamples=0; |
---|
1328 |
} |
---|
1329 |
|
---|
1330 |
*length = nsamples * connection->spec.dimension * sizeof (quadlet_t) + 8; |
---|
1331 |
*tag = IEC61883_TAG_WITH_CIP; |
---|
1332 |
*sy = 0; |
---|
1333 |
|
---|
1334 |
// keep track of the total amount of events transmitted |
---|
1335 |
connection->status.events+=nsamples; |
---|
1336 |
|
---|
1337 |
// one packet transmitted |
---|
1338 |
connection->status.packets++; |
---|
1339 |
|
---|
1340 |
if(packet->dbs) { |
---|
1341 |
debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL, |
---|
1342 |
"SLAVE XMT: %08d, CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %4d, info->packets=%4d, events=%4d, %d, %d %d %d\n", cycle, |
---|
1343 |
connection->iso.iso_channel, packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, *length,((*length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped, |
---|
1344 |
connection->status.packets, connection->status.events, connection->status.frames_left, |
---|
1345 |
nevents, nsamples,xrun); |
---|
1346 |
} |
---|
1347 |
|
---|
1348 |
if( (!(connection->status.packets % 4)) || (connection->status.frames_left<=0)) { |
---|
1349 |
retval=RAW1394_ISO_DEFER; |
---|
1350 |
} |
---|
1351 |
return retval; |
---|
1352 |
|
---|
1353 |
} |
---|
1354 |
|
---|
1355 |
/** |
---|
1356 |
* The master transmit handler. |
---|
1357 |
* |
---|
1358 |
* This is the most difficult, because we have to generate timing information ourselves. |
---|
1359 |
* |
---|
1360 |
*/ |
---|
1361 |
|
---|
1362 |
/* |
---|
1363 |
Includes code from libiec61883 |
---|
1364 |
*/ |
---|
1365 |
static enum raw1394_iso_disposition |
---|
1366 |
iso_master_transmit_handler(raw1394handle_t handle, |
---|
1367 |
unsigned char *data, unsigned int *length, |
---|
1368 |
unsigned char *tag, unsigned char *sy, |
---|
1369 |
int cycle, unsigned int dropped) |
---|
1370 |
{ |
---|
1371 |
freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle); |
---|
1372 |
assert(connection); |
---|
1373 |
|
---|
1374 |
struct iec61883_packet *packet = (struct iec61883_packet *) data; |
---|
1375 |
assert(packet); |
---|
1376 |
assert(length); |
---|
1377 |
assert(tag); |
---|
1378 |
assert(sy); |
---|
1379 |
|
---|
1380 |
// construct the packet cip |
---|
1381 |
int nevents = iec61883_cip_fill_header (handle, &connection->status.cip, packet); |
---|
1382 |
int xrun=0; |
---|
1383 |
int nsamples=0; |
---|
1384 |
|
---|
1385 |
enum raw1394_iso_disposition retval = RAW1394_ISO_OK; |
---|
1386 |
// debug |
---|
1387 |
if(packet->fdf != 0xFF) { |
---|
1388 |
connection->status.fdf=packet->fdf; |
---|
1389 |
} |
---|
1390 |
|
---|
1391 |
if (nevents > 0) { |
---|
1392 |
nsamples = nevents; |
---|
1393 |
} |
---|
1394 |
else { |
---|
1395 |
if (connection->status.cip.mode == IEC61883_MODE_BLOCKING_EMPTY) { |
---|
1396 |
nsamples = 0; |
---|
1397 |
} |
---|
1398 |
else { |
---|
1399 |
nsamples = connection->status.cip.syt_interval; |
---|
1400 |
} |
---|
1401 |
} |
---|
1402 |
|
---|
1403 |
// dropped packets are very bad when transmitting and the other side is sync'ing on that! |
---|
1404 |
//connection->status.packets+=dropped; |
---|
1405 |
connection->status.dropped += dropped; |
---|
1406 |
|
---|
1407 |
if (nsamples > 0) { |
---|
1408 |
// read the data payload from the ringbuffer |
---|
1409 |
xrun=freebob_am824_xmit(data+8, nsamples, packet->dbc, connection); |
---|
1410 |
} |
---|
1411 |
|
---|
1412 |
if (xrun) { |
---|
1413 |
printError("MASTER XMT: Buffer underrun!\n"); |
---|
1414 |
connection->status.xruns++; |
---|
1415 |
retval=RAW1394_ISO_DEFER; |
---|
1416 |
/* this is to make sure that the receiving device doesnt receive junk, |
---|
1417 |
as part of the package wasn't filled. |
---|
1418 |
*/ |
---|
1419 |
nsamples=0; |
---|
1420 |
} |
---|
1421 |
|
---|
1422 |
*length = nsamples * connection->spec.dimension * sizeof (quadlet_t) + 8; |
---|
1423 |
*tag = IEC61883_TAG_WITH_CIP; |
---|
1424 |
*sy = 0; |
---|
1425 |
|
---|
1426 |
// keep track of the total amount of events transmitted |
---|
1427 |
connection->status.events+=nsamples; |
---|
1428 |
|
---|
1429 |
// one packet transmitted |
---|
1430 |
connection->status.packets++; |
---|
1431 |
|
---|
1432 |
if(packet->dbs) { |
---|
1433 |
debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL, |
---|
1434 |
"MASTER XMT: CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %4d, info->packets=%4d, events=%4d, %d, %d %d %d\n", |
---|
1435 |
connection->iso.iso_channel, packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, *length,((*length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped, |
---|
1436 |
connection->status.packets, connection->status.events, connection->status.frames_left, |
---|
1437 |
nevents, nsamples,xrun); |
---|
1438 |
} |
---|
1439 |
|
---|
1440 |
if( (!(connection->status.packets % 4)) || (connection->status.frames_left<=0)) { |
---|
1441 |
retval=RAW1394_ISO_DEFER; |
---|
1442 |
} |
---|
1443 |
|
---|
1444 |
return retval; |
---|
1445 |
|
---|
1446 |
} |
---|
1447 |
|
---|
1448 |
static enum raw1394_iso_disposition |
---|
1449 |
iso_slave_receive_handler(raw1394handle_t handle, unsigned char *data, |
---|
1450 |
unsigned int length, unsigned char channel, |
---|
1451 |
unsigned char tag, unsigned char sy, unsigned int cycle, |
---|
1452 |
unsigned int dropped) |
---|
1453 |
{ |
---|
1454 |
enum raw1394_iso_disposition retval=RAW1394_ISO_OK; |
---|
1455 |
/* slave receive is easy if you assume that the connections are synced |
---|
1456 |
* Synced connections have matched data rates, so just receiving and calling the rcv handler would |
---|
1457 |
* suffice in this case. As the connection is externally matched to the master connection, the buffer fill |
---|
1458 |
* will be ok. |
---|
1459 |
*/ |
---|
1460 |
|
---|
1461 |
int xrun=0; |
---|
1462 |
|
---|
1463 |
freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle); |
---|
1464 |
assert(connection); |
---|
1465 |
|
---|
1466 |
struct iec61883_packet *packet = (struct iec61883_packet *) data; |
---|
1467 |
assert(packet); |
---|
1468 |
|
---|
1469 |
// FIXME: dropped packets are very bad when transmitting and the other side is sync'ing on that! |
---|
1470 |
//connection->status.packets+=dropped; |
---|
1471 |
connection->status.dropped+=dropped; |
---|
1472 |
|
---|
1473 |
if((packet->fdf) != 0xFF && (packet->dbs>0) && (length>=2*sizeof(quadlet_t))) { |
---|
1474 |
unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs; |
---|
1475 |
connection->status.fdf=packet->fdf; |
---|
1476 |
|
---|
1477 |
// add the data payload to the ringbuffer |
---|
1478 |
xrun= freebob_am824_recv(data + 8, nevents, packet->dbc, connection); |
---|
1479 |
|
---|
1480 |
if(xrun) { |
---|
1481 |
printError("SLAVE RCV: Buffer overrun!\n"); |
---|
1482 |
connection->status.xruns++; |
---|
1483 |
retval=RAW1394_ISO_DEFER; |
---|
1484 |
} else { |
---|
1485 |
retval=RAW1394_ISO_OK; |
---|
1486 |
} |
---|
1487 |
|
---|
1488 |
// keep track of the total amount of events received |
---|
1489 |
connection->status.events+=nevents; |
---|
1490 |
} else { |
---|
1491 |
// discard packet |
---|
1492 |
// can be important for sync though |
---|
1493 |
} |
---|
1494 |
|
---|
1495 |
// one packet received |
---|
1496 |
connection->status.packets++; |
---|
1497 |
|
---|
1498 |
if(packet->dbs) { |
---|
1499 |
debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL, |
---|
1500 |
"SLAVE RCV: CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %6d\n", |
---|
1501 |
channel, packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, length, |
---|
1502 |
((length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped); |
---|
1503 |
} |
---|
1504 |
|
---|
1505 |
if( (!(connection->status.packets % 4)) || (connection->status.frames_left<=0)) { |
---|
1506 |
retval=RAW1394_ISO_DEFER; |
---|
1507 |
} |
---|
1508 |
|
---|
1509 |
return retval; |
---|
1510 |
} |
---|
1511 |
|
---|
1512 |
/* |
---|
1513 |
* write received events to the stream ringbuffers. |
---|
1514 |
*/ |
---|
1515 |
|
---|
1516 |
int freebob_am824_recv(char *data, |
---|
1517 |
int nevents, unsigned int dbc, |
---|
1518 |
freebob_connection_t *connection) |
---|
1519 |
{ |
---|
1520 |
int xrun=0; |
---|
1521 |
unsigned int i=0; |
---|
1522 |
|
---|
1523 |
for(i = 0; i < connection->nb_streams; i++) { |
---|
1524 |
freebob_stream_t *stream = &(connection->streams[i]); |
---|
1525 |
size_t written=0; |
---|
1526 |
|
---|
1527 |
assert(stream); |
---|
1528 |
|
---|
1529 |
debugPrintShort(DEBUG_LEVEL_HANDLERS,"[%d: %d ",i,freebob_ringbuffer_write_space(stream->buffer)); |
---|
1530 |
|
---|
1531 |
written = freebob_decode_events_to_stream( |
---|
1532 |
connection, |
---|
1533 |
stream, |
---|
1534 |
(quadlet_t *)data, |
---|
1535 |
nevents, |
---|
1536 |
dbc |
---|
1537 |
); |
---|
1538 |
|
---|
1539 |
if (written < nevents) { |
---|
1540 |
xrun++; |
---|
1541 |
} |
---|
1542 |
|
---|
1543 |
debugPrintShort(DEBUG_LEVEL_HANDLERS, "%d %d]",written,freebob_ringbuffer_write_space(stream->buffer)); |
---|
1544 |
} |
---|
1545 |
|
---|
1546 |
connection->status.frames_left-=nevents; |
---|
1547 |
|
---|
1548 |
debugPrintShort(DEBUG_LEVEL_HANDLERS, "\n"); |
---|
1549 |
|
---|
1550 |
return xrun; |
---|
1551 |
} |
---|
1552 |
|
---|
1553 |
/* |
---|
1554 |
* get xmit events from ringbuffer |
---|
1555 |
*/ |
---|
1556 |
|
---|
1557 |
int freebob_am824_xmit( char *data, |
---|
1558 |
int nevents, unsigned int dbc, |
---|
1559 |
freebob_connection_t *connection) |
---|
1560 |
{ |
---|
1561 |
int xrun=0; |
---|
1562 |
unsigned int i=0; |
---|
1563 |
|
---|
1564 |
for(i = 0; i < connection->nb_streams; i++) { |
---|
1565 |
freebob_stream_t *stream = &(connection->streams[i]); |
---|
1566 |
size_t read=0; |
---|
1567 |
|
---|
1568 |
assert(stream); |
---|
1569 |
debugPrintShort(DEBUG_LEVEL_HANDLERS, "[%d: %d ",i,freebob_ringbuffer_read_space(stream->buffer)); |
---|
1570 |
|
---|
1571 |
read = freebob_encode_stream_to_events( |
---|
1572 |
connection, |
---|
1573 |
stream, |
---|
1574 |
(quadlet_t *)data, |
---|
1575 |
nevents, |
---|
1576 |
dbc |
---|
1577 |
); |
---|
1578 |
|
---|
1579 |
debugPrintShort(DEBUG_LEVEL_HANDLERS, "%d %d]",read,freebob_ringbuffer_read_space(stream->buffer)); |
---|
1580 |
|
---|
1581 |
if (read < nevents) { |
---|
1582 |
xrun++; |
---|
1583 |
} |
---|
1584 |
|
---|
1585 |
} |
---|
1586 |
debugPrintShort(DEBUG_LEVEL_HANDLERS, "\n"); |
---|
1587 |
|
---|
1588 |
connection->status.frames_left-=nevents; |
---|
1589 |
|
---|
1590 |
return xrun; |
---|
1591 |
} |
---|
1592 |
|
---|
1593 |
int |
---|
1594 |
freebob_streaming_create_thread (pthread_t* thread, |
---|
1595 |
int priority, |
---|
1596 |
int realtime, |
---|
1597 |
void*(*start_routine)(void*), |
---|
1598 |
void* arg) |
---|
1599 |
{ |
---|
1600 |
int result = 0; |
---|
1601 |
|
---|
1602 |
result = pthread_create (thread, 0, start_routine, arg); |
---|
1603 |
if (result) { |
---|
1604 |
debugPrint(DEBUG_LEVEL_THREADS,"creating thread with default parameters"); |
---|
1605 |
} |
---|
1606 |
return result; |
---|
1607 |
} |
---|
1608 |
|
---|