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

Revision 431, 89.1 kB (checked in by pieterpalmers, 15 years ago)

- fix bug in midi handling
- bump version to 1.0.2

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