root/branches/libfreebob-1.0/src/libfreebobstreaming/freebob_streaming.c

Revision 513, 90.0 kB (checked in by ppalmers, 15 years ago)

- renumber the midi location parameters to fix bogus values returned

by AV/C discovery

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
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 "libfreebob/freebob_streaming.h"
36 #include "freebob_streaming_private.h"
37 #include "freebob_connections.h"
38 #include "freebob_debug.h"
39 #include "thread.h"
40 #include "messagebuffer.h"
41
42 #include <signal.h>
43 #include <unistd.h>
44
45 /**
46  * Callbacks
47  */
48
49 static enum raw1394_iso_disposition
50 iso_slave_receive_handler(raw1394handle_t handle, unsigned char *data,
51         unsigned int length, unsigned char channel,
52         unsigned char tag, unsigned char sy, unsigned int cycle,
53         unsigned int dropped);
54        
55 static enum raw1394_iso_disposition
56 iso_master_receive_handler(raw1394handle_t handle, unsigned char *data,
57         unsigned int length, unsigned char channel,
58         unsigned char tag, unsigned char sy, unsigned int cycle,
59         unsigned int dropped);
60        
61 static enum raw1394_iso_disposition
62 iso_slave_transmit_handler(raw1394handle_t handle,
63                 unsigned char *data, unsigned int *length,
64                 unsigned char *tag, unsigned char *sy,
65                 int cycle, unsigned int dropped);
66                
67 static enum raw1394_iso_disposition
68 iso_master_transmit_handler(raw1394handle_t handle,
69                 unsigned char *data, unsigned int *length,
70                 unsigned char *tag, unsigned char *sy,
71                 int cycle, unsigned int dropped);
72                        
73 static int freebob_am824_recv(char *data,
74                                                           int nevents, unsigned int offset, unsigned int dbc,
75                                                           freebob_connection_t *connection);
76
77 static int freebob_am824_xmit(char *data,
78                                                           int nevents, unsigned int offset, unsigned int dbc,
79                                                           freebob_connection_t *connection);
80                                
81 int freebob_streaming_reset_playback_streams(freebob_device_t *dev);
82
83 int g_verbose=0;
84
85 freebob_device_t *freebob_streaming_init (freebob_device_info_t *device_info, freebob_options_t options) {
86         int i;
87         int c;
88         int err=0;
89         freebob_device_t* dev=NULL;
90         int discover_verbose=0;
91        
92         freebob_messagebuffer_init();
93
94         g_verbose=options.verbose;
95
96         if(g_verbose) discover_verbose=5;
97
98         assert(device_info);
99        
100         printMessage("FreeBoB Streaming Device Init\n");
101         printMessage(" Using FreeBoB lib version %s\n",freebob_get_version());
102         printMessage(" Device information:\n");
103        
104         printMessage(" Device options:\n");
105         /* driver related setup */
106         printMessage("  Port                     : %d\n",options.port);
107         printMessage("  Device Node Id           : %d\n",options.node_id);
108         printMessage("  Samplerate               : %d\n",options.sample_rate);
109         printMessage("  Period Size              : %d\n",options.period_size);
110         printMessage("  Nb Buffers               : %d\n",options.nb_buffers);
111         printMessage("  Directions               : %X\n",options.directions);
112        
113         // initialize the freebob_device
114         // allocate memory
115         dev=calloc(1,sizeof(freebob_device_t));
116        
117         if(!dev) {
118                 printError("cannot allocate memory for dev structure!\n");
119                 return NULL;
120         }
121        
122         // clear the device structure
123         memset(dev,0,sizeof(freebob_device_t));
124        
125         // copy the arguments to the device structure
126         memcpy(&dev->device_info, device_info, sizeof(freebob_device_info_t));
127         memcpy(&dev->options, &options, sizeof(freebob_options_t));
128        
129         // read in the device specification
130        
131         /* load the connections*/
132         /*
133          * This info should be provided by the Freebob CML application
134          *
135          */
136         freebob_connection_info_t *libfreebob_capture_connections=NULL;
137         freebob_connection_info_t *libfreebob_playback_connections=NULL;
138
139         dev->fb_handle = freebob_new_handle(options.port);
140         if (!dev->fb_handle) {
141                 free(dev);
142                 printError("cannot create libfreebob handle\n");
143                 return NULL;
144         }
145
146         if (freebob_discover_devices(dev->fb_handle, discover_verbose)!=0) {
147                 freebob_destroy_handle(dev->fb_handle);
148                 free(dev);
149                 printError("device discovering failed\n");
150                 return NULL;
151         }
152
153         /* Try and set the samplerate
154          * This should be done after device discovery
155          * but before reading the bus description as the device capabilities can change
156          */
157
158     if(options.node_id > -1) {
159         if (freebob_set_samplerate(dev->fb_handle, options.node_id, options.sample_rate) != 0) {
160             freebob_destroy_handle(dev->fb_handle);
161             free(dev);
162             printError("Failed to set samplerate...\n");
163             return NULL;
164         }
165
166         } else {
167             int devices_on_bus = freebob_get_nb_devices_on_bus(dev->fb_handle);
168             debugPrint(DEBUG_LEVEL_STARTUP,"port = %d, devices_on_bus = %d\n", options.port, devices_on_bus);
169                        
170             for(i=0;i<devices_on_bus;i++) {
171                 int node_id=freebob_get_device_node_id(dev->fb_handle, i);
172                 debugPrint(DEBUG_LEVEL_STARTUP,"set samplerate for device = %d, node = %d\n", i, node_id);
173                                
174                 if (freebob_set_samplerate(dev->fb_handle, node_id, options.sample_rate) != 0) {
175                         freebob_destroy_handle(dev->fb_handle);
176                         free(dev);
177                         printError("Failed to set samplerate...\n");
178                         return NULL;
179                 }
180             }
181
182         }
183
184         /* Read the connection specification
185          */
186  
187         if(!(options.directions & FREEBOB_IGNORE_CAPTURE)) {
188                 libfreebob_capture_connections=freebob_get_connection_info(dev->fb_handle, options.node_id, 0);
189         }
190
191         if(!(options.directions & FREEBOB_IGNORE_PLAYBACK)) {
192                 libfreebob_playback_connections=freebob_get_connection_info(dev->fb_handle, options.node_id, 1);
193         }
194  
195
196         if (libfreebob_capture_connections) {
197                 dev->nb_connections_capture=libfreebob_capture_connections->nb_connections;
198                 // FIXME:
199                 //dev->nb_connections_capture=0;
200         } else {
201                 dev->nb_connections_capture=0;
202         }       
203        
204         if (libfreebob_playback_connections) {
205                 dev->nb_connections_playback=libfreebob_playback_connections->nb_connections;
206                 // FIXME:
207 //              dev->nb_connections_playback=0;
208         } else {
209                 dev->nb_connections_playback=0;
210         }
211         // FIXME: temporary disable the playback
212 //      dev->nb_connections_playback=0;
213        
214         dev->nb_connections=dev->nb_connections_playback+dev->nb_connections_capture;
215         /* see if there are any connections */
216         if (!dev->nb_connections) {
217                 printError("No connections specified, bailing out\n");
218                 if(libfreebob_capture_connections) { free(libfreebob_capture_connections); libfreebob_capture_connections=NULL; }
219                 if(libfreebob_playback_connections) { free(libfreebob_playback_connections); libfreebob_playback_connections=NULL; }
220                 freebob_destroy_handle(dev->fb_handle);
221                 free(dev);
222                
223                 return NULL;
224         }
225        
226         dev->connections=calloc(dev->nb_connections_playback+dev->nb_connections_capture, sizeof(freebob_connection_t));
227        
228         for (c=0;c<dev->nb_connections_capture;c++) {
229                 memcpy(&dev->connections[c].spec, libfreebob_capture_connections->connections[c], sizeof(freebob_connection_spec_t));
230                 dev->connections[c].spec.direction=FREEBOB_CAPTURE;
231         }
232         for (c=0;c<dev->nb_connections_playback;c++) {
233                 memcpy(&dev->connections[c+dev->nb_connections_capture].spec, libfreebob_playback_connections->connections[c], sizeof(freebob_connection_spec_t));
234                 dev->connections[c+dev->nb_connections_capture].spec.direction=FREEBOB_PLAYBACK;
235         }
236        
237         // In order to correct for bogus midi channel numbers
238         // we redefine the location parameter to the order the
239         // channels appear in the specification
240         int midichannel=0;
241         for (c=0;c<dev->nb_connections_capture;c++) {
242                 midichannel=0;
243                 int s;
244                 freebob_connection_t *connection= &(dev->connections[c]);
245                 for (s=0;s<connection->spec.stream_info->nb_streams;s++) {
246                         if(connection->spec.stream_info->streams[s]->format == IEC61883_STREAM_TYPE_MIDI) {
247                                 connection->spec.stream_info->streams[s]->location=midichannel++;
248                         }
249                 }
250         }
251         for (c=0;c<dev->nb_connections_playback;c++) {
252                 midichannel=0;
253                 int s;
254                 freebob_connection_t *connection= &(dev->connections[c+dev->nb_connections_capture]);
255                 for (s=0;s<connection->spec.stream_info->nb_streams;s++) {
256                         if(connection->spec.stream_info->streams[s]->format == IEC61883_STREAM_TYPE_MIDI) {
257                                 connection->spec.stream_info->streams[s]->location=midichannel++;
258                         }
259                 }
260         }
261
262         /* Figure out a master connection.
263          * Either it is given in the spec libfreebob
264          * Or it is the first connection defined (capture connections first)
265          */
266         int master_found=FALSE;
267        
268         for (c=0;c<dev->nb_connections_capture+dev->nb_connections_playback;c++) {
269                 if (dev->connections[c].spec.is_master==TRUE) {
270                         master_found=TRUE;
271                         if(dev->options.sample_rate<0) {
272                                 dev->options.sample_rate=dev->connections[c].spec.samplerate;
273                         }
274                         break;
275                 }
276         }
277        
278         if((!master_found) && (dev->nb_connections_capture+dev->nb_connections_playback > 0)) {
279                 dev->connections[0].spec.is_master=TRUE;
280                 if(dev->options.sample_rate<0) {
281                         dev->options.sample_rate=dev->connections[0].spec.samplerate;
282                 }
283         }
284
285         // initialize all connections
286         for(i=0; i < dev->nb_connections; i++) {
287                 freebob_connection_t *connection= &(dev->connections[i]);
288                 if ((err=freebob_streaming_init_connection(dev, connection))<0) {
289                         printError("failed to init connection %d\n",i);
290                         break;
291                 }
292         }
293        
294         if(libfreebob_capture_connections) { freebob_free_connection_info(libfreebob_capture_connections); libfreebob_capture_connections=NULL; }
295         if(libfreebob_playback_connections) { freebob_free_connection_info(libfreebob_playback_connections); libfreebob_playback_connections=NULL; }
296        
297         // prepare the FD map   
298         // the FD map is not stricly nescessary due to dev->fdmap[i]=dev->connections[i];
299         // but makes things flexible at the moment
300        
301         assert(dev->nb_connections==dev->nb_connections_capture+dev->nb_connections_playback);
302        
303         dev->nfds   = dev->nb_connections;
304         dev->pfds   = malloc (sizeof (struct pollfd) * dev->nfds);
305         dev->fdmap  = malloc (sizeof (freebob_connection_t *) * dev->nfds); // holds the connection idx of this fd
306        
307         for(i=0; i < dev->nb_connections; i++) {
308                 freebob_connection_t *connection= &(dev->connections[i]);
309                 dev->fdmap[i]=connection;
310                 dev->pfds[i].fd = raw1394_get_fd (connection->raw_handle);
311                 dev->pfds[i].events = POLLIN;
312                 connection->pfd=&dev->pfds[i];
313         }
314        
315         // check for errors
316         if(err) {
317                 debugPrint(DEBUG_LEVEL_STARTUP, "Cleaning up connections\n");
318                
319                 // the connection that failed doesn't have to be cleaned
320                 i-=1;
321                
322                 for(; i >= 0; i--) {
323                         freebob_connection_t *connection= &(dev->connections[i]);
324                         debugPrint(DEBUG_LEVEL_STARTUP, "Cleaning up connection %d\n",i);
325                         if ((freebob_streaming_cleanup_connection(dev, connection))<0) {
326                                 printError( "Failed to clean connection %d\n",i);
327                         }
328                 }
329                 free(dev->pfds);
330                 free(dev->fdmap);
331                 free(dev->connections);
332                 free(dev);
333                 return NULL;
334         }
335        
336         freebob_destroy_handle(dev->fb_handle);
337        
338         return dev;
339
340 }
341
342 void freebob_streaming_finish(freebob_device_t *dev) {
343         debugPrint(DEBUG_LEVEL_STARTUP,"Cleaning up connections\n");
344         unsigned int i;
345         int err=0;
346        
347         // cleanup all connections
348         for(i=0; i < dev->nb_connections; i++) {
349                 freebob_connection_t *connection= &(dev->connections[i]);
350                 if ((err=freebob_streaming_cleanup_connection(dev, connection))<0) {
351                         printError("Failed to cleanup connection %d\n",i);
352                         return;
353                 }
354         }
355        
356         // free stream structures
357         if(dev->capture_streams) {
358                 free(dev->capture_streams);
359         }
360         if(dev->playback_streams) {
361                 free(dev->playback_streams);
362         }
363         if(dev->synced_capture_streams) {
364                 free(dev->synced_capture_streams);
365         }
366         if(dev->synced_playback_streams) {
367                 free(dev->synced_playback_streams);
368         }
369        
370         // cleanup data structures
371         free(dev->pfds);
372         free(dev->fdmap);
373         free(dev->connections);
374         free(dev);
375        
376         freebob_messagebuffer_exit();
377        
378         return;
379 }
380
381 int freebob_streaming_get_nb_capture_streams(freebob_device_t *dev) {
382         return dev->nb_capture_streams;
383 }
384
385 int freebob_streaming_get_nb_playback_streams(freebob_device_t *dev) {
386         return dev->nb_playback_streams;
387 }
388
389 int freebob_streaming_get_capture_stream_name(freebob_device_t *dev, int i, char* buffer, size_t buffersize) {
390         freebob_stream_t *stream;
391         if(i<dev->nb_capture_streams) {
392                 stream=*(dev->capture_streams+i);
393 /*              return snprintf (buffer, buffersize, "%s_%d_%d_%d_%s",
394                                  "cap", (int) stream->parent->spec.port,
395                                  stream->parent->spec.node & 0x3F,
396                                  stream->parent->spec.plug, stream->spec.name);
397 */
398                 return snprintf (buffer, buffersize, "dev%d%s_%s",
399                                  stream->parent->spec.id , "c", stream->spec.name);
400         } else {
401                 return -1;
402         }
403 }
404
405 int freebob_streaming_get_playback_stream_name(freebob_device_t *dev, int i, char* buffer, size_t buffersize) {
406         freebob_stream_t *stream;
407         if(i<dev->nb_playback_streams) {
408                 stream=*(dev->playback_streams+i);
409 /*              return snprintf (buffer, buffersize, "%s_%d_%d_%d_%s",
410                                  "pbk", (int) stream->parent->spec.port,
411                                  stream->parent->spec.node & 0x3F,
412                                  stream->parent->spec.plug, stream->spec.name);
413 */
414                 return snprintf (buffer, buffersize, "dev%d%s_%s",
415                                  stream->parent->spec.id, "p", stream->spec.name);
416         } else {
417                 return -1;
418         }
419 }
420
421 freebob_streaming_stream_type freebob_streaming_get_capture_stream_type(freebob_device_t *dev, int i) {
422         freebob_stream_t *stream;
423         if(i<dev->nb_capture_streams) {
424                 stream=*(dev->capture_streams+i);
425                 switch (stream->spec.format) {
426                 case IEC61883_STREAM_TYPE_MBLA:
427                         return freebob_stream_type_audio;
428                 case IEC61883_STREAM_TYPE_MIDI:
429                         return freebob_stream_type_midi;
430                 case IEC61883_STREAM_TYPE_SPDIF:
431                 default:
432                         return freebob_stream_type_unknown;
433                 }
434         } else {
435                 return freebob_stream_type_invalid;
436         }
437 }
438
439 freebob_streaming_stream_type freebob_streaming_get_playback_stream_type(freebob_device_t *dev, int i) {
440         freebob_stream_t *stream;
441         if(i<dev->nb_playback_streams) {
442                 stream=*(dev->playback_streams+i);
443                 switch (stream->spec.format) {
444                 case IEC61883_STREAM_TYPE_MBLA:
445                         return freebob_stream_type_audio;
446                 case IEC61883_STREAM_TYPE_MIDI:
447                         return freebob_stream_type_midi;
448                 case IEC61883_STREAM_TYPE_SPDIF:
449                 default:
450                         return freebob_stream_type_unknown;
451                 }
452         } else {
453                 return freebob_stream_type_invalid;
454         }
455 }
456
457 int freebob_streaming_set_stream_buffer(freebob_device_t *dev,  freebob_stream_t *dst, char *b, freebob_streaming_buffer_type t) {
458         assert(dst);
459        
460         // free the preallocated buffer first
461         freebob_streaming_free_stream_buffer(dev,dst);
462        
463         switch (t) {
464                 case freebob_buffer_type_per_stream:
465                         dst->user_buffer=calloc(dev->options.period_size,sizeof(freebob_sample_t));
466                         dst->buffer_type=freebob_buffer_type_per_stream;
467                         break;
468                
469                 case freebob_buffer_type_uint24:
470                         if(b) {
471                                 dst->buffer_type=t;
472                                 dst->user_buffer=b;
473                         } else {
474                                 // allocate a default type
475                                 dst->buffer_type=freebob_buffer_type_per_stream;
476                                 dst->user_buffer=calloc(dev->options.period_size,sizeof(freebob_sample_t));
477                                 return -1;
478                         }
479                         break;
480                        
481                 case freebob_buffer_type_float:
482                         if(b) {
483                                 dst->buffer_type=t;
484                                 dst->user_buffer=b;
485                         } else {
486                                 // allocate a default type
487                                 dst->buffer_type=freebob_buffer_type_per_stream;
488                                 dst->user_buffer=calloc(dev->options.period_size,sizeof(freebob_sample_t));
489                                 return -1;
490                         }
491                         break;
492                
493                 default:
494                         // allocate a default type
495                         dst->buffer_type=freebob_buffer_type_per_stream;
496                         dst->user_buffer=calloc(dev->options.period_size,sizeof(freebob_sample_t));
497                         return -1;
498                        
499         }
500         return 0;
501 }
502
503 void freebob_streaming_free_stream_buffer(freebob_device_t* dev, freebob_stream_t *dst)
504 {
505        
506         if((dst->buffer_type==freebob_buffer_type_per_stream) && (dst->user_buffer)) {
507                 free(dst->user_buffer);
508                 dst->user_buffer=NULL;
509         }
510 }
511
512
513 int freebob_streaming_set_capture_stream_buffer(freebob_device_t *dev, int i, char *buff,  freebob_streaming_buffer_type t) {
514        
515         freebob_stream_t *stream;
516         if(i<dev->nb_capture_streams) {
517                 stream=*(dev->capture_streams+i);
518                 assert(stream);
519                 return freebob_streaming_set_stream_buffer(dev,  stream, buff, t);
520                
521         } else {
522                 return -1;
523         }
524        
525 }
526
527 int freebob_streaming_set_playback_stream_buffer(freebob_device_t *dev, int i, char *buff,  freebob_streaming_buffer_type t) {
528         freebob_stream_t *stream;
529         if(i<dev->nb_playback_streams) {
530                
531                 stream=*(dev->playback_streams+i);
532                
533                 assert(stream);
534                 return freebob_streaming_set_stream_buffer(dev, stream, buff, t);
535                
536         } else {
537                 return -1;
538         }
539 }
540
541 int freebob_streaming_start_thread(freebob_device_t *dev) {
542         int err;
543         // start the packetizer thread
544         // init the packetizer thread communication semaphores
545         if((err=sem_init(&dev->packetizer.transfer_boundary, 0, 0))) {
546                 printError( "Cannot init packet transfer semaphore\n");
547                 return err;
548         } else {
549                 debugPrint(DEBUG_LEVEL_STARTUP,"FREEBOB: successfull init of packet transfer semaphore\n");
550         }
551        
552         dev->packetizer.priority=dev->options.packetizer_priority;
553         dev->packetizer.realtime=dev->options.realtime;
554        
555         // start watchdog
556         if (dev->packetizer.realtime) {
557                 freebob_streaming_start_watchdog(dev);
558         }
559        
560         // start packetizer thread
561         dev->packetizer.run=1;
562        
563         if (freebob_streaming_create_thread(dev, &dev->packetizer.transfer_thread, dev->packetizer.priority, dev->packetizer.realtime, freebob_iso_packet_iterator, (void *)dev)) {
564                 printError("cannot create packet transfer thread");
565                 return -1;
566         } else {
567                 debugPrint(DEBUG_LEVEL_STARTUP,"Created packet transfer thread\n");
568         }
569         return 0;
570 }
571
572 int freebob_streaming_stop_thread(freebob_device_t *dev) {
573         void *status;
574        
575         debugPrint(DEBUG_LEVEL_STARTUP," Stopping packetizer thread...\n");
576         dev->packetizer.run=0;
577        
578        
579         //sem_post(&dev->packetizer.transfer_ack);
580        
581         pthread_join(dev->packetizer.transfer_thread, &status);
582        
583         // stop watchdog
584         if (dev->packetizer.realtime) {
585                 freebob_streaming_stop_watchdog(dev);
586         }
587        
588         // cleanup semaphores
589         sem_destroy(&dev->packetizer.transfer_boundary);
590
591         return 0;
592 }
593
594
595 int freebob_streaming_start(freebob_device_t *dev) {
596         int err;
597         int i;
598        
599         for(i=0; i < dev->nb_connections; i++) {
600                 err=0;
601                 freebob_connection_t *connection= &(dev->connections[i]);
602
603                 int fdf, syt_interval;
604
605                 int samplerate=dev->options.sample_rate;
606
607                 switch (samplerate) {
608                 case 32000:
609                         syt_interval = 8;
610                         fdf = IEC61883_FDF_SFC_32KHZ;
611                         break;
612                 case 44100:
613                         syt_interval = 8;
614                         fdf = IEC61883_FDF_SFC_44K1HZ;
615                         break;
616                 default:
617                 case 48000:
618                         syt_interval = 8;
619                         fdf = IEC61883_FDF_SFC_48KHZ;
620                         break;
621                 case 88200:
622                         syt_interval = 16;
623                         fdf = IEC61883_FDF_SFC_88K2HZ;
624                         break;
625                 case 96000:
626                         syt_interval = 16;
627                         fdf = IEC61883_FDF_SFC_96KHZ;
628                         break;
629                 case 176400:
630                         syt_interval = 32;
631                         fdf = IEC61883_FDF_SFC_176K4HZ;
632                         break;
633                 case 192000:
634                         syt_interval = 32;
635                         fdf = IEC61883_FDF_SFC_192KHZ;
636                         break;
637                 }
638                
639                 if(dev->options.period_size < syt_interval) {
640                         printError("Period size (%d) too small! Samplerate %d requires period >= %d\n",
641                                    dev->options.period_size, samplerate, syt_interval);
642                         return -1;
643                 }
644                 connection->iso.packets_per_period = dev->options.period_size/syt_interval;
645
646                 //connection->plug=0;
647                 connection->iso.hostplug=-1;
648                
649                 // create the CCM PTP connection
650                 connection->iso.do_disconnect=0;
651
652                 // start receiving
653                 switch (connection->spec.direction) {
654                 case FREEBOB_CAPTURE:
655                
656                         debugPrint(DEBUG_LEVEL_STARTUP," creating capture connections...\n");
657                         if (connection->spec.iso_channel < 0) {
658                                 // we need to make the connection ourself
659                                 debugPrint(DEBUG_LEVEL_STARTUP, "Executing CMP procedure...\n");
660                                
661                                 connection->iso.iso_channel = iec61883_cmp_connect(
662                                         connection->raw_handle,
663                                         connection->spec.node | 0xffc0,
664                                         &connection->spec.plug,
665                                         raw1394_get_local_id (connection->raw_handle),
666                                         &connection->iso.hostplug,
667                                         &connection->iso.bandwidth);
668                                        
669                                 connection->iso.do_disconnect=1;
670                                
671                         } else {
672                                 connection->iso.iso_channel=connection->spec.iso_channel;
673                         }
674                        
675                         if (connection->spec.is_master) { //master connection
676                                 dev->sync_master_connection=connection;
677                                 connection->status.master=NULL;
678                                
679                         }
680
681                         // setup the optimal parameters for the raw1394 ISO buffering
682                         connection->iso.packets_per_period=dev->options.period_size/syt_interval;
683                         // hardware interrupts occur when one DMA block is full, and the size of one DMA
684                         // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq
685                         // occurs at a period boundary (optimal CPU use)
686                         // note: try and use 2 interrupts per period for better latency.
687                         connection->iso.max_packet_size=getpagesize() / connection->iso.packets_per_period * 2;
688                         connection->iso.irq_interval=connection->iso.packets_per_period/2;
689
690                         connection->iso.packet_size=4 * (2 + syt_interval * connection->spec.dimension);
691
692                         if (connection->iso.max_packet_size < connection->iso.packet_size) {
693                                 connection->iso.max_packet_size=connection->iso.packet_size;
694                         }
695
696                         /* the receive buffer size doesn't matter for the latency,
697                            but it has a minimal value in order for libraw to operate correctly (300) */
698                         connection->iso.buffers=400;
699
700                         // this is a hack
701                         if(dev->options.period_size < 128) {
702                                 connection->iso.receive_mode=RAW1394_DMA_PACKET_PER_BUFFER;
703                         } else {
704                                 connection->iso.receive_mode=RAW1394_DMA_BUFFERFILL;
705                         }
706
707                 break;
708                 case FREEBOB_PLAYBACK:
709                         debugPrint(DEBUG_LEVEL_STARTUP," creating playback connections...\n");
710                
711                         if (connection->spec.iso_channel < 0) { // we need to make the connection ourself
712                                 debugPrint(DEBUG_LEVEL_STARTUP, "Executing CMP procedure...\n");
713                                 connection->iso.iso_channel = iec61883_cmp_connect(
714                                 connection->raw_handle,
715                                 raw1394_get_local_id (connection->raw_handle),
716                                 &connection->iso.hostplug,
717                                 connection->spec.node | 0xffc0,
718                                 &connection->spec.plug,
719                                 &connection->iso.bandwidth);
720                                
721                                 connection->iso.do_disconnect=1;
722                         } else {
723                                 connection->iso.iso_channel=connection->spec.iso_channel;
724                         }
725
726                         if (connection->spec.is_master) { // master connection
727                                 dev->sync_master_connection=connection;
728                                 connection->status.master=NULL;
729                         }
730
731                         iec61883_cip_init (
732                                 &connection->status.cip,
733                                 IEC61883_FMT_AMDTP,
734                                 fdf,
735                                 samplerate,
736                                 connection->spec.dimension,
737                                 syt_interval);
738                                
739                         iec61883_cip_set_transmission_mode (
740                                 &connection->status.cip,
741                                 IEC61883_MODE_BLOCKING_EMPTY);
742
743
744                         // setup the optimal parameters for the raw1394 ISO buffering
745                         connection->iso.packets_per_period=dev->options.period_size/syt_interval;
746                         // hardware interrupts occur when one DMA block is full, and the size of one DMA
747                         // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq is
748                         // occurs at a period boundary (optimal CPU use)
749                         // note: try and use 2 interrupts per period for better latency.
750                         connection->iso.max_packet_size=getpagesize() / connection->iso.packets_per_period * 2;
751                         connection->iso.irq_interval=connection->iso.packets_per_period / 2;
752
753                         connection->iso.packet_size=4 * (2 + syt_interval * connection->spec.dimension);
754
755                         if (connection->iso.max_packet_size < connection->iso.packet_size) {
756                                 connection->iso.max_packet_size=connection->iso.packet_size;
757                         }
758
759                         /* the transmit buffer size should be as low as possible for latency.
760                         */
761                         connection->iso.buffers=connection->iso.packets_per_period;
762                         if (connection->iso.buffers<10) connection->iso.buffers=10;
763
764                 break;
765                 }
766                
767                 // reset the connection, such that the buffers are empty
768                 freebob_streaming_reset_connection(dev, connection);
769
770                 if(connection->iso.iso_channel<0) {
771                         printError("Could not do CMP for connection %d\n",i);
772                         i-=1;
773                         while(i>=0) {
774                                 connection= &(dev->connections[i]);
775                
776                                 if (connection->iso.do_disconnect) {
777                                         // destroy the CCM PTP connection
778                                         switch (connection->spec.direction) {
779                                         case FREEBOB_CAPTURE:
780                                                 iec61883_cmp_disconnect(
781                                                         connection->raw_handle,
782                                                         connection->spec.node | 0xffc0,
783                                                         connection->spec.plug,
784                                                         raw1394_get_local_id (connection->raw_handle),
785                                                         connection->iso.hostplug,
786                                                         connection->iso.iso_channel,
787                                                         connection->iso.bandwidth);
788                                                
789                                         break;
790                                         case FREEBOB_PLAYBACK:
791                                                 iec61883_cmp_disconnect(
792                                                         connection->raw_handle,
793                                                         raw1394_get_local_id (connection->raw_handle),
794                                                         connection->iso.hostplug,
795                                                         connection->spec.node | 0xffc0,
796                                                         connection->spec.plug,
797                                                         connection->iso.iso_channel,
798                                                         connection->iso.bandwidth);
799                        
800                                         break;
801                                         }
802                                 }
803                                 i--;
804                         }
805                         return -1;
806                 }
807         }
808        
809         /* update the sync master pointer for all connections */
810         debugPrint(DEBUG_LEVEL_STARTUP,"Connection summary:\n");
811         int sync_masters_present=0;
812        
813         for(i=0; i < dev->nb_connections; i++) {
814                 err=0;
815                
816                 freebob_connection_t *connection= &(dev->connections[i]);
817                
818                 if (connection->spec.direction == FREEBOB_CAPTURE) {
819                         debugPrint(DEBUG_LEVEL_STARTUP,"  Capture : from node %02X.%02d to node %02X.%02d on channel %02d  {%p} ",
820                                 connection->spec.node & ~0xffc0, connection->spec.plug,
821                                 raw1394_get_local_id (connection->raw_handle) & ~0xffc0, connection->iso.hostplug,
822                                 connection->iso.iso_channel, connection);
823                 } else if (connection->spec.direction == FREEBOB_PLAYBACK) {
824                        
825                         debugPrint(DEBUG_LEVEL_STARTUP,"  Playback: from node %02X.%02d to node %02X.%02d on channel %02d  {%p} ",
826                                 raw1394_get_local_id (connection->raw_handle) & ~0xffc0, connection->iso.hostplug,
827                                 connection->spec.node & ~0xffc0, connection->spec.plug,
828                                 connection->iso.iso_channel, connection);
829                 }
830                
831                 if (connection->spec.is_master) {
832                         sync_masters_present++;
833                        
834                         debugPrintShort(DEBUG_LEVEL_STARTUP," [MASTER]");       
835                 } else {
836                         assert(dev->sync_master_connection);
837                         connection->status.master=&dev->sync_master_connection->status;
838                        
839                         debugPrintShort(DEBUG_LEVEL_STARTUP," [SLAVE]");
840                 }
841                 debugPrintShort(DEBUG_LEVEL_STARTUP,"\n");
842         }
843        
844         if (sync_masters_present == 0) {
845                 printError("no sync master connection present!\n");
846                 // TODO: cleanup
847                 //freebob_streaming_stop(driver);
848                 return -1;
849         } else if (sync_masters_present > 1) {
850                 printError("too many sync master connections present! (%d)\n",sync_masters_present);
851                 // TODO: cleanup
852                 //freebob_streaming_stop(driver);
853                 return -1;
854         }
855        
856         // reset the playback streams
857         if((err=freebob_streaming_reset_playback_streams(dev))<0) {
858                 // TODO: cleanup
859                 printError("Could not reset playback streams.\n");
860                 return err;
861         }
862
863         // put nb_periods*period_size of null frames into the playback buffers
864         if((err=freebob_streaming_prefill_playback_streams(dev))<0) {
865                 // TODO: cleanup
866                 printError("Could not prefill playback streams.\n");
867                 return err;
868         }
869                
870         // we should transfer nb_buffers-1 periods of playback from the stream buffers to the event buffer
871         for (i=0;i<dev->options.nb_buffers;i++) {
872                 freebob_streaming_transfer_playback_buffers(dev);
873         }
874
875         freebob_streaming_print_bufferfill(dev);
876                
877         debugPrint(DEBUG_LEVEL_STARTUP,"Armed...\n");
878        
879         freebob_streaming_start_thread(dev);
880
881         return 0;
882
883 }
884
885 int freebob_streaming_stop(freebob_device_t *dev) {
886         unsigned int i;
887        
888
889         freebob_streaming_stop_thread(dev);
890        
891         // stop ISO xmit/receive
892         for(i=0; i < dev->nb_connections; i++) {
893                 freebob_connection_t *connection= &(dev->connections[i]);
894
895                 if (connection->iso.do_disconnect) {
896                         // destroy the CCM PTP connection
897                         switch (connection->spec.direction) {
898                         case FREEBOB_CAPTURE:
899                                 iec61883_cmp_disconnect(
900                                         connection->raw_handle,
901                                         connection->spec.node | 0xffc0,
902                                         connection->spec.plug,
903                                         raw1394_get_local_id (connection->raw_handle),
904                                         connection->iso.hostplug,
905                                         connection->iso.iso_channel,
906                                         connection->iso.bandwidth);
907                                
908                         break;
909                         case FREEBOB_PLAYBACK:
910                                 iec61883_cmp_disconnect(
911                                         connection->raw_handle,
912                                         raw1394_get_local_id (connection->raw_handle),
913                                         connection->iso.hostplug,
914                                         connection->spec.node | 0xffc0,
915                                         connection->spec.plug,
916                                         connection->iso.iso_channel,
917                                         connection->iso.bandwidth);
918        
919                         break;
920                         }
921                 }
922                
923         }
924         return 0;
925 }
926
927 void freebob_streaming_print_bufferfill(freebob_device_t *dev) {
928 #ifdef DEBUG   
929     int i=0;
930         for(i=0; i < dev->nb_connections; i++) {
931                 freebob_connection_t *connection= &(dev->connections[i]);
932                 debugPrint(DEBUG_LEVEL_XRUN_RECOVERY, "%i: %d\n",i,freebob_ringbuffer_read_space(connection->event_buffer));
933         }
934 #endif
935 }
936
937 int freebob_streaming_prefill_playback_streams(freebob_device_t *dev) {
938         int i;
939         int err=0;
940        
941         for(i=0; i < dev->nb_playback_streams; i++) {
942                 freebob_stream_t *stream;
943
944                
945                 stream=*(dev->playback_streams+i);
946                
947                 assert(stream);
948                 err=freebob_streaming_prefill_stream(dev, stream);
949                 if (err) {
950                         printError("Could not prefill stream %d\n",i);
951                         return -1;
952                 }
953         }
954         return 0;
955        
956 }
957
958 int freebob_streaming_reset_playback_streams(freebob_device_t *dev) {
959         int i;
960         int err=0;
961        
962         for(i=0; i < dev->nb_playback_streams; i++) {
963                 freebob_stream_t *stream;
964
965                 stream=*(dev->playback_streams+i);
966                
967                 assert(stream);
968                 err=freebob_streaming_reset_stream(dev, stream);
969                 if (err) {
970                         printError("Could not reset stream %d\n",i);
971                         return -1;
972                 }
973         }
974         return 0;
975        
976 }
977
978 int freebob_streaming_reset(freebob_device_t *dev) {
979         /*
980          * Reset means:
981          * 1) Stopping the packetizer thread
982          * 2) Bringing all buffers & connections into a know state
983          *    - Clear all capture buffers
984          *    - Put nb_periods*period_size of null frames into the playback buffers
985          * 3) Restarting the packetizer thread
986          */
987
988         unsigned long i;
989         int err;
990         assert(dev);
991
992         debugPrint(DEBUG_LEVEL_XRUN_RECOVERY, "Resetting streams...\n");
993        
994         if((err=freebob_streaming_stop_thread(dev))<0) {
995                 printError("Could not stop packetizer thread.\n");
996                 return err;
997         }
998
999         //freebob_streaming_stop_iso(dev);
1000
1001         // check if the packetizer is stopped
1002         assert(!dev->packetizer.run);
1003        
1004         // reset all connections
1005         for(i=0; i < dev->nb_connections; i++) {
1006                 freebob_connection_t *connection= &(dev->connections[i]);
1007                 freebob_streaming_reset_connection(dev,connection);
1008         }
1009        
1010         // put nb_periods*period_size of null frames into the playback buffers
1011         if((err=freebob_streaming_prefill_playback_streams(dev))<0) {
1012                 printError("Could not prefill playback streams.\n");
1013                 return err;
1014         }
1015        
1016         // we should transfer nb_buffers-1 periods of playback from the stream buffers to the event buffer
1017         for (i=0;i<dev->options.nb_buffers;i++) {
1018                 freebob_streaming_transfer_playback_buffers(dev);
1019         }
1020                        
1021         // clear the xrun flag
1022         dev->xrun_detected=FALSE;
1023        
1024         //freebob_streaming_start_iso(dev);
1025         freebob_streaming_print_bufferfill(dev);
1026        
1027         if((err=freebob_streaming_start_thread(dev))<0) {
1028                 printError("Could not start packetizer thread.\n");
1029                 return err;
1030         }
1031        
1032        
1033         return 0;
1034 }
1035
1036 int freebob_streaming_xrun_recovery(freebob_device_t *dev) {
1037         freebob_streaming_reset(dev);
1038         dev->xrun_count++;
1039        
1040         return 0;
1041 }
1042
1043 int freebob_streaming_wait(freebob_device_t *dev) {
1044         int ret;
1045
1046         // Wait for packetizer thread to signal a period completion
1047         sem_wait(&dev->packetizer.transfer_boundary);
1048        
1049         // acknowledge the reception of the period
1050         //sem_post(&dev->packetizer.transfer_ack);
1051        
1052         if(dev->xrun_detected) {
1053                 // notify the driver of the underrun and the delay
1054                 ret = (-1) * freebob_streaming_xrun_recovery(dev);
1055         } else {
1056                 ret=dev->options.period_size;
1057         }
1058        
1059         return ret;
1060 }
1061
1062 int freebob_streaming_transfer_capture_buffers(freebob_device_t *dev) {
1063         int i;
1064         int xrun;
1065         unsigned int offset=0;
1066        
1067         freebob_ringbuffer_data_t vec[2];
1068         // transfer the received events into the stream buffers
1069         for (i=0;i<dev->nb_connections_capture;i++) {
1070                 freebob_connection_t *connection= &(dev->connections[i]); // capture connections are first in the array
1071                 assert(connection);
1072                
1073                 debugPrint(DEBUG_LEVEL_WAIT, "R: > %d\n",freebob_ringbuffer_read_space(connection->event_buffer));
1074                        
1075                         // we received one period of frames on each connection
1076                         // this is period_size*dimension of events
1077
1078                 int events2read=dev->options.period_size*connection->spec.dimension;
1079                 int bytes2read=events2read*sizeof(quadlet_t);
1080                        
1081                         // TODO: implement dbc for midi
1082                 int dbc=0;
1083                        
1084                         /*      read events2read bytes from the ringbuffer
1085                 *  first see if it can be done in one read.
1086                 *  if so, ok.
1087                 *  otherwise read up to a multiple of clusters directly from the buffer
1088                 *  then do the buffer wrap around using ringbuffer_read
1089                 *  then read the remaining data directly from the buffer in a third pass
1090                 *  Make sure that we cannot end up on a non-cluster aligned position!
1091                         */
1092                 int cluster_size=connection->spec.dimension*sizeof(quadlet_t);
1093 //              unsigned int frames2read=events2read/connection->spec.dimension;
1094                        
1095                 while(bytes2read>0) {
1096                         unsigned int framesread=(dev->options.period_size*cluster_size-bytes2read)/cluster_size;
1097                         offset=framesread;
1098 //                      offset=0;
1099                        
1100                         int bytesread=0;
1101                                                
1102                         freebob_ringbuffer_get_read_vector(connection->event_buffer, vec);
1103                                
1104                         if(vec[0].len==0) { // this indicates an empty event buffer
1105                                 printError("Event buffer underrun on capture connection %d\n",i);
1106                                 break;
1107                         }
1108                                
1109                                 /* if we don't take care we will get stuck in an infinite loop
1110                         * because we align to a cluster boundary later
1111                         * the remaining nb of bytes in one read operation can be smaller than one cluster
1112                         * this can happen because the ringbuffer size is always a power of 2
1113                                 */
1114                         if(vec[0].len<cluster_size) {
1115                                         // use the ringbuffer function to read one cluster (handles wrap around)
1116                                 freebob_ringbuffer_read(connection->event_buffer,connection->cluster_buffer,cluster_size);
1117                                        
1118                                 // decode the temporary buffer
1119                                 debugPrint(DEBUG_LEVEL_WAIT, "R: %5d [%5d %5d] %5d %5d\n",bytes2read,vec[0].len,vec[1].len,1, offset);
1120                                        
1121                                 xrun = freebob_am824_recv(connection->cluster_buffer, 1, offset, dbc, connection);
1122                                        
1123                                 if(xrun<0) {
1124                                                 // xrun detected
1125                                         printError("Frame buffer overrun on capture connection %d\n",i);
1126                                         break;
1127                                 }
1128                                        
1129                                         // we advanced one cluster_size
1130                                 bytes2read-=cluster_size;
1131                                        
1132                         } else { //
1133                                
1134                                 if(bytes2read>vec[0].len) {
1135                                                 // align to a cluster boundary
1136                                         bytesread=vec[0].len-(vec[0].len%cluster_size);
1137                                 } else {
1138                                         bytesread=bytes2read;
1139                                 }
1140                                        
1141                                 debugPrint(DEBUG_LEVEL_WAIT, "R: %5d [%5d %5d] %5d %5d\n",bytes2read,vec[0].len,vec[1].len,bytesread, offset);
1142                                        
1143                                 xrun = freebob_am824_recv(vec[0].buf, bytesread/sizeof(quadlet_t)/connection->spec.dimension, offset, dbc, connection);
1144                                        
1145                                 if(xrun<0) {
1146                                                 // xrun detected
1147                                         printError("Frame buffer overrun on capture connection %d\n",i);
1148                                         break;
1149                                 }
1150        
1151                                 freebob_ringbuffer_read_advance(connection->event_buffer, bytesread);
1152                                 bytes2read -= bytesread;
1153                         }
1154                                
1155                                 // the bytes2read should always be cluster aligned
1156                         assert(bytes2read%cluster_size==0);
1157                         debugPrint(DEBUG_LEVEL_WAIT, "R: < %d\n",freebob_ringbuffer_read_space(connection->event_buffer));
1158                                
1159                 }
1160
1161         }
1162         return 0;
1163 }
1164
1165 int freebob_streaming_transfer_playback_buffers(freebob_device_t *dev) {
1166         int i;
1167         int xrun;
1168         unsigned int offset=0;
1169        
1170         freebob_ringbuffer_data_t vec[2];
1171         // transfer the output stream buffers content to the event buffers
1172         for (i=dev->nb_connections_capture;i<dev->nb_connections_capture+dev->nb_connections_playback;i++) {
1173                 freebob_connection_t *connection= &(dev->connections[i]);
1174                 assert(connection);
1175                 debugPrint(DEBUG_LEVEL_WAIT, "W: < %d\n",freebob_ringbuffer_write_space(connection->event_buffer));
1176                        
1177                         // we received one period of frames on each connection
1178                         // this is period_size*dimension of events
1179
1180                 int events2write=dev->options.period_size*connection->spec.dimension;
1181                 int bytes2write=events2write*sizeof(quadlet_t);
1182                        
1183                         // TODO: implement dbc for midi
1184                 int dbc=0;
1185                        
1186                 /*      write events2write bytes to the ringbuffer
1187                 *  first see if it can be done in one read.
1188                 *  if so, ok.
1189                 *  otherwise write up to a multiple of clusters directly to the buffer
1190                 *  then do the buffer wrap around using ringbuffer_write
1191                 *  then write the remaining data directly to the buffer in a third pass
1192                 *  Make sure that we cannot end up on a non-cluster aligned position!
1193                 */
1194                 int cluster_size=connection->spec.dimension*sizeof(quadlet_t);
1195 //              unsigned int frames2write=events2write/connection->spec.dimension;
1196                        
1197                 while(bytes2write>0) {
1198                         int byteswritten=0;
1199                        
1200                         unsigned int frameswritten=(dev->options.period_size*cluster_size-bytes2write)/cluster_size;
1201                         offset=frameswritten;
1202 //                      offset=0;
1203                        
1204                         freebob_ringbuffer_get_write_vector(connection->event_buffer, vec);
1205                                
1206                         if(vec[0].len==0) { // this indicates a full event buffer
1207                                 printError("Event buffer overrun on playback connection %d\n",i);
1208                                 break;
1209                         }
1210                                
1211                         /* if we don't take care we will get stuck in an infinite loop
1212                         * because we align to a cluster boundary later
1213                         * the remaining nb of bytes in one write operation can be smaller than one cluster
1214                         * this can happen because the ringbuffer size is always a power of 2
1215                         */
1216                         if(vec[0].len<cluster_size) {
1217                                
1218                                 // encode to the temporary buffer
1219                                 debugPrint(DEBUG_LEVEL_WAIT, "W: %d [%d %d] %d\n",bytes2write,vec[0].len,vec[1].len,1);
1220                                        
1221                                 xrun = freebob_am824_xmit(connection->cluster_buffer, 1, offset, dbc, connection);
1222                                
1223                                 if(xrun<0) {
1224                                                 // xrun detected
1225                                         printError("Frame buffer underrun on playback connection %d\n",i);
1226                                         break;
1227                                 }
1228                                        
1229                                 // use the ringbuffer function to write one cluster (handles wrap around)
1230                                 freebob_ringbuffer_write(connection->event_buffer,connection->cluster_buffer,cluster_size);
1231                                        
1232                                 // we advanced one cluster_size
1233                                 bytes2write-=cluster_size;
1234                                        
1235                         } else { //
1236                                
1237                                 if(bytes2write>vec[0].len) {
1238                                         // align to a cluster boundary
1239                                         byteswritten=vec[0].len-(vec[0].len%cluster_size);
1240                                 } else {
1241                                         byteswritten=bytes2write;
1242                                 }
1243                                        
1244                                 debugPrint(DEBUG_LEVEL_WAIT, "W: %d [%d %d] %d\n",bytes2write,vec[0].len,vec[1].len,byteswritten);
1245                                        
1246                                 xrun = freebob_am824_xmit(vec[0].buf, byteswritten/sizeof(quadlet_t)/connection->spec.dimension, offset, dbc, connection);
1247                                        
1248                                 if(xrun<0) {
1249                                                 // xrun detected
1250                                         printError("Frame buffer underrun on playback connection %d\n",i);
1251                                         break;
1252                                 }
1253        
1254                                 freebob_ringbuffer_write_advance(connection->event_buffer, byteswritten);
1255                                 bytes2write -= byteswritten;
1256                         }
1257                                
1258                         // the bytes2write should always be cluster aligned
1259                         assert(bytes2write%cluster_size==0);
1260                                
1261                 }
1262
1263                 debugPrint(DEBUG_LEVEL_WAIT, "W: > %d\n",freebob_ringbuffer_write_space(connection->event_buffer));
1264         }
1265        
1266        
1267         return 0;
1268 }
1269
1270 int freebob_streaming_transfer_buffers(freebob_device_t *dev) {
1271         int err=0;
1272        
1273         err=freebob_streaming_transfer_capture_buffers(dev);
1274         if (err) return err;
1275        
1276         err=freebob_streaming_transfer_playback_buffers(dev);
1277         return err;
1278        
1279 }
1280
1281
1282 int freebob_streaming_write(freebob_device_t *dev, int i, freebob_sample_t *buffer, int nsamples) {
1283         int retval;
1284        
1285         freebob_stream_t *stream;
1286         assert(i<dev->nb_playback_streams);
1287        
1288         stream=*(dev->playback_streams+i);
1289         assert(stream);
1290        
1291         retval=freebob_ringbuffer_write(stream->buffer,(char *)buffer,nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t);
1292                
1293         return retval;
1294 }
1295
1296 int freebob_streaming_read(freebob_device_t *dev, int i, freebob_sample_t *buffer, int nsamples) {
1297         // this has one ringbuffer too many, but that will be solved shortly
1298         int retval=0;
1299
1300         freebob_stream_t *stream;
1301         assert(i<dev->nb_capture_streams);
1302        
1303         stream=*(dev->capture_streams+i);
1304         assert(stream);
1305        
1306         // now read from the stream ringbuffer
1307         retval=freebob_ringbuffer_read(stream->buffer, (char *)buffer, nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t);     
1308
1309 //      fprintf(stderr,"rb read1 [%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, retval);
1310        
1311         return retval;
1312 }
1313
1314 pthread_t freebob_streaming_get_packetizer_thread(freebob_device_t *dev) {
1315         return dev->packetizer.transfer_thread;
1316 }
1317
1318 /* --------------------- *
1319  * PRIVATE STUFF         *
1320  * --------------------- */
1321  
1322  
1323 unsigned int freebob_streaming_register_generic_stream(freebob_stream_t *stream, freebob_stream_t ***oldset, unsigned int set_size) {
1324         int i;
1325         int found=0;
1326         unsigned int new_set_size;
1327        
1328         freebob_stream_t **new_streams=calloc(set_size+1,sizeof(freebob_stream_t *));
1329         freebob_stream_t **set=*oldset;
1330        
1331         for (i=0;i<set_size;i++) {
1332                 *(new_streams+i)=*(set+i);
1333                 if(*(set+i)==stream) {
1334                         printError("stream already registered\n");
1335                         found=1;
1336                 }
1337         }
1338         if (!found) {
1339                 *(new_streams+set_size)=stream;
1340                 new_set_size=set_size+1;
1341                
1342                 free(*oldset);
1343                 *oldset=new_streams;
1344         } else {
1345                 free(new_streams);
1346                 new_set_size=set_size;
1347         }
1348         return new_set_size;
1349        
1350 }
1351
1352 void freebob_streaming_register_capture_stream(freebob_device_t *dev, freebob_stream_t *stream) {
1353         dev->nb_capture_streams=
1354                 freebob_streaming_register_generic_stream(
1355                         stream,
1356                         &dev->capture_streams,
1357                         dev->nb_capture_streams);
1358         if (stream->spec.format==IEC61883_STREAM_TYPE_MBLA) {
1359                 dev->nb_synced_capture_streams=
1360                         freebob_streaming_register_generic_stream(
1361                                 stream,
1362                                 &dev->synced_capture_streams,
1363                                 dev->nb_synced_capture_streams);
1364         }
1365 }
1366
1367 void freebob_streaming_register_playback_stream(freebob_device_t *dev, freebob_stream_t *stream) {
1368         dev->nb_playback_streams=
1369                 freebob_streaming_register_generic_stream(
1370                         stream,
1371                         &dev->playback_streams,
1372                         dev->nb_playback_streams);
1373         if (stream->spec.format==IEC61883_STREAM_TYPE_MBLA) {
1374                 dev->nb_synced_playback_streams=
1375                         freebob_streaming_register_generic_stream(
1376                                 stream,
1377                                 &dev->synced_playback_streams,
1378                                 dev->nb_synced_playback_streams);
1379         }
1380 }
1381
1382 static inline int
1383 freebob_streaming_period_complete (freebob_device_t *dev) {
1384         unsigned long i;
1385         //unsigned int period_boundary_bytes=dev->options.period_size*sizeof(freebob_sample_t);
1386        
1387         assert(dev);
1388        
1389         for(i=0; i < dev->nb_connections; i++) {
1390                 freebob_connection_t *connection= &(dev->connections[i]);
1391                 if (connection->status.frames_left > 0) {
1392                         return FALSE;
1393                 }
1394         }
1395         return TRUE;
1396        
1397 #if 0   
1398         for(i=0; i < dev->nb_synced_capture_streams; i++) {
1399                 assert(dev->synced_capture_streams);
1400                 assert(dev->synced_capture_streams[i]);
1401                
1402                 /* We check if there is more than one period of samples in the buffer.
1403                  * if not the period isn't complete yet.
1404                  */
1405                 if (freebob_ringbuffer_read_space(dev->synced_capture_streams[i]->buffer) < period_boundary_bytes) {
1406                         return FALSE;
1407                 }
1408         }
1409        
1410         for(i=0; i < dev->nb_synced_playback_streams; i++) {
1411                 assert(dev->synced_playback_streams);
1412                 assert(dev->synced_playback_streams[i]);
1413                 //FIXME: check this!
1414                 /* We check if there is still one period of samples in the output buffer.
1415                  * if so, the period isn't complete yet.
1416                  */
1417                 if (freebob_ringbuffer_read_space(dev->synced_playback_streams[i]->buffer) > period_boundary_bytes) {
1418                         return FALSE;
1419                 }
1420         }
1421         return TRUE;
1422 #endif
1423 }
1424
1425 static inline void
1426 freebob_streaming_period_reset (freebob_device_t *dev) {
1427 //      unsigned long i;
1428         //unsigned int period_boundary_bytes=dev->options.period_size*sizeof(freebob_sample_t);
1429         unsigned long i;
1430         //unsigned int period_boundary_bytes=dev->options.period_size*sizeof(freebob_sample_t);
1431         printEnter();
1432         assert(dev);
1433        
1434         for(i=0; i < dev->nb_connections; i++) {
1435                 freebob_connection_t *connection= &(dev->connections[i]);
1436                 connection->status.frames_left+=dev->options.period_size;
1437                 // enable poll
1438                 connection->pfd->events=POLLIN;
1439         }
1440         printExit();
1441         return;
1442 }
1443
1444 static inline int
1445 freebob_streaming_xrun_detected_on_connection (freebob_device_t *dev, freebob_connection_t *connection) {
1446         assert((connection));
1447         if (connection->status.xruns>0) {
1448                 return TRUE;
1449         }
1450         return FALSE;
1451 }
1452
1453 static inline int
1454 freebob_streaming_xrun_detected (freebob_device_t *dev, freebob_connection_t **connections, int nb_connections) {
1455         int i;
1456        
1457         for(i=0; i < nb_connections; i++) {
1458                 assert((connections[i]));
1459
1460                 if (freebob_streaming_xrun_detected_on_connection (dev, connections[i])) {
1461                         return TRUE;
1462                 }
1463         }
1464         return FALSE;
1465 }
1466
1467 int freebob_streaming_start_iso_connection(freebob_device_t *dev, freebob_connection_t *connection) {
1468         int err;
1469
1470         err=0;
1471         if (connection->spec.direction == FREEBOB_CAPTURE) {
1472                 connection->status.packets=0;   
1473                 connection->status.dropped=0;           
1474                 if (connection->spec.is_master) { //master connection
1475
1476                         debugPrint(DEBUG_LEVEL_STARTUP,
1477                                 "Init ISO master receive handler on channel %d...\n",
1478                                 connection->iso.iso_channel);
1479
1480                         debugPrint(DEBUG_LEVEL_STARTUP,
1481                                 "   (%s, BUFFERS=%d, PACKET_SIZE=%d, PACKET_MAX=%d, IRQ=%d, %d PKT/PERIOD)...\n",
1482                                 (connection->iso.receive_mode==RAW1394_DMA_PACKET_PER_BUFFER ? "PACKET_PER_BUFFER" : "BUFFERFILL"),
1483                                 connection->iso.buffers,
1484                                 connection->iso.packet_size,
1485                                 connection->iso.max_packet_size,
1486                                 connection->iso.irq_interval,
1487                                 connection->iso.packets_per_period);
1488
1489                         raw1394_iso_recv_init(
1490                                         connection->raw_handle,
1491                                         iso_master_receive_handler,
1492                                         connection->iso.buffers,
1493                                         connection->iso.max_packet_size,
1494                                         connection->iso.iso_channel,
1495                                         connection->iso.receive_mode, // RAW1394_DMA_BUFFERFILL,
1496                                         connection->iso.irq_interval);
1497
1498                 } else {
1499                         //slave receive connection
1500                         debugPrint(DEBUG_LEVEL_STARTUP,
1501                                 "Init ISO slave receive handler on channel %d...\n",
1502                                 connection->iso.iso_channel);
1503
1504                         debugPrint(DEBUG_LEVEL_STARTUP,
1505                                 "   (%s, BUFFERS=%d, PACKET_SIZE=%d, PACKET_MAX=%d, IRQ=%d, %d PKT/PERIOD)...\n",
1506                                 (connection->iso.receive_mode==RAW1394_DMA_PACKET_PER_BUFFER ? "PACKET_PER_BUFFER" : "BUFFERFILL"),                             connection->iso.buffers,
1507                                 connection->iso.packet_size,
1508                                 connection->iso.max_packet_size,
1509                                 connection->iso.irq_interval,
1510                                 connection->iso.packets_per_period);
1511
1512                         raw1394_iso_recv_init( 
1513                                         connection->raw_handle,
1514                                         iso_slave_receive_handler,
1515                                         connection->iso.buffers,
1516                                         connection->iso.max_packet_size,
1517                                         connection->iso.iso_channel,
1518                                         connection->iso.receive_mode, // RAW1394_DMA_BUFFERFILL,
1519                                         connection->iso.irq_interval);
1520                 }
1521                
1522                 debugPrint(DEBUG_LEVEL_STARTUP,
1523                         "Start ISO receive for connection on channel %d at cycle %d...\n",
1524                           connection->iso.iso_channel, connection->iso.startcycle);
1525                        
1526                 err = raw1394_iso_recv_start(
1527                                 connection->raw_handle,
1528                 connection->iso.startcycle,
1529                 -1,//IEC61883_TAG_WITH_CIP,
1530                 0);
1531
1532                 if (err) {
1533                         printError("couldn't start receiving: %s\n",
1534                                            strerror (errno));
1535                                 // TODO: cleanup
1536                         return err;
1537                 }                                       
1538                
1539         } else if (connection->spec.direction == FREEBOB_PLAYBACK) {
1540                
1541                 if (connection->spec.is_master) { // master connection
1542                         debugPrint(DEBUG_LEVEL_STARTUP,
1543                                 "Init ISO master transmit handler on channel %d...\n",
1544                                 connection->iso.iso_channel);
1545
1546                         debugPrint(DEBUG_LEVEL_STARTUP,
1547                                 "   (BUFFERS=%d, PACKET_SIZE=%d, PACKET_MAX=%d, IRQ=%d, %d PKT/PERIOD)...\n",
1548                                 connection->iso.buffers,
1549                                 connection->iso.packet_size,
1550                                 connection->iso.max_packet_size,
1551                                 connection->iso.irq_interval,
1552                                 connection->iso.packets_per_period);
1553
1554                                
1555                         raw1394_iso_xmit_init(
1556                                         connection->raw_handle,
1557                                         iso_master_transmit_handler,
1558                                         connection->iso.buffers,
1559                                         connection->iso.max_packet_size,
1560                                         connection->iso.iso_channel,
1561                                         RAW1394_ISO_SPEED_400,
1562                                         connection->iso.irq_interval);                 
1563                 } else {
1564                        
1565                         debugPrint(DEBUG_LEVEL_STARTUP,
1566                                 "Init ISO slave transmit handler on channel %d...\n",
1567                                 connection->iso.iso_channel);
1568
1569                         debugPrint(DEBUG_LEVEL_STARTUP,
1570                                 "   (BUFFERS=%d, PACKET_SIZE=%d, PACKET_MAX=%d, IRQ=%d, %d PKT/PERIOD)...\n",
1571                                 connection->iso.buffers,
1572                                 connection->iso.packet_size,
1573                                 connection->iso.max_packet_size,
1574                                 connection->iso.irq_interval,
1575                                 connection->iso.packets_per_period);
1576
1577                         raw1394_iso_xmit_init(
1578                                         connection->raw_handle,
1579                                         iso_slave_transmit_handler,
1580                                         connection->iso.buffers,
1581                                         connection->iso.max_packet_size,
1582                                         connection->iso.iso_channel,
1583                                         RAW1394_ISO_SPEED_400,
1584                                         connection->iso.irq_interval); 
1585
1586                 }
1587        
1588                 debugPrint(DEBUG_LEVEL_STARTUP,
1589                         "Start ISO transmit for connection on channel %d at cycle %d\n",
1590                         connection->iso.iso_channel, connection->iso.startcycle);
1591                        
1592                 err=raw1394_iso_xmit_start(
1593                         connection->raw_handle,
1594                         connection->iso.startcycle,
1595                         connection->iso.prebuffers);
1596
1597                 if (err) {
1598                         printError("couldn't start transmitting: %s\n",
1599                                            strerror (errno));
1600                                 // TODO: cleanup
1601                         return err;
1602                 }
1603         }
1604         return 0;
1605 }
1606
1607 int freebob_streaming_stop_iso_connection(freebob_device_t *dev, freebob_connection_t *connection) {
1608        
1609         debugPrintWithTimeStamp(DEBUG_LEVEL_STARTUP, "Stop connection on channel %d ...\n", connection->iso.iso_channel);
1610         if (connection->spec.direction == FREEBOB_CAPTURE) {
1611                 raw1394_iso_recv_flush(connection->raw_handle);
1612         } else {
1613                 raw1394_iso_xmit_sync(connection->raw_handle);
1614         }
1615                
1616         raw1394_iso_stop(connection->raw_handle);
1617        
1618         debugPrint(DEBUG_LEVEL_STARTUP, "Shutdown connection on channel %d ...\n", connection->iso.iso_channel);
1619                
1620         raw1394_iso_shutdown(connection->raw_handle);
1621        
1622         return 0;
1623 }
1624
1625 int freebob_streaming_wait_for_sync_stream(freebob_device_t *dev, freebob_connection_t *connection) {
1626         int err;
1627        
1628         debugPrint(DEBUG_LEVEL_STARTUP, "Waiting for the sync stream...\n");
1629        
1630         // start the sync master connection
1631        
1632         connection->iso.startcycle=-1; // don't care when we start this
1633         connection->status.events=0;
1634        
1635         freebob_streaming_start_iso_connection(dev,connection);
1636        
1637         // wait until something is received/sent on the connection
1638         while(connection->status.events==0) {
1639                 err=0;
1640                        
1641                 // get a packet on the sync master connection
1642                 err=raw1394_loop_iterate(connection->raw_handle);
1643                        
1644                 if (err == -1) {
1645                         printError("Possible raw1394 error: %s on sync master connection: %d\n",
1646                                            strerror (errno),connection->spec.id);
1647                 }
1648         }
1649        
1650         freebob_streaming_stop_iso_connection(dev,connection);
1651        
1652         // reset the connection
1653         freebob_streaming_reset_connection(dev, connection);
1654        
1655         // FIXME: only works for sync on receive stream because we don't prefill.
1656         // ?FIXED?
1657         if(connection->spec.direction==1) { // playback
1658                 int i;
1659
1660                 if((err=freebob_streaming_reset_playback_streams(dev))<0) {
1661                         printError("Could not reset playback streams.\n");
1662                         return err;
1663                 }
1664
1665                 // put nb_periods*period_size of null frames into the playback buffers
1666                 if((err=freebob_streaming_prefill_playback_streams(dev))<0) {
1667                         printError("Could not prefill playback streams.\n");
1668                         return err;
1669                 }
1670                        
1671                 // we should transfer nb_buffers periods of playback from the stream buffers to the event buffer
1672                 for (i=0;i<dev->options.nb_buffers;i++) {
1673                         freebob_streaming_transfer_playback_buffers(dev);
1674                 }
1675         }       
1676
1677         debugPrint(DEBUG_LEVEL_STARTUP, "  stream is running.\n");
1678
1679         return 0;
1680 }
1681
1682 int freebob_streaming_start_iso(freebob_device_t *dev) {
1683         freebob_connection_t *connection=NULL;
1684         unsigned int c;
1685 //      int err;
1686
1687         // when starting the thread, we should wait with iterating the slave connections
1688         // until the master connection has processed some samples, because the devices
1689         // tend to start with a stream of no-data packets, leading to xruns on slave
1690         // transmit, leading to multiple restarts of the thread, which doesn't work correctly (yet)
1691 /*      debugPrint(DEBUG_LEVEL_STARTUP, "Waiting for the sync master...\n");
1692        
1693        
1694         connection=dev->sync_master_connection;
1695        
1696         // start the sync master connection
1697        
1698         connection->iso.startcycle=-1; // don't care when we start this
1699         connection->status.events=0;
1700        
1701         freebob_streaming_start_iso_connection(dev,connection);*/
1702        
1703         // wait until something is received/sent on the connection
1704 //      while(connection->status.events==0) {
1705 //              err=0;
1706 //             
1707 //              // get a packet on the sync master connection
1708 //              err=raw1394_loop_iterate(connection->raw_handle);
1709 //             
1710 //              if (err == -1) {
1711 //                      printError("Possible raw1394 error: %s on sync master connection: %d\n",
1712 //                                         strerror (errno),connection->spec.id);
1713 //              }
1714 //      }
1715        
1716 #define NB_CYCLES_TO_SKIP 100
1717
1718         // get the last timestamp & calculate the start times for the connections
1719         // start ISO xmit/receive
1720        
1721         // we introduce some delay to let the freebob devices start streaming.
1722         usleep(2000);
1723         freebob_streaming_wait_for_sync_stream(dev, dev->sync_master_connection);
1724        
1725         for(c=0; c < dev->nb_connections; c++) {
1726                 connection= &(dev->connections[c]);
1727                
1728 //              if(connection != dev->sync_master_connection) {
1729                        
1730                         connection->iso.startcycle=(dev->sync_master_connection->status.last_timestamp.cycle+NB_CYCLES_TO_SKIP)%8000;
1731                        
1732 //                      connection->iso.startcycle=0;
1733                        
1734                         freebob_streaming_start_iso_connection(dev, connection);
1735 //              }       
1736         }       
1737        
1738         return 0;
1739 }
1740
1741 int freebob_streaming_stop_iso(freebob_device_t *dev) {
1742         unsigned int c;
1743         // stop ISO xmit/receive
1744         for(c=0; c < dev->nb_connections; c++) {
1745                 freebob_connection_t *connection= &(dev->connections[c]);
1746
1747                 freebob_streaming_stop_iso_connection(dev,connection);
1748         }
1749         return 0;
1750 }
1751
1752 /*
1753  * The thread responsible for packet iteration
1754  */
1755
1756 void * freebob_iso_packet_iterator(void *arg)
1757 {
1758
1759         freebob_device_t * dev=(freebob_device_t *) arg;
1760         int err;
1761 //      int cycle=0;
1762         int underrun_detected=0;
1763        
1764         int notdone=TRUE;
1765        
1766         freebob_connection_t *connection=NULL;
1767        
1768         assert(dev);
1769         assert(dev->sync_master_connection);
1770         assert(dev->connections);
1771        
1772         debugPrint(DEBUG_LEVEL_STARTUP, "Entering packetizer thread...\n");
1773        
1774         freebob_streaming_start_iso(dev);
1775
1776         freebob_streaming_print_bufferfill(dev);
1777         // start xmit/receive
1778         debugPrint(DEBUG_LEVEL_STARTUP, "Go Go Go!!!\n");
1779        
1780 #define POLL_BASED     
1781 #ifdef POLL_BASED
1782         while (dev->packetizer.run && !underrun_detected) {
1783                
1784                 freebob_streaming_period_reset(dev);
1785                
1786                 dev->watchdog_check = 1;
1787                
1788                 notdone=TRUE;
1789                
1790                 while(notdone) {
1791                        
1792                         err = poll (dev->pfds, dev->nfds, -1);
1793                        
1794                         if (err == -1) {
1795                                 if (errno == EINTR) {
1796                                         continue;
1797                                 }
1798                                 printError("poll error: %s\n", strerror (errno));
1799                                 dev->packetizer.status = -2;
1800                                 dev->packetizer.retval = 0;
1801                                 notdone=FALSE;
1802                                 break;
1803                         }
1804                        
1805                         int i=0;
1806                
1807                         for (i = 0; i < dev->nfds; i++) {
1808                                 if (dev->pfds[i].revents & POLLERR) {
1809                                         printError ("error on fd for %d\n",i);
1810                                 }
1811
1812                                 if (dev->pfds[i].revents & POLLHUP) {
1813                                         printError ("hangup on fd for %d\n",i);
1814                                 }
1815                                
1816                                 if(dev->pfds[i].revents & (POLLIN)) {
1817                                         // FIXME: this can segfault
1818                                         connection=dev->fdmap[i];
1819                                        
1820                                         assert(connection);
1821                                        
1822                                         err = raw1394_loop_iterate (connection->raw_handle);
1823                                        
1824                                         // detect underruns on the connection
1825                                         if (freebob_streaming_xrun_detected_on_connection(dev,connection)) {
1826                                                 printError("Xrun on connection %d\n", connection->spec.id);
1827                                                 underrun_detected=TRUE;
1828                                                 break; // we can exit as the underrun handler will flush the buffers anyway
1829                                         }
1830                                
1831                                         if (err == -1) {
1832                                                 printError ("possible raw1394 error: %s\n", strerror (errno));
1833                                                 dev->packetizer.status = -2;
1834                                                 dev->packetizer.retval = 0;
1835                                                 notdone=FALSE;
1836                                                 break;
1837                                         }
1838                                 }
1839
1840                                
1841
1842                         }
1843
1844                         notdone=(!freebob_streaming_period_complete(dev) && !underrun_detected && (dev->packetizer.run)) && notdone;
1845                 }
1846                
1847                 if(underrun_detected) {
1848                         dev->xrun_detected=TRUE;
1849                 }
1850
1851 #else
1852         while (dev->packetizer.run && !underrun_detected) {
1853                
1854                 freebob_streaming_period_reset(dev);
1855                        
1856                 dev->watchdog_check = 1;
1857                        
1858                 notdone=TRUE;
1859                        
1860                 while(notdone) {
1861                                
1862                         err=0;
1863                        
1864                         // this makes sure the sync_master finishes before the others finish
1865                         connection=dev->sync_master_connection;
1866                         if (connection->status.frames_left > 0) {
1867                                 // process a packet on the sync master connection
1868                                 err=raw1394_loop_iterate(connection->raw_handle);
1869                                
1870                                 if (err == -1) {
1871                                         printError("Possible raw1394 error: %s on sync master connection: %d\n",
1872                                                         strerror (errno),connection->spec.id);
1873                                                
1874                                         dev->packetizer.status = -2;
1875                                         dev->packetizer.retval = 0;
1876                                         notdone=FALSE;
1877                                         break;
1878                                 }
1879                                
1880                                 // detect underruns on the sync master connection
1881                                 if (freebob_streaming_xrun_detected(dev,&connection,1)) {
1882                                         printError("Xrun on sync master connection %d\n", connection->spec.id);
1883                                         underrun_detected=TRUE;
1884                                         break; // we can exit as the underrun handler will flush the buffers anyway
1885                                 }
1886                         }
1887                                
1888                        
1889                         // now iterate on the slave connections
1890                         int c;
1891                         for(c=0; c<dev->nb_connections; c++) {
1892
1893                                 connection = &(dev->connections[c]);
1894                                
1895                                 if ((connection == dev->sync_master_connection))
1896                                                 continue;
1897                                
1898                                 err=raw1394_loop_iterate(connection->raw_handle);
1899                                
1900                                 if (err == -1) {
1901                                         printError("Possible raw1394 error: %s on connection: %d\n",
1902                                                         strerror (errno),connection->spec.id);
1903                                         dev->packetizer.status = -2;
1904                                         dev->packetizer.retval = 0;
1905                                         notdone=FALSE;
1906                                 }
1907                                
1908                                 // detect underruns
1909                                 if (freebob_streaming_xrun_detected(dev,&connection,1)) {
1910                                         printError("Xrun on slave connection %d\n", connection->spec.id);
1911                                         underrun_detected=TRUE;
1912                                         break; // we can exit as the underrun handler will flush the buffers anyway
1913                                 }
1914                         }
1915                                
1916                         notdone=(!freebob_streaming_period_complete(dev) && !underrun_detected && (dev->packetizer.run)) && notdone;
1917                 }
1918                
1919                 if(underrun_detected) {
1920                         dev->xrun_detected=TRUE;
1921                 }
1922        
1923 #endif
1924                 // notify the waiting thread
1925 #ifdef DEBUG
1926                 debugPrint(DEBUG_LEVEL_HANDLERS, "Post semaphore ");
1927                 int c;
1928                 for(c=0; c<dev->nb_connections; c++) {
1929                         connection = &(dev->connections[c]);
1930                         debugPrintShort(DEBUG_LEVEL_HANDLERS,"[%d: %d]",c,connection->status.frames_left);
1931                 }
1932                 debugPrintShort(DEBUG_LEVEL_HANDLERS,"\n");
1933 #endif
1934
1935                 sem_post(&dev->packetizer.transfer_boundary);
1936
1937 #ifdef DEBUG
1938                 if((dev->sync_master_connection->status.packets - dev->sync_master_connection->status.total_packets_prev) > 1024*2) {
1939                         unsigned int i;
1940                         debugPrintShort(DEBUG_LEVEL_PACKETCOUNTER,"\r -> ");
1941                        
1942                         for(i=0; i < dev->nb_connections; i++) {
1943                                 freebob_connection_t *connection= &(dev->connections[i]);
1944                                 assert(connection);
1945                                
1946                                 debugPrintShort(DEBUG_LEVEL_PACKETCOUNTER,"[%s, %02d, %10d, %04d, %4d, (R: %04d)]",
1947                                         (connection->spec.direction==FREEBOB_CAPTURE ? "C" : "P"),
1948                                         connection->status.fdf,
1949                                         connection->status.packets,
1950                                         connection->status.last_cycle,
1951                                         connection->status.dropped,
1952                                         freebob_ringbuffer_read_space(connection->event_buffer)/(sizeof(quadlet_t)*connection->spec.dimension)
1953                                    );
1954                         }
1955        
1956                         debugPrintShort(DEBUG_LEVEL_PACKETCOUNTER," XRUNS (%2d)",dev->xrun_count);     
1957                         fflush (stderr);
1958                        
1959                         dev->sync_master_connection->status.total_packets_prev=dev->sync_master_connection->status.packets;
1960                 }
1961
1962 #endif
1963
1964         }
1965        
1966         freebob_streaming_stop_iso(dev);
1967        
1968         debugPrint(DEBUG_LEVEL_STARTUP, "Exiting packetizer thread...\n");
1969        
1970        
1971         pthread_exit (0);       
1972 }
1973
1974 void freebob_streaming_append_master_timestamp(freebob_device_t *dev, freebob_timestamp_t *t) {
1975         int c;
1976 //      int retval;
1977         freebob_connection_t *connection;
1978        
1979         assert(dev);
1980        
1981         for(c=0; c<dev->nb_connections; c++) {
1982
1983                 connection = &(dev->connections[c]);
1984                
1985                 // skip the sync master
1986                 if ((connection == dev->sync_master_connection))
1987                         continue;
1988                
1989                 // write the timestamp
1990
1991 /*              retval=freebob_ringbuffer_write(connection->timestamp_buffer,(char *)t,sizeof(freebob_timestamp_t));
1992                
1993                 if(retval!=sizeof(unsigned int)) {
1994                         printError("Timestamp buffer overrun on connection %d!\n",c);
1995                 }
1996 */             
1997         }
1998 }
1999
2000 inline int freebob_streaming_decode_midi(freebob_connection_t *connection,
2001                                                                   quadlet_t* events,
2002                                                                   unsigned int nsamples,
2003                                                                   unsigned int dbc
2004                                                                  ) {
2005         quadlet_t *target_event;
2006        
2007         assert (connection);
2008         assert (events);
2009
2010         freebob_stream_t *stream;
2011        
2012         unsigned int j=0;
2013         unsigned int s=0;
2014         int written=0;
2015         quadlet_t *buffer;
2016        
2017         for (s=0;s<connection->nb_streams;s++) {
2018                 stream=&connection->streams[s];
2019                
2020                 assert (stream);
2021                 assert (stream->spec.position < connection->spec.dimension);
2022                 assert(stream->user_buffer);
2023                
2024                 if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {
2025                         /* idea:
2026                         spec says: current_midi_port=(dbc+j)%8;
2027                         => if we start at (dbc+stream->location)%8,
2028                         we'll start at the right event for the midi port.
2029                         => if we increment j with 8, we stay at the right event.
2030                         */
2031                         buffer=((quadlet_t *)(stream->user_buffer));
2032                         written=0;
2033                        
2034                         for(j = (dbc & 0x07)+stream->spec.location; j < nsamples; j += 8) {
2035                                 target_event=(quadlet_t *)(events + ((j * connection->spec.dimension) + stream->spec.position));
2036                                 quadlet_t sample_int=ntohl(*target_event);
2037                                 if(IEC61883_AM824_GET_LABEL(sample_int) != IEC61883_AM824_LABEL_MIDI_NO_DATA) {
2038                                         *(buffer)=(sample_int >> 16);
2039                                         buffer++;
2040                                         written++;
2041                                 }
2042                         }
2043                        
2044                         int written_to_rb=freebob_ringbuffer_write(stream->buffer, (char *)(stream->user_buffer), written*sizeof(quadlet_t))/sizeof(quadlet_t);
2045                         if(written_to_rb<written) {
2046                                 printMessage("MIDI OUT bytes lost (%d/%d)",written_to_rb,written);
2047                         }
2048                 }
2049         }
2050         return 0;
2051        
2052 }
2053
2054 /*
2055  * according to the MIDI over 1394 spec, we are only allowed to send a maximum of one midi byte every 320usec
2056  * therefore we can only send one byte on 1 out of 3 iso cycles (=325usec)
2057  */
2058
2059 inline int freebob_streaming_encode_midi(freebob_connection_t *connection,
2060                                                                 quadlet_t* events,
2061                                                                 unsigned int nsamples,
2062                                                                 unsigned int dbc
2063                                                                 ) {
2064         quadlet_t *target_event;
2065        
2066         assert (connection);
2067         assert (events);
2068
2069         freebob_stream_t *stream;
2070
2071         unsigned int j=0;
2072         unsigned int s=0;
2073         int read=0;
2074         quadlet_t *buffer;
2075        
2076         for (s=0;s<connection->nb_streams;s++) {
2077                 stream=&connection->streams[s];
2078
2079                 assert (stream);
2080                 assert (stream->spec.position < connection->spec.dimension);
2081                 assert(stream->user_buffer);
2082                
2083                 if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {
2084                         /* idea:
2085                                 spec says: current_midi_port=(dbc+j)%8;
2086                                 => if we start at (dbc+stream->location)%8,
2087                                 we'll start at the right event for the midi port.
2088                                 => if we increment j with 8, we stay at the right event.
2089                         */
2090                        
2091                         if(stream->midi_counter<=0) { // we can send a byte
2092                                 read=freebob_ringbuffer_read(stream->buffer, (char *)(stream->user_buffer), 1*sizeof(quadlet_t))/sizeof(quadlet_t);
2093                                 if(read) {
2094                                         j = (dbc & 0x07)+stream->spec.location;
2095                                         target_event=(quadlet_t *)(events + ((j * connection->spec.dimension) + stream->spec.position));
2096                                         buffer=((quadlet_t *)(stream->user_buffer));
2097                                
2098                                         *target_event=htonl(IEC61883_AM824_SET_LABEL((*buffer)<<16,IEC61883_AM824_LABEL_MIDI_1X));
2099                                         stream->midi_counter=3; // only if we send a byte, we reset the counter
2100                                 }
2101                         } else {
2102                                 stream->midi_counter--;
2103                         }
2104                 }
2105         }
2106         return 0;
2107 }
2108
2109
2110 /**
2111  * ISO send/receive callback handlers
2112  */
2113
2114 static enum raw1394_iso_disposition
2115 iso_master_receive_handler(raw1394handle_t handle, unsigned char *data,
2116         unsigned int length, unsigned char channel,
2117         unsigned char tag, unsigned char sy, unsigned int cycle,
2118         unsigned int dropped)
2119 {
2120         enum raw1394_iso_disposition retval=RAW1394_ISO_OK;
2121
2122         freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);
2123         assert(connection);
2124        
2125         struct iec61883_packet *packet = (struct iec61883_packet *) data;
2126         assert(packet);
2127        
2128         // FIXME: dropped packets are very bad when transmitting and the other side is sync'ing on that!
2129         connection->status.dropped+=dropped;
2130
2131 #ifdef DEBUG   
2132         connection->status.last_cycle=cycle;
2133 #endif
2134
2135         if((packet->fmt == 0x10) && (packet->fdf != 0xFF) && (packet->dbs>0) && (length>=2*sizeof(quadlet_t))) {
2136                 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;
2137                
2138                 // add the data payload to the ringbuffer
2139
2140                 assert(connection->spec.dimension == packet->dbs);
2141                
2142                 if (freebob_ringbuffer_write(
2143                                 connection->event_buffer,(char *)(data+8),
2144                                 nevents*sizeof(quadlet_t)*connection->spec.dimension) <
2145                                 nevents*sizeof(quadlet_t)*connection->spec.dimension)
2146                 {
2147                         printError("MASTER RCV: Buffer overrun!\n");
2148                         connection->status.xruns++;
2149                         retval=RAW1394_ISO_DEFER;
2150                 } else {
2151                         retval=RAW1394_ISO_OK;
2152                         // we cannot offload midi encoding due to the need for a dbc value
2153                         freebob_streaming_decode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);
2154                 }
2155                
2156                 // keep the frame counter
2157                 connection->status.frames_left -= nevents;
2158                
2159                 // keep track of the total amount of events received
2160                 connection->status.events+=nevents;
2161
2162 #ifdef DEBUG   
2163                 connection->status.fdf=packet->fdf;
2164 #endif
2165                
2166         } else {
2167                 // discard packet
2168                 // can be important for sync though
2169         }
2170
2171         // one packet received
2172         connection->status.packets++;
2173
2174 #ifdef DEBUG
2175         if(packet->dbs) {
2176                 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;
2177                 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,
2178                         "MASTER RCV: %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\n",
2179                         cycle,
2180                         channel, packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, length,
2181                         ((length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped,
2182                         connection->status.packets, connection->status.events, connection->status.frames_left,
2183                         nevents);
2184         }
2185 #endif
2186
2187         if((connection->status.frames_left<=0)) {
2188                 connection->pfd->events=0;
2189                 return RAW1394_ISO_DEFER;
2190         }
2191
2192         return retval;
2193 }
2194
2195
2196 static enum raw1394_iso_disposition
2197                 iso_slave_receive_handler(raw1394handle_t handle, unsigned char *data,
2198                                                                   unsigned int length, unsigned char channel,
2199                                                                   unsigned char tag, unsigned char sy, unsigned int cycle,
2200                                                                   unsigned int dropped)
2201 {
2202         enum raw1394_iso_disposition retval=RAW1394_ISO_OK;
2203         /* slave receive is easy if you assume that the connections are synced
2204         Synced connections have matched data rates, so just receiving and
2205         calling the rcv handler would suffice in this case. As the connection
2206         is externally matched to the master connection, the buffer fill will be ok.
2207         */
2208         /* TODO: implement correct SYT behaviour */
2209                
2210         freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);
2211         assert(connection);
2212        
2213         struct iec61883_packet *packet = (struct iec61883_packet *) data;
2214         assert(packet);
2215        
2216         // FIXME: dropped packets are very bad when transmitting and the other side is sync'ing on that!
2217         //connection->status.packets+=dropped;
2218         connection->status.dropped+=dropped;
2219
2220 #ifdef DEBUG   
2221         connection->status.last_cycle=cycle;
2222 #endif
2223
2224         if((packet->fmt == 0x10) && (packet->fdf != 0xFF) && (packet->dbs>0) && (length>=2*sizeof(quadlet_t))) {
2225                 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;
2226
2227 #ifdef DEBUG   
2228                 connection->status.fdf=packet->fdf;
2229 #endif
2230                
2231                 // add the data payload to the ringbuffer
2232
2233                 assert(connection->spec.dimension == packet->dbs);
2234
2235                 if (freebob_ringbuffer_write(
2236                                         connection->event_buffer,(char *)(data+8),
2237                                         nevents*sizeof(quadlet_t)*connection->spec.dimension) <
2238                         nevents*sizeof(quadlet_t)*connection->spec.dimension)
2239                 {
2240                         printError("SLAVE RCV: Buffer overrun!\n");
2241                         connection->status.xruns++;
2242                         retval=RAW1394_ISO_DEFER;
2243                 } else {
2244                         retval=RAW1394_ISO_OK;
2245                         // we cannot offload midi encoding due to the need for a dbc value
2246                         freebob_streaming_decode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);
2247                 }
2248
2249                 connection->status.frames_left-=nevents;
2250                
2251                 // keep track of the total amount of events received
2252                 connection->status.events+=nevents;
2253         } else {
2254                 // discard packet
2255                 // can be important for sync though
2256         }
2257
2258         // one packet received
2259         connection->status.packets++;
2260        
2261         if(packet->dbs) {
2262                 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,
2263                         "SLAVE RCV: CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %6d\n",
2264                         channel, packet->fdf,
2265                         packet->syt,
2266                         packet->dbs,
2267                         packet->dbc,
2268                         packet->fmt,
2269                         length,
2270                         ((length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped);
2271         }
2272                
2273                
2274         if((connection->status.frames_left<=0)) {
2275                 connection->pfd->events=0;
2276                 return RAW1394_ISO_DEFER;
2277         }
2278
2279         return retval;
2280 }
2281
2282 /**
2283  * The master transmit handler.
2284  *
2285  * This is the most difficult, because we have to generate timing information ourselves.
2286  *
2287  */
2288
2289 /*
2290  Includes code from libiec61883
2291  */
2292 static enum raw1394_iso_disposition
2293 iso_master_transmit_handler(raw1394handle_t handle,
2294                 unsigned char *data, unsigned int *length,
2295                 unsigned char *tag, unsigned char *sy,
2296                 int cycle, unsigned int dropped)
2297 {
2298         freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);
2299         assert(connection);
2300        
2301         struct iec61883_packet *packet = (struct iec61883_packet *) data;
2302         assert(packet);
2303         assert(length);
2304         assert(tag);
2305         assert(sy);     
2306        
2307         // construct the packet cip
2308         int nevents = iec61883_cip_fill_header (handle, &connection->status.cip, packet);
2309         int nsamples=0;
2310         int bytes_read;
2311        
2312 #ifdef DEBUG   
2313         connection->status.last_cycle=cycle;
2314
2315         if(packet->fdf != 0xFF) {
2316                 connection->status.fdf=packet->fdf;
2317         }
2318 #endif
2319
2320         enum raw1394_iso_disposition retval = RAW1394_ISO_OK;
2321
2322
2323
2324         if (nevents > 0) {
2325                 nsamples = nevents;
2326         }
2327         else {
2328                 if (connection->status.cip.mode == IEC61883_MODE_BLOCKING_EMPTY) {
2329                         nsamples = 0;
2330                 }
2331                 else {
2332                         nsamples = connection->status.cip.syt_interval;
2333                 }
2334         }
2335        
2336         // dropped packets are very bad when transmitting and the other side is sync'ing on that!
2337         connection->status.dropped += dropped;
2338                
2339         if (nsamples > 0) {
2340
2341                 assert(connection->spec.dimension == packet->dbs);
2342
2343                 if ((bytes_read=freebob_ringbuffer_read(connection->event_buffer,(char *)(data+8),nsamples*sizeof(quadlet_t)*connection->spec.dimension)) <
2344                                    nsamples*sizeof(quadlet_t)*connection->spec.dimension)
2345                 {
2346                         printError("MASTER XMT: Buffer underrun! (%d / %d) (%d / %d )\n",
2347                                            bytes_read,nsamples*sizeof(quadlet_t)*connection->spec.dimension,
2348                                            freebob_ringbuffer_read_space(connection->event_buffer),0);
2349                         connection->status.xruns++;
2350                         retval=RAW1394_ISO_DEFER;
2351                         nsamples=0;
2352                 } else {
2353                         retval=RAW1394_ISO_OK;
2354                         // we cannot offload midi encoding due to the need for a dbc value
2355                         freebob_streaming_encode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);
2356                 }
2357         }
2358        
2359         *length = nsamples * connection->spec.dimension * sizeof (quadlet_t) + 8;
2360         *tag = IEC61883_TAG_WITH_CIP;
2361         *sy = 0;
2362        
2363         // keep track of the total amount of events transmitted
2364         connection->status.events+=nsamples;
2365        
2366         connection->status.frames_left-=nsamples;
2367                
2368         // one packet transmitted
2369         connection->status.packets++;
2370
2371         if(packet->dbs) {
2372                 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,
2373                                                                 "MASTER 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\n", cycle,
2374                                                                 connection->iso.iso_channel,  packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, *length,((*length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped,
2375                                                                 connection->status.packets, connection->status.events, connection->status.frames_left,
2376                                                                 nevents, nsamples);
2377         }
2378
2379         if((connection->status.frames_left<=0)) {
2380                 connection->pfd->events=0;
2381                 return RAW1394_ISO_DEFER;
2382         }
2383
2384         return retval;
2385
2386 }
2387
2388 static enum raw1394_iso_disposition
2389                 iso_slave_transmit_handler(raw1394handle_t handle,
2390                                                                    unsigned char *data, unsigned int *length,
2391                                                                    unsigned char *tag, unsigned char *sy,
2392                                                                    int cycle, unsigned int dropped)
2393 {
2394         freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);
2395         assert(connection);
2396        
2397         struct iec61883_packet *packet = (struct iec61883_packet *) data;
2398         assert(packet);
2399         assert(length);
2400         assert(tag);
2401         assert(sy);     
2402        
2403         // construct the packet cip
2404         struct iec61883_cip old_cip;
2405         memcpy(&old_cip,&connection->status.cip,sizeof(struct iec61883_cip));
2406        
2407         int nevents = iec61883_cip_fill_header (handle, &connection->status.cip, packet);
2408         int nsamples=0;
2409         int bytes_read;
2410
2411 #ifdef DEBUG   
2412         connection->status.last_cycle=cycle;
2413
2414         if(packet->fdf != 0xFF) {
2415                 connection->status.fdf=packet->fdf;
2416         }
2417 #endif
2418
2419         enum raw1394_iso_disposition retval = RAW1394_ISO_OK;
2420
2421
2422         if (nevents > 0) {
2423                 nsamples = nevents;
2424         }
2425         else {
2426                 if (connection->status.cip.mode == IEC61883_MODE_BLOCKING_EMPTY) {
2427                         nsamples = 0;
2428                 }
2429                 else {
2430                         nsamples = connection->status.cip.syt_interval;
2431                 }
2432         }
2433        
2434         // dropped packets are very bad when transmitting and the other side is sync'ing on that!
2435         //connection->status.packets+=dropped;
2436         connection->status.dropped += dropped;
2437                
2438         if (nsamples > 0) {
2439                 int bytes_to_read=nsamples*sizeof(quadlet_t)*connection->spec.dimension;
2440
2441                 assert(connection->spec.dimension == packet->dbs);
2442
2443                 if ((bytes_read=freebob_ringbuffer_read(connection->event_buffer,(char *)(data+8),bytes_to_read)) <
2444                         bytes_to_read)
2445                 {
2446                         /* there is no more data in the ringbuffer */
2447                        
2448                         /* If there are already more than on period
2449                         * of frames transfered to the XMIT buffer, there is no xrun.
2450                         *
2451                         */
2452                         if(connection->status.frames_left<=0) {
2453                                 // we stop processing this untill the next period boundary
2454                                 // that's when new data is ready
2455                                
2456                                 connection->pfd->events=0;
2457                                
2458                                 // reset the cip to the old value
2459                                 memcpy(&connection->status.cip,&old_cip,sizeof(struct iec61883_cip));
2460
2461                                 // retry this packet
2462                                 retval=RAW1394_ISO_AGAIN;
2463 //                              retval=RAW1394_ISO_DEFER;
2464                                 nsamples=0;
2465                         } else {
2466                                 printError("SLAVE XMT : Buffer underrun! %d (%d / %d) (%d / %d )\n",
2467                                            connection->status.frames_left, bytes_read,bytes_to_read,
2468                                            freebob_ringbuffer_read_space(connection->event_buffer),0);
2469                                 connection->status.xruns++;
2470                                 retval=RAW1394_ISO_DEFER;
2471                                 nsamples=0;
2472                         }
2473                 } else {
2474                         retval=RAW1394_ISO_OK;
2475                         // we cannot offload midi encoding due to the need for a dbc value
2476                         freebob_streaming_encode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);
2477                 }
2478         }
2479        
2480         *length = nsamples * connection->spec.dimension * sizeof (quadlet_t) + 8;
2481         *tag = IEC61883_TAG_WITH_CIP;
2482         *sy = 0;
2483        
2484         // keep track of the total amount of events transmitted
2485         connection->status.events+=nsamples;
2486        
2487         connection->status.frames_left-=nsamples;
2488                
2489         // one packet transmitted
2490         connection->status.packets++;
2491
2492         if(packet->dbs) {
2493                 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,
2494                                                                 "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\n", cycle,
2495                                                                 connection->iso.iso_channel,  packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, *length,((*length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped,
2496                                                                 connection->status.packets, connection->status.events, connection->status.frames_left,
2497                                                                 nevents, nsamples);
2498         }
2499
2500         if((connection->status.frames_left<=0)) {
2501                 connection->pfd->events=0;
2502                 return RAW1394_ISO_DEFER;
2503         }
2504
2505         return retval;
2506
2507 }
2508
2509 /*
2510  * Decoders and encoders
2511  */
2512 #ifdef ENABLE_SSE
2513 typedef float v4sf __attribute__ ((vector_size (16)));
2514 typedef int v4si __attribute__ ((vector_size (16)));
2515 typedef int v2si __attribute__ ((vector_size (8)));
2516
2517 static inline int 
2518 freebob_decode_events_to_stream(freebob_connection_t *connection,
2519                                                                 freebob_stream_t *stream,
2520                                                                 quadlet_t* events,
2521                                                                 unsigned int nsamples,
2522                                                                 unsigned int dbc
2523                                                                 ) {
2524         quadlet_t *target_event;
2525         int do_ringbuffer_write=0;
2526        
2527         assert (stream);
2528         assert (connection);
2529         assert (events);
2530         assert (stream->spec.position < connection->spec.dimension);
2531                
2532         freebob_sample_t *buffer=NULL;
2533         float *floatbuff=NULL;
2534
2535         int dimension=connection->spec.dimension;
2536        
2537         static const float multiplier = 1.0f / (float)(0x7FFFFF);
2538         static const float sse_multiplier[4] __attribute__((aligned(16))) = {
2539                 1.0f / (float)(0x7FFFFF),
2540                 1.0f / (float)(0x7FFFFF),
2541                 1.0f / (float)(0x7FFFFF),
2542                 1.0f / (float)(0x7FFFFF)
2543         };
2544         unsigned int tmp[4];
2545
2546         assert(stream->user_buffer);
2547        
2548         switch(stream->buffer_type) {
2549                 case freebob_buffer_type_per_stream:
2550                 default:
2551                         // use the preallocated buffer (at init time)
2552                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2553                        
2554                         do_ringbuffer_write=1;
2555                         break;
2556                                
2557                 case freebob_buffer_type_uint24:
2558                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2559                        
2560                         do_ringbuffer_write=0;
2561                         break;
2562                                
2563                 case freebob_buffer_type_float:
2564                         floatbuff=((float *)(stream->user_buffer))+stream->user_buffer_position;
2565                        
2566                         do_ringbuffer_write=0;
2567                         break;
2568         }
2569        
2570         int j=0;
2571         int written=0;
2572        
2573         if (stream->spec.format== IEC61883_STREAM_TYPE_MBLA) {
2574                 target_event=(quadlet_t *)(events + stream->spec.position);
2575
2576                 // TODO: convert this into function pointer based
2577                 switch(stream->buffer_type) {
2578                         default:
2579                         case freebob_buffer_type_uint24:
2580                                 for(j = 0; j < nsamples; j += 1) { // decode max nsamples
2581                                         *(buffer)=(ntohl((*target_event) ) & 0x00FFFFFF);
2582                                         buffer++;
2583                                         target_event+=dimension;
2584                                 }
2585                                 break;
2586                         case freebob_buffer_type_float:
2587                                 j=0;
2588                                 if(nsamples>3) {
2589                                         for(j = 0; j < nsamples-3; j += 4) {
2590                                                 tmp[0] = ntohl(*target_event);
2591                                                 target_event += dimension;
2592                                                 tmp[1] = ntohl(*target_event);
2593                                                 target_event += dimension;
2594                                                 tmp[2] = ntohl(*target_event);
2595                                                 target_event += dimension;
2596                                                 tmp[3] = ntohl(*target_event);
2597                                                 target_event += dimension;
2598                                                 asm("pslld $8, %[in2]\n\t" // sign extend 24th bit
2599                                                                 "pslld $8, %[in1]\n\t"
2600                                                                 "psrad $8, %[in2]\n\t"
2601                                                                 "psrad $8, %[in1]\n\t"
2602                                                                 "cvtpi2ps %[in2], %%xmm0\n\t"
2603                                                                 "movlhps %%xmm0, %%xmm0\n\t"
2604                                                                 "cvtpi2ps %[in1], %%xmm0\n\t"
2605                                                                 "mulps %[ssemult], %%xmm0\n\t"
2606                                                                 "movups %%xmm0, %[floatbuff]"
2607                                                         : [floatbuff] "=m" (*(v4sf*)floatbuff)
2608                                                         : [in1] "y" (*(v2si*)tmp),
2609                                                 [in2] "y" (*(v2si*)(tmp+2)),
2610                                                 [ssemult] "x" (*(v4sf*)sse_multiplier)
2611                                                         : "xmm0");
2612                                                 floatbuff += 4;
2613                                         }
2614                                 }
2615                                 for(; j < nsamples; ++j) { // decode max nsamples
2616                                         unsigned int v = ntohl(*target_event) & 0x00FFFFFF;
2617                                         // sign-extend highest bit of 24-bit int
2618                                         int tmp = (int)(v << 8) / 256;
2619                                         *floatbuff = tmp * multiplier;
2620
2621                                         floatbuff++;
2622                                         target_event += dimension;
2623                                 }
2624                                 asm volatile("emms");
2625                                
2626                                 break;
2627                 }
2628
2629 //              fprintf(stderr,"rb write [%02d: %08p %08p]\n",stream->spec.position, stream, stream->buffer);
2630        
2631 //      fprintf(stderr,"rb write [%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, written);
2632                 if(do_ringbuffer_write) {
2633                         // reset the buffer pointer
2634                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2635                         written=freebob_ringbuffer_write(stream->buffer, (char *)(buffer), nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t);
2636                 } else {
2637                         written=nsamples;
2638                 }
2639                
2640 //      fprintf(stderr,"rb write1[%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, written);
2641                
2642                 return written;
2643        
2644         } else if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {
2645                 return nsamples; // for midi streams we always indicate a full write
2646        
2647         } else {//if (stream->spec.format == IEC61883_STREAM_TYPE_SPDIF) {
2648                 return nsamples; // for unsupported we always indicate a full read
2649        
2650         }
2651        
2652         return 0;
2653
2654
2655 }
2656
2657 static inline int
2658 freebob_encode_stream_to_events(freebob_connection_t *connection,
2659                                                                 freebob_stream_t *stream,
2660                                                                 quadlet_t* events,
2661                                                                 unsigned int nsamples,
2662                                                                 unsigned int dbc
2663                                                                 ) {
2664         quadlet_t *target_event;
2665         //freebob_sample_t buff[nsamples];
2666         int do_ringbuffer_read=0;
2667        
2668         freebob_sample_t *buffer=NULL;
2669         float *floatbuff=NULL;
2670
2671         const float multiplier = (float)(0x7FFFFF00);
2672         static const float sse_multiplier[4] __attribute__((aligned(16))) = {
2673                 (float)(0x7FFFFF00),
2674                 (float)(0x7FFFFF00),
2675                 (float)(0x7FFFFF00),
2676                 (float)(0x7FFFFF00)
2677         };
2678
2679         static const int sse_mask[4] __attribute__((aligned(16))) = {
2680                 0x40000000,  0x40000000,  0x40000000,  0x40000000
2681         };
2682
2683         unsigned int out[4];   
2684        
2685         int dimension=connection->spec.dimension;
2686        
2687         unsigned int j=0;
2688         unsigned int read=0;
2689
2690         assert (stream);
2691         assert (connection);
2692         assert (events);
2693         assert (stream->spec.position < connection->spec.dimension);
2694        
2695         switch(stream->buffer_type) {
2696                 case freebob_buffer_type_per_stream:
2697                 default:
2698 //                      assert(nsamples < dev->options.period_size);
2699                         // use the preallocated buffer (at init time)
2700                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2701                        
2702                         do_ringbuffer_read=1;
2703                         break;
2704                                
2705                 case freebob_buffer_type_uint24:
2706                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2707                        
2708                         do_ringbuffer_read=0;
2709                         break;
2710                                
2711                 case freebob_buffer_type_float:
2712                         floatbuff=((float *)(stream->user_buffer))+stream->user_buffer_position;
2713                        
2714                         do_ringbuffer_read=0;
2715                         break;
2716         }
2717        
2718        
2719         if(stream->spec.format == IEC61883_STREAM_TYPE_MBLA) { // MBLA
2720                 target_event=(quadlet_t *)(events + (stream->spec.position));
2721                
2722                 if(do_ringbuffer_read) {
2723                         read=freebob_ringbuffer_read(stream->buffer, (char *)buffer, nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t);
2724                 } else {
2725                         read=nsamples;
2726                 }
2727                
2728                 // TODO: convert this into function pointer based
2729                 switch(stream->buffer_type) {
2730                         default:
2731                         case freebob_buffer_type_uint24:
2732                                 for(j = 0; j < read; j += 1) { // decode max nsamples
2733                                         *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);
2734                                         buffer++;
2735                                         target_event+=dimension;
2736                                        
2737                 //                      fprintf(stderr,"[%03d, %02d: %08p %08X %08X]\n",j, stream->spec.position, target_event, *target_event, *buffer);
2738
2739                                 }
2740                                 break;
2741                         case freebob_buffer_type_float:
2742 /*                              for(j = 0; j < read; j += 1) { // decode max nsamples
2743                                         // don't care for overflow
2744                                         float v = *floatbuff * multiplier;  // v: -231 .. 231
2745                                         unsigned int tmp = ((int)v);
2746                                         *target_event = htonl((tmp >> 8) | 0x40000000);
2747                                        
2748                                         floatbuff++;
2749                                         target_event += connection->spec.dimension;
2750                                 }*/
2751                                 j=0;
2752                                 if(read>3) {
2753                                         for (j = 0; j < read-3; j += 4) {
2754                                                 asm("movups %[floatbuff], %%xmm0\n\t"
2755                                                                 "mulps %[ssemult], %%xmm0\n\t"
2756                                                                 "cvttps2pi %%xmm0, %[out1]\n\t"
2757                                                                 "movhlps %%xmm0, %%xmm0\n\t"
2758                                                                 "psrld $8, %[out1]\n\t"
2759                                                                 "cvttps2pi %%xmm0, %[out2]\n\t"
2760                                                                 "por %[mmxmask], %[out1]\n\t"
2761                                                                 "psrld $8, %[out2]\n\t"
2762                                                                 "por %[mmxmask], %[out2]\n\t"
2763                                                         : [out1] "=&y" (*(v2si*)&out[0]),
2764                                                 [out2] "=&y" (*(v2si*)&out[2])
2765                                                         : [floatbuff] "m" (*(v4sf*)floatbuff),
2766                                                 [ssemult] "x" (*(v4sf*)sse_multiplier),
2767                                                 [mmxmask] "y" (*(v2si*)sse_mask)
2768                                                         : "xmm0");
2769                                                 floatbuff += 4;
2770                                                 *target_event = htonl(out[0]);
2771                                                 target_event += dimension;
2772                                                 *target_event = htonl(out[1]);
2773                                                 target_event += dimension;
2774                                                 *target_event = htonl(out[2]);
2775                                                 target_event += dimension;
2776                                                 *target_event = htonl(out[3]);
2777                                                 target_event += dimension;
2778                                         }
2779                                 }
2780                                 for(; j < read; ++j) {
2781                                 // don't care for overflow
2782                                         float v = *floatbuff * multiplier;  // v: -231 .. 231
2783                                         unsigned int tmp = (int)v;
2784                                         *target_event = htonl((tmp >> 8) | 0x40000000);
2785                
2786                                         floatbuff++;
2787                                         target_event += dimension;
2788                                 }
2789
2790                                 asm volatile("emms");
2791                                 break;
2792                 }
2793                
2794                 /*             
2795                 for(j = 0; j < nsamples; j+=1) {
2796                         *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);
2797                         buffer++;
2798                         target_event+=connection->spec.dimension;
2799                 }
2800                 */
2801                
2802                 return read;
2803                
2804         } else if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {
2805                 return nsamples; // for midi we always indicate a full read
2806        
2807         } else { //if (stream->spec.format == IEC61883_STREAM_TYPE_SPDIF) {
2808                 return nsamples; // for unsupported we always indicate a full read
2809        
2810         }
2811         return 0;
2812
2813 }
2814
2815 #else
2816
2817 static inline int 
2818 freebob_decode_events_to_stream(freebob_connection_t *connection,
2819                                                                 freebob_stream_t *stream,
2820                                                                 quadlet_t* events,
2821                                                                 unsigned int nsamples,
2822                                                                 unsigned int dbc
2823                                                                 ) {
2824         quadlet_t *target_event;
2825         int do_ringbuffer_write=0;
2826        
2827         assert (stream);
2828         assert (connection);
2829         assert (events);
2830         assert (stream->spec.position < connection->spec.dimension);
2831                
2832         freebob_sample_t *buffer=NULL;
2833         float *floatbuff=NULL;
2834
2835         const float multiplier = 1.0f / (float)(0x7FFFFF);
2836        
2837         int dimension=connection->spec.dimension;
2838        
2839         assert(stream->user_buffer);
2840        
2841         switch(stream->buffer_type) {
2842                 case freebob_buffer_type_per_stream:
2843                 default:
2844 //                      assert(nsamples < dev->options.period_size);
2845                        
2846                         // use the preallocated buffer (at init time)
2847                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2848                        
2849                         do_ringbuffer_write=1;
2850                         break;
2851                                
2852                 case freebob_buffer_type_uint24:
2853                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2854                        
2855                         do_ringbuffer_write=0;
2856                         break;
2857                                
2858                 case freebob_buffer_type_float:
2859                         floatbuff=((float *)(stream->user_buffer))+stream->user_buffer_position;
2860                        
2861                         do_ringbuffer_write=0;
2862                         break;
2863         }
2864        
2865         int j=0;
2866         int written=0;
2867        
2868         if (stream->spec.format== IEC61883_STREAM_TYPE_MBLA) {
2869                 target_event=(quadlet_t *)(events + stream->spec.position);
2870
2871                 // TODO: convert this into function pointer based
2872                 switch(stream->buffer_type) {
2873                         default:
2874                         case freebob_buffer_type_uint24:
2875                                 for(j = 0; j < nsamples; j += 1) { // decode max nsamples
2876                                         *(buffer)=(ntohl((*target_event) ) & 0x00FFFFFF);
2877                 //                      fprintf(stderr,"[%03d, %02d: %08p %08X %08X]\n",j, stream->spec.position, target_event, *target_event, *buffer);
2878                                         buffer++;
2879                                         target_event+=dimension;
2880                                 }
2881                                 break;
2882                         case freebob_buffer_type_float:
2883                                 for(j = 0; j < nsamples; j += 1) { // decode max nsamples               
2884
2885                                         unsigned int v = ntohl(*target_event) & 0x00FFFFFF;
2886                                         // sign-extend highest bit of 24-bit int
2887                                         int tmp = (int)(v << 8) / 256;
2888                
2889                                         *floatbuff = tmp * multiplier;
2890                                
2891                                         floatbuff++;
2892                                         target_event+=dimension;
2893                                 }
2894                                 break;
2895                 }
2896
2897 //              fprintf(stderr,"rb write [%02d: %08p %08p]\n",stream->spec.position, stream, stream->buffer);
2898        
2899 //      fprintf(stderr,"rb write [%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, written);
2900                 if(do_ringbuffer_write) {
2901                         // reset the buffer pointer
2902                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2903                         written=freebob_ringbuffer_write(stream->buffer, (char *)(buffer), nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t);
2904                 } else {
2905                         written=nsamples;
2906                 }
2907                
2908 //      fprintf(stderr,"rb write1[%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, written);
2909                
2910                 return written;
2911        
2912         } else if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {
2913                 return nsamples; // for midi streams we always indicate a full write
2914        
2915         } else {//if (stream->spec.format == IEC61883_STREAM_TYPE_SPDIF) {
2916                 return nsamples; // for unsupported we always indicate a full read
2917        
2918         }
2919        
2920         return 0;
2921
2922
2923 }
2924
2925 static inline int
2926 freebob_encode_stream_to_events(freebob_connection_t *connection,
2927                                                                 freebob_stream_t *stream,
2928                                                                 quadlet_t* events,
2929                                                                 unsigned int nsamples,
2930                                                                 unsigned int dbc
2931                                                                 ) {
2932         quadlet_t *target_event;
2933         //freebob_sample_t buff[nsamples];
2934         int do_ringbuffer_read=0;
2935        
2936         freebob_sample_t *buffer=NULL;
2937         float *floatbuff=NULL;
2938
2939         const float multiplier = (float)(0x7FFFFF00);
2940         int dimension=connection->spec.dimension;
2941        
2942         unsigned int j=0;
2943         unsigned int read=0;
2944
2945         assert (stream);
2946         assert (connection);
2947         assert (events);
2948         assert (stream->spec.position < connection->spec.dimension);
2949        
2950         switch(stream->buffer_type) {
2951                 case freebob_buffer_type_per_stream:
2952                 default:
2953 //                      assert(nsamples < dev->options.period_size);
2954                         // use the preallocated buffer (at init time)
2955                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2956                        
2957                         do_ringbuffer_read=1;
2958                         break;
2959                                
2960                 case freebob_buffer_type_uint24:
2961                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2962                        
2963                         do_ringbuffer_read=0;
2964                         break;
2965                                
2966                 case freebob_buffer_type_float:
2967                         floatbuff=((float *)(stream->user_buffer))+stream->user_buffer_position;
2968                        
2969                         do_ringbuffer_read=0;
2970                         break;
2971         }
2972        
2973        
2974         if(stream->spec.format == IEC61883_STREAM_TYPE_MBLA) { // MBLA
2975                 target_event=(quadlet_t *)(events + (stream->spec.position));
2976                
2977                 if(do_ringbuffer_read) {
2978                         read=freebob_ringbuffer_read(stream->buffer, (char *)buffer, nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t);
2979                 } else {
2980                         read=nsamples;
2981                 }
2982                
2983                 // TODO: convert this into function pointer based
2984                 switch(stream->buffer_type) {
2985                         default:
2986                         case freebob_buffer_type_uint24:
2987                                 for(j = 0; j < read; j += 1) { // decode max nsamples
2988                                         *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);
2989                                         buffer++;
2990                                         target_event+=dimension;
2991                                        
2992                 //                      fprintf(stderr,"[%03d, %02d: %08p %08X %08X]\n",j, stream->spec.position, target_event, *target_event, *buffer);
2993
2994                                 }
2995                                 break;
2996                         case freebob_buffer_type_float:
2997                                 for(j = 0; j < read; j += 1) { // decode max nsamples
2998                                         // don't care for overflow
2999                                         float v = *floatbuff * multiplier;  // v: -231 .. 231
3000                                         unsigned int tmp = ((int)v);
3001                                         *target_event = htonl((tmp >> 8) | 0x40000000);
3002                                        
3003                                         floatbuff++;
3004                                         target_event += dimension;
3005                                 }
3006                                 break;
3007                 }
3008                
3009                 /*             
3010                 for(j = 0; j < nsamples; j+=1) {
3011                         *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);
3012                         buffer++;
3013                         target_event+=connection->spec.dimension;
3014                 }
3015                 */
3016                
3017                 return read;
3018                
3019         } else if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {
3020                 return nsamples; // for midi we always indicate a full read
3021        
3022         } else { //if (stream->spec.format == IEC61883_STREAM_TYPE_SPDIF) {
3023                 return nsamples; // for unsupported we always indicate a full read
3024        
3025         }
3026         return 0;
3027
3028 }
3029 #endif
3030
3031 /*
3032  * write received events to the stream ringbuffers.
3033  */
3034
3035 int freebob_am824_recv(char *data,
3036                                            int nevents, unsigned int offset, unsigned int dbc,
3037                                freebob_connection_t *connection)
3038 {
3039         int xrun=0;
3040         unsigned int i=0;
3041        
3042         for(i = 0; i < connection->nb_streams; i++) {
3043                 freebob_stream_t *stream = &(connection->streams[i]);
3044                 size_t written=0;
3045                
3046                 assert(stream);
3047                
3048                 stream->user_buffer_position=offset;
3049                
3050                 debugPrintShort(DEBUG_LEVEL_HANDLERS,"[%d: %d ",i,freebob_ringbuffer_write_space(stream->buffer));
3051                 written = freebob_decode_events_to_stream(
3052                         connection,
3053                         stream,
3054                         (quadlet_t *)data,
3055                         nevents,
3056                         dbc
3057                         );
3058
3059                 if (written < nevents) {
3060                         xrun++;
3061                 }
3062                
3063                 debugPrintShort(DEBUG_LEVEL_HANDLERS, "%d %d]",written,freebob_ringbuffer_write_space(stream->buffer));
3064         }
3065        
3066 //      connection->status.frames_left-=nevents;
3067                
3068         debugPrintShort(DEBUG_LEVEL_HANDLERS, "\n");
3069        
3070         return xrun;
3071 }
3072
3073 /*
3074  * get xmit events from ringbuffer
3075  */
3076
3077 int freebob_am824_xmit( char *data,
3078                                                 int nevents, unsigned int offset, unsigned int dbc,
3079                                                 freebob_connection_t *connection)
3080 {
3081         int xrun=0;
3082         unsigned int i=0;
3083        
3084         for(i = 0; i < connection->nb_streams; i++) {
3085                 freebob_stream_t *stream = &(connection->streams[i]);
3086                 size_t read=0;
3087                
3088                 assert(stream);
3089                 debugPrintShort(DEBUG_LEVEL_HANDLERS, "[%d: %d ",i,freebob_ringbuffer_read_space(stream->buffer));
3090                
3091                 stream->user_buffer_position=offset;
3092                
3093                 read = freebob_encode_stream_to_events(
3094                         connection,
3095                         stream,
3096                         (quadlet_t *)data,
3097                         nevents,
3098                         dbc
3099                         );
3100                
3101                 debugPrintShort(DEBUG_LEVEL_HANDLERS, "%d %d]",read,freebob_ringbuffer_read_space(stream->buffer));
3102
3103                 if (read < nevents) {
3104                         xrun++;
3105                 }
3106                
3107         }
3108         debugPrintShort(DEBUG_LEVEL_HANDLERS, "\n");
3109        
3110 //      connection->status.frames_left-=nevents;
3111        
3112         return xrun;
3113 }
3114
3115 void *freebob_streaming_watchdog_thread (void *arg)
3116 {
3117         freebob_device_t *dev = (freebob_device_t *) arg;
3118
3119         dev->watchdog_check = 0;
3120
3121         while (1) {
3122                 sleep (2);
3123                 if (dev->watchdog_check == 0) {
3124
3125                         printError("watchdog: timeout");
3126
3127                         /* kill our process group, try to get a dump */
3128                         kill (-getpgrp(), SIGABRT);
3129                         /*NOTREACHED*/
3130                         exit (1);
3131                 }
3132                 dev->watchdog_check = 0;
3133         }
3134 }
3135
3136 int freebob_streaming_start_watchdog (freebob_device_t *dev)
3137 {
3138         int watchdog_priority = dev->packetizer.priority + 10;
3139         int max_priority = sched_get_priority_max (SCHED_FIFO);
3140
3141         debugPrint(DEBUG_LEVEL_STARTUP, "Starting Watchdog...\n");
3142        
3143         if ((max_priority != -1) &&
3144                         (max_priority < watchdog_priority))
3145                 watchdog_priority = max_priority;
3146        
3147         if (freebob_streaming_create_thread (dev, &dev->watchdog_thread, watchdog_priority,
3148                 TRUE, freebob_streaming_watchdog_thread, dev)) {
3149                         printError ("cannot start watchdog thread");
3150                         return -1;
3151                 }
3152
3153         return 0;
3154 }
3155
3156 void freebob_streaming_stop_watchdog (freebob_device_t *dev)
3157 {
3158         debugPrint(DEBUG_LEVEL_STARTUP, "Stopping Watchdog...\n");
3159        
3160         pthread_cancel (dev->watchdog_thread);
3161         pthread_join (dev->watchdog_thread, NULL);
3162 }
Note: See TracBrowser for help on using the browser.