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

Revision 427, 89.5 kB (checked in by pieterpalmers, 16 years ago)

fixed jackd freewheeling issue

  • 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-1)%8 [due to location_min=1],
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-1; 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                         // first prefill the buffer with NO_DATA's on all time muxed channels
2061                         for(j=0; (j < nsamples); j++) {
2062                                 target_event=(quadlet_t *)(events + ((j * connection->spec.dimension) + stream->spec.position));
2063                                
2064                                 *target_event=htonl(IEC61883_AM824_SET_LABEL(0,IEC61883_AM824_LABEL_MIDI_NO_DATA));
2065
2066                         }
2067                        
2068                         /* idea:
2069                                 spec says: current_midi_port=(dbc+j)%8;
2070                                 => if we start at (dbc+stream->location-1)%8 [due to location_min=1],
2071                                 we'll start at the right event for the midi port.
2072                                 => if we increment j with 8, we stay at the right event.
2073                         */
2074                        
2075                         if(stream->midi_counter<=0) { // we can send a byte
2076                                 read=freebob_ringbuffer_read(stream->buffer, (char *)(stream->user_buffer), 1*sizeof(quadlet_t))/sizeof(quadlet_t);
2077                                 if(read) {
2078 //                                      j = (dbc%8)+stream->spec.location-1;
2079                                         j = (dbc & 0x07)+stream->spec.location-1;
2080                                         target_event=(quadlet_t *)(events + ((j * connection->spec.dimension) + stream->spec.position));
2081                                         buffer=((quadlet_t *)(stream->user_buffer));
2082                                
2083                                         *target_event=htonl(IEC61883_AM824_SET_LABEL((*buffer)<<16,IEC61883_AM824_LABEL_MIDI_1X));
2084                                         stream->midi_counter=3; // only if we send a byte, we reset the counter
2085                                 }
2086                         } else {
2087                                 stream->midi_counter--;
2088                         }
2089                 }
2090         }
2091         return 0;
2092
2093 }
2094
2095
2096 /**
2097  * ISO send/receive callback handlers
2098  */
2099
2100 static enum raw1394_iso_disposition
2101 iso_master_receive_handler(raw1394handle_t handle, unsigned char *data,
2102         unsigned int length, unsigned char channel,
2103         unsigned char tag, unsigned char sy, unsigned int cycle,
2104         unsigned int dropped)
2105 {
2106         enum raw1394_iso_disposition retval=RAW1394_ISO_OK;
2107
2108         freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);
2109         assert(connection);
2110        
2111         struct iec61883_packet *packet = (struct iec61883_packet *) data;
2112         assert(packet);
2113        
2114         // FIXME: dropped packets are very bad when transmitting and the other side is sync'ing on that!
2115         connection->status.dropped+=dropped;
2116
2117 #ifdef DEBUG   
2118         connection->status.last_cycle=cycle;
2119 #endif
2120
2121         if((packet->fmt == 0x10) && (packet->fdf != 0xFF) && (packet->dbs>0) && (length>=2*sizeof(quadlet_t))) {
2122                 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;
2123                
2124                 // add the data payload to the ringbuffer
2125
2126                 assert(connection->spec.dimension == packet->dbs);
2127                
2128                 if (freebob_ringbuffer_write(
2129                                 connection->event_buffer,(char *)(data+8),
2130                                 nevents*sizeof(quadlet_t)*connection->spec.dimension) <
2131                                 nevents*sizeof(quadlet_t)*connection->spec.dimension)
2132                 {
2133                         printError("MASTER RCV: Buffer overrun!\n");
2134                         connection->status.xruns++;
2135                         retval=RAW1394_ISO_DEFER;
2136                 } else {
2137                         retval=RAW1394_ISO_OK;
2138                         // we cannot offload midi encoding due to the need for a dbc value
2139                         freebob_streaming_decode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);
2140                 }
2141                
2142                 // keep the frame counter
2143                 connection->status.frames_left -= nevents;
2144                
2145                 // keep track of the total amount of events received
2146                 connection->status.events+=nevents;
2147
2148 #ifdef DEBUG   
2149                 connection->status.fdf=packet->fdf;
2150 #endif
2151                
2152         } else {
2153                 // discard packet
2154                 // can be important for sync though
2155         }
2156
2157         // one packet received
2158         connection->status.packets++;
2159
2160 #ifdef DEBUG
2161         if(packet->dbs) {
2162                 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;
2163                 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,
2164                         "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",
2165                         cycle,
2166                         channel, packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, length,
2167                         ((length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped,
2168                         connection->status.packets, connection->status.events, connection->status.frames_left,
2169                         nevents);
2170         }
2171 #endif
2172
2173         if((connection->status.frames_left<=0)) {
2174                 connection->pfd->events=0;
2175                 return RAW1394_ISO_DEFER;
2176         }
2177
2178         return retval;
2179 }
2180
2181
2182 static enum raw1394_iso_disposition
2183                 iso_slave_receive_handler(raw1394handle_t handle, unsigned char *data,
2184                                                                   unsigned int length, unsigned char channel,
2185                                                                   unsigned char tag, unsigned char sy, unsigned int cycle,
2186                                                                   unsigned int dropped)
2187 {
2188         enum raw1394_iso_disposition retval=RAW1394_ISO_OK;
2189         /* slave receive is easy if you assume that the connections are synced
2190         Synced connections have matched data rates, so just receiving and
2191         calling the rcv handler would suffice in this case. As the connection
2192         is externally matched to the master connection, the buffer fill will be ok.
2193         */
2194         /* TODO: implement correct SYT behaviour */
2195                
2196         freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);
2197         assert(connection);
2198        
2199         struct iec61883_packet *packet = (struct iec61883_packet *) data;
2200         assert(packet);
2201        
2202         // FIXME: dropped packets are very bad when transmitting and the other side is sync'ing on that!
2203         //connection->status.packets+=dropped;
2204         connection->status.dropped+=dropped;
2205
2206 #ifdef DEBUG   
2207         connection->status.last_cycle=cycle;
2208 #endif
2209
2210         if((packet->fmt == 0x10) && (packet->fdf != 0xFF) && (packet->dbs>0) && (length>=2*sizeof(quadlet_t))) {
2211                 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;
2212
2213 #ifdef DEBUG   
2214                 connection->status.fdf=packet->fdf;
2215 #endif
2216                
2217                 // add the data payload to the ringbuffer
2218
2219                 assert(connection->spec.dimension == packet->dbs);
2220
2221                 if (freebob_ringbuffer_write(
2222                                         connection->event_buffer,(char *)(data+8),
2223                                         nevents*sizeof(quadlet_t)*connection->spec.dimension) <
2224                         nevents*sizeof(quadlet_t)*connection->spec.dimension)
2225                 {
2226                         printError("SLAVE RCV: Buffer overrun!\n");
2227                         connection->status.xruns++;
2228                         retval=RAW1394_ISO_DEFER;
2229                 } else {
2230                         retval=RAW1394_ISO_OK;
2231                         // we cannot offload midi encoding due to the need for a dbc value
2232                         freebob_streaming_decode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);
2233                 }
2234
2235                 connection->status.frames_left-=nevents;
2236                
2237                 // keep track of the total amount of events received
2238                 connection->status.events+=nevents;
2239         } else {
2240                 // discard packet
2241                 // can be important for sync though
2242         }
2243
2244         // one packet received
2245         connection->status.packets++;
2246        
2247         if(packet->dbs) {
2248                 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,
2249                         "SLAVE RCV: CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d), DROPPED = %6d\n",
2250                         channel, packet->fdf,
2251                         packet->syt,
2252                         packet->dbs,
2253                         packet->dbc,
2254                         packet->fmt,
2255                         length,
2256                         ((length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped);
2257         }
2258                
2259                
2260         if((connection->status.frames_left<=0)) {
2261                 connection->pfd->events=0;
2262                 return RAW1394_ISO_DEFER;
2263         }
2264
2265         return retval;
2266 }
2267
2268 /**
2269  * The master transmit handler.
2270  *
2271  * This is the most difficult, because we have to generate timing information ourselves.
2272  *
2273  */
2274
2275 /*
2276  Includes code from libiec61883
2277  */
2278 static enum raw1394_iso_disposition
2279 iso_master_transmit_handler(raw1394handle_t handle,
2280                 unsigned char *data, unsigned int *length,
2281                 unsigned char *tag, unsigned char *sy,
2282                 int cycle, unsigned int dropped)
2283 {
2284         freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);
2285         assert(connection);
2286        
2287         struct iec61883_packet *packet = (struct iec61883_packet *) data;
2288         assert(packet);
2289         assert(length);
2290         assert(tag);
2291         assert(sy);     
2292        
2293         // construct the packet cip
2294         int nevents = iec61883_cip_fill_header (handle, &connection->status.cip, packet);
2295         int nsamples=0;
2296         int bytes_read;
2297        
2298 #ifdef DEBUG   
2299         connection->status.last_cycle=cycle;
2300
2301         if(packet->fdf != 0xFF) {
2302                 connection->status.fdf=packet->fdf;
2303         }
2304 #endif
2305
2306         enum raw1394_iso_disposition retval = RAW1394_ISO_OK;
2307
2308
2309
2310         if (nevents > 0) {
2311                 nsamples = nevents;
2312         }
2313         else {
2314                 if (connection->status.cip.mode == IEC61883_MODE_BLOCKING_EMPTY) {
2315                         nsamples = 0;
2316                 }
2317                 else {
2318                         nsamples = connection->status.cip.syt_interval;
2319                 }
2320         }
2321        
2322         // dropped packets are very bad when transmitting and the other side is sync'ing on that!
2323         connection->status.dropped += dropped;
2324                
2325         if (nsamples > 0) {
2326
2327                 assert(connection->spec.dimension == packet->dbs);
2328
2329                 if ((bytes_read=freebob_ringbuffer_read(connection->event_buffer,(char *)(data+8),nsamples*sizeof(quadlet_t)*connection->spec.dimension)) <
2330                                    nsamples*sizeof(quadlet_t)*connection->spec.dimension)
2331                 {
2332                         printError("MASTER XMT: Buffer underrun! (%d / %d) (%d / %d )\n",
2333                                            bytes_read,nsamples*sizeof(quadlet_t)*connection->spec.dimension,
2334                                            freebob_ringbuffer_read_space(connection->event_buffer),0);
2335                         connection->status.xruns++;
2336                         retval=RAW1394_ISO_DEFER;
2337                         nsamples=0;
2338                 } else {
2339                         retval=RAW1394_ISO_OK;
2340                         // we cannot offload midi encoding due to the need for a dbc value
2341                         freebob_streaming_encode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);
2342                 }
2343         }
2344        
2345         *length = nsamples * connection->spec.dimension * sizeof (quadlet_t) + 8;
2346         *tag = IEC61883_TAG_WITH_CIP;
2347         *sy = 0;
2348        
2349         // keep track of the total amount of events transmitted
2350         connection->status.events+=nsamples;
2351        
2352         connection->status.frames_left-=nsamples;
2353                
2354         // one packet transmitted
2355         connection->status.packets++;
2356
2357         if(packet->dbs) {
2358                 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,
2359                                                                 "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,
2360                                                                 connection->iso.iso_channel,  packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, *length,((*length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped,
2361                                                                 connection->status.packets, connection->status.events, connection->status.frames_left,
2362                                                                 nevents, nsamples);
2363         }
2364
2365         if((connection->status.frames_left<=0)) {
2366                 connection->pfd->events=0;
2367                 return RAW1394_ISO_DEFER;
2368         }
2369
2370         return retval;
2371
2372 }
2373
2374 static enum raw1394_iso_disposition
2375                 iso_slave_transmit_handler(raw1394handle_t handle,
2376                                                                    unsigned char *data, unsigned int *length,
2377                                                                    unsigned char *tag, unsigned char *sy,
2378                                                                    int cycle, unsigned int dropped)
2379 {
2380         freebob_connection_t *connection=(freebob_connection_t *) raw1394_get_userdata (handle);
2381         assert(connection);
2382        
2383         struct iec61883_packet *packet = (struct iec61883_packet *) data;
2384         assert(packet);
2385         assert(length);
2386         assert(tag);
2387         assert(sy);     
2388        
2389         // construct the packet cip
2390         struct iec61883_cip old_cip;
2391         memcpy(&old_cip,&connection->status.cip,sizeof(struct iec61883_cip));
2392        
2393         int nevents = iec61883_cip_fill_header (handle, &connection->status.cip, packet);
2394         int nsamples=0;
2395         int bytes_read;
2396
2397 #ifdef DEBUG   
2398         connection->status.last_cycle=cycle;
2399
2400         if(packet->fdf != 0xFF) {
2401                 connection->status.fdf=packet->fdf;
2402         }
2403 #endif
2404
2405         enum raw1394_iso_disposition retval = RAW1394_ISO_OK;
2406
2407
2408         if (nevents > 0) {
2409                 nsamples = nevents;
2410         }
2411         else {
2412                 if (connection->status.cip.mode == IEC61883_MODE_BLOCKING_EMPTY) {
2413                         nsamples = 0;
2414                 }
2415                 else {
2416                         nsamples = connection->status.cip.syt_interval;
2417                 }
2418         }
2419        
2420         // dropped packets are very bad when transmitting and the other side is sync'ing on that!
2421         //connection->status.packets+=dropped;
2422         connection->status.dropped += dropped;
2423                
2424         if (nsamples > 0) {
2425                 int bytes_to_read=nsamples*sizeof(quadlet_t)*connection->spec.dimension;
2426
2427                 assert(connection->spec.dimension == packet->dbs);
2428
2429                 if ((bytes_read=freebob_ringbuffer_read(connection->event_buffer,(char *)(data+8),bytes_to_read)) <
2430                         bytes_to_read)
2431                 {
2432                         /* there is no more data in the ringbuffer */
2433                        
2434                         /* If there are already more than on period
2435                         * of frames transfered to the XMIT buffer, there is no xrun.
2436                         *
2437                         */
2438                         if(connection->status.frames_left<=0) {
2439                                 // we stop processing this untill the next period boundary
2440                                 // that's when new data is ready
2441                                
2442                                 connection->pfd->events=0;
2443                                
2444                                 // reset the cip to the old value
2445                                 memcpy(&connection->status.cip,&old_cip,sizeof(struct iec61883_cip));
2446
2447                                 // retry this packet
2448                                 retval=RAW1394_ISO_AGAIN;
2449 //                              retval=RAW1394_ISO_DEFER;
2450                                 nsamples=0;
2451                         } else {
2452                                 printError("SLAVE XMT : Buffer underrun! %d (%d / %d) (%d / %d )\n",
2453                                            connection->status.frames_left, bytes_read,bytes_to_read,
2454                                            freebob_ringbuffer_read_space(connection->event_buffer),0);
2455                                 connection->status.xruns++;
2456                                 retval=RAW1394_ISO_DEFER;
2457                                 nsamples=0;
2458                         }
2459                 } else {
2460                         retval=RAW1394_ISO_OK;
2461                         // we cannot offload midi encoding due to the need for a dbc value
2462                         freebob_streaming_encode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);
2463                 }
2464         }
2465        
2466         *length = nsamples * connection->spec.dimension * sizeof (quadlet_t) + 8;
2467         *tag = IEC61883_TAG_WITH_CIP;
2468         *sy = 0;
2469        
2470         // keep track of the total amount of events transmitted
2471         connection->status.events+=nsamples;
2472        
2473         connection->status.frames_left-=nsamples;
2474                
2475         // one packet transmitted
2476         connection->status.packets++;
2477
2478         if(packet->dbs) {
2479                 debugPrintWithTimeStamp(DEBUG_LEVEL_HANDLERS_LOWLEVEL,
2480                                                                 "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,
2481                                                                 connection->iso.iso_channel,  packet->fdf,packet->syt,packet->dbs,packet->dbc,packet->fmt, *length,((*length / sizeof (quadlet_t)) - 2)/packet->dbs, dropped,
2482                                                                 connection->status.packets, connection->status.events, connection->status.frames_left,
2483                                                                 nevents, nsamples);
2484         }
2485
2486         if((connection->status.frames_left<=0)) {
2487                 connection->pfd->events=0;
2488                 return RAW1394_ISO_DEFER;
2489         }
2490
2491         return retval;
2492
2493 }
2494
2495 /*
2496  * Decoders and encoders
2497  */
2498 #ifdef ENABLE_SSE
2499 typedef float v4sf __attribute__ ((vector_size (16)));
2500 typedef int v4si __attribute__ ((vector_size (16)));
2501 typedef int v2si __attribute__ ((vector_size (8)));
2502
2503 static inline int 
2504 freebob_decode_events_to_stream(freebob_connection_t *connection,
2505                                                                 freebob_stream_t *stream,
2506                                                                 quadlet_t* events,
2507                                                                 unsigned int nsamples,
2508                                                                 unsigned int dbc
2509                                                                 ) {
2510         quadlet_t *target_event;
2511         int do_ringbuffer_write=0;
2512        
2513         assert (stream);
2514         assert (connection);
2515         assert (events);
2516         assert (stream->spec.position < connection->spec.dimension);
2517                
2518         freebob_sample_t *buffer=NULL;
2519         float *floatbuff=NULL;
2520
2521         int dimension=connection->spec.dimension;
2522        
2523         static const float multiplier = 1.0f / (float)(0x7FFFFF);
2524         static const float sse_multiplier[4] __attribute__((aligned(16))) = {
2525                 1.0f / (float)(0x7FFFFF),
2526                 1.0f / (float)(0x7FFFFF),
2527                 1.0f / (float)(0x7FFFFF),
2528                 1.0f / (float)(0x7FFFFF)
2529         };
2530         unsigned int tmp[4];
2531
2532         assert(stream->user_buffer);
2533        
2534         switch(stream->buffer_type) {
2535                 case freebob_buffer_type_per_stream:
2536                 default:
2537                         // use the preallocated buffer (at init time)
2538                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2539                        
2540                         do_ringbuffer_write=1;
2541                         break;
2542                                
2543                 case freebob_buffer_type_uint24:
2544                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2545                        
2546                         do_ringbuffer_write=0;
2547                         break;
2548                                
2549                 case freebob_buffer_type_float:
2550                         floatbuff=((float *)(stream->user_buffer))+stream->user_buffer_position;
2551                        
2552                         do_ringbuffer_write=0;
2553                         break;
2554         }
2555        
2556         int j=0;
2557         int written=0;
2558        
2559         if (stream->spec.format== IEC61883_STREAM_TYPE_MBLA) {
2560                 target_event=(quadlet_t *)(events + stream->spec.position);
2561
2562                 // TODO: convert this into function pointer based
2563                 switch(stream->buffer_type) {
2564                         default:
2565                         case freebob_buffer_type_uint24:
2566                                 for(j = 0; j < nsamples; j += 1) { // decode max nsamples
2567                                         *(buffer)=(ntohl((*target_event) ) & 0x00FFFFFF);
2568                                         buffer++;
2569                                         target_event+=dimension;
2570                                 }
2571                                 break;
2572                         case freebob_buffer_type_float:
2573                                 j=0;
2574                                 if(nsamples>3) {
2575                                         for(j = 0; j < nsamples-3; j += 4) {
2576                                                 tmp[0] = ntohl(*target_event);
2577                                                 target_event += dimension;
2578                                                 tmp[1] = ntohl(*target_event);
2579                                                 target_event += dimension;
2580                                                 tmp[2] = ntohl(*target_event);
2581                                                 target_event += dimension;
2582                                                 tmp[3] = ntohl(*target_event);
2583                                                 target_event += dimension;
2584                                                 asm("pslld $8, %[in2]\n\t" // sign extend 24th bit
2585                                                                 "pslld $8, %[in1]\n\t"
2586                                                                 "psrad $8, %[in2]\n\t"
2587                                                                 "psrad $8, %[in1]\n\t"
2588                                                                 "cvtpi2ps %[in2], %%xmm0\n\t"
2589                                                                 "movlhps %%xmm0, %%xmm0\n\t"
2590                                                                 "cvtpi2ps %[in1], %%xmm0\n\t"
2591                                                                 "mulps %[ssemult], %%xmm0\n\t"
2592                                                                 "movups %%xmm0, %[floatbuff]"
2593                                                         : [floatbuff] "=m" (*(v4sf*)floatbuff)
2594                                                         : [in1] "y" (*(v2si*)tmp),
2595                                                 [in2] "y" (*(v2si*)(tmp+2)),
2596                                                 [ssemult] "x" (*(v4sf*)sse_multiplier)
2597                                                         : "xmm0");
2598                                                 floatbuff += 4;
2599                                         }
2600                                 }
2601                                 for(; j < nsamples; ++j) { // decode max nsamples
2602                                         unsigned int v = ntohl(*target_event) & 0x00FFFFFF;
2603                                         // sign-extend highest bit of 24-bit int
2604                                         int tmp = (int)(v << 8) / 256;
2605                                         *floatbuff = tmp * multiplier;
2606
2607                                         floatbuff++;
2608                                         target_event += dimension;
2609                                 }
2610                                 asm volatile("emms");
2611                                
2612                                 break;
2613                 }
2614
2615 //              fprintf(stderr,"rb write [%02d: %08p %08p]\n",stream->spec.position, stream, stream->buffer);
2616        
2617 //      fprintf(stderr,"rb write [%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, written);
2618                 if(do_ringbuffer_write) {
2619                         // reset the buffer pointer
2620                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2621                         written=freebob_ringbuffer_write(stream->buffer, (char *)(buffer), nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t);
2622                 } else {
2623                         written=nsamples;
2624                 }
2625                
2626 //      fprintf(stderr,"rb write1[%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, written);
2627                
2628                 return written;
2629        
2630         } else if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {
2631                 return nsamples; // for midi streams we always indicate a full write
2632        
2633         } else {//if (stream->spec.format == IEC61883_STREAM_TYPE_SPDIF) {
2634                 return nsamples; // for unsupported we always indicate a full read
2635        
2636         }
2637        
2638         return 0;
2639
2640
2641 }
2642
2643 static inline int
2644 freebob_encode_stream_to_events(freebob_connection_t *connection,
2645                                                                 freebob_stream_t *stream,
2646                                                                 quadlet_t* events,
2647                                                                 unsigned int nsamples,
2648                                                                 unsigned int dbc
2649                                                                 ) {
2650         quadlet_t *target_event;
2651         //freebob_sample_t buff[nsamples];
2652         int do_ringbuffer_read=0;
2653        
2654         freebob_sample_t *buffer=NULL;
2655         float *floatbuff=NULL;
2656
2657         const float multiplier = (float)(0x7FFFFF00);
2658         static const float sse_multiplier[4] __attribute__((aligned(16))) = {
2659                 (float)(0x7FFFFF00),
2660                 (float)(0x7FFFFF00),
2661                 (float)(0x7FFFFF00),
2662                 (float)(0x7FFFFF00)
2663         };
2664
2665         static const int sse_mask[4] __attribute__((aligned(16))) = {
2666                 0x40000000,  0x40000000,  0x40000000,  0x40000000
2667         };
2668
2669         unsigned int out[4];   
2670        
2671         int dimension=connection->spec.dimension;
2672        
2673         unsigned int j=0;
2674         unsigned int read=0;
2675
2676         assert (stream);
2677         assert (connection);
2678         assert (events);
2679         assert (stream->spec.position < connection->spec.dimension);
2680        
2681         switch(stream->buffer_type) {
2682                 case freebob_buffer_type_per_stream:
2683                 default:
2684 //                      assert(nsamples < dev->options.period_size);
2685                         // use the preallocated buffer (at init time)
2686                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2687                        
2688                         do_ringbuffer_read=1;
2689                         break;
2690                                
2691                 case freebob_buffer_type_uint24:
2692                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2693                        
2694                         do_ringbuffer_read=0;
2695                         break;
2696                                
2697                 case freebob_buffer_type_float:
2698                         floatbuff=((float *)(stream->user_buffer))+stream->user_buffer_position;
2699                        
2700                         do_ringbuffer_read=0;
2701                         break;
2702         }
2703        
2704        
2705         if(stream->spec.format == IEC61883_STREAM_TYPE_MBLA) { // MBLA
2706                 target_event=(quadlet_t *)(events + (stream->spec.position));
2707                
2708                 if(do_ringbuffer_read) {
2709                         read=freebob_ringbuffer_read(stream->buffer, (char *)buffer, nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t);
2710                 } else {
2711                         read=nsamples;
2712                 }
2713                
2714                 // TODO: convert this into function pointer based
2715                 switch(stream->buffer_type) {
2716                         default:
2717                         case freebob_buffer_type_uint24:
2718                                 for(j = 0; j < read; j += 1) { // decode max nsamples
2719                                         *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);
2720                                         buffer++;
2721                                         target_event+=dimension;
2722                                        
2723                 //                      fprintf(stderr,"[%03d, %02d: %08p %08X %08X]\n",j, stream->spec.position, target_event, *target_event, *buffer);
2724
2725                                 }
2726                                 break;
2727                         case freebob_buffer_type_float:
2728 /*                              for(j = 0; j < read; j += 1) { // decode max nsamples
2729                                         // don't care for overflow
2730                                         float v = *floatbuff * multiplier;  // v: -231 .. 231
2731                                         unsigned int tmp = ((int)v);
2732                                         *target_event = htonl((tmp >> 8) | 0x40000000);
2733                                        
2734                                         floatbuff++;
2735                                         target_event += connection->spec.dimension;
2736                                 }*/
2737                                 j=0;
2738                                 if(read>3) {
2739                                         for (j = 0; j < read-3; j += 4) {
2740                                                 asm("movups %[floatbuff], %%xmm0\n\t"
2741                                                                 "mulps %[ssemult], %%xmm0\n\t"
2742                                                                 "cvttps2pi %%xmm0, %[out1]\n\t"
2743                                                                 "movhlps %%xmm0, %%xmm0\n\t"
2744                                                                 "psrld $8, %[out1]\n\t"
2745                                                                 "cvttps2pi %%xmm0, %[out2]\n\t"
2746                                                                 "por %[mmxmask], %[out1]\n\t"
2747                                                                 "psrld $8, %[out2]\n\t"
2748                                                                 "por %[mmxmask], %[out2]\n\t"
2749                                                         : [out1] "=&y" (*(v2si*)&out[0]),
2750                                                 [out2] "=&y" (*(v2si*)&out[2])
2751                                                         : [floatbuff] "m" (*(v4sf*)floatbuff),
2752                                                 [ssemult] "x" (*(v4sf*)sse_multiplier),
2753                                                 [mmxmask] "y" (*(v2si*)sse_mask)
2754                                                         : "xmm0");
2755                                                 floatbuff += 4;
2756                                                 *target_event = htonl(out[0]);
2757                                                 target_event += dimension;
2758                                                 *target_event = htonl(out[1]);
2759                                                 target_event += dimension;
2760                                                 *target_event = htonl(out[2]);
2761                                                 target_event += dimension;
2762                                                 *target_event = htonl(out[3]);
2763                                                 target_event += dimension;
2764                                         }
2765                                 }
2766                                 for(; j < read; ++j) {
2767                                 // don't care for overflow
2768                                         float v = *floatbuff * multiplier;  // v: -231 .. 231
2769                                         unsigned int tmp = (int)v;
2770                                         *target_event = htonl((tmp >> 8) | 0x40000000);
2771                
2772                                         floatbuff++;
2773                                         target_event += dimension;
2774                                 }
2775
2776                                 asm volatile("emms");
2777                                 break;
2778                 }
2779                
2780                 /*             
2781                 for(j = 0; j < nsamples; j+=1) {
2782                         *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);
2783                         buffer++;
2784                         target_event+=connection->spec.dimension;
2785                 }
2786                 */
2787                
2788                 return read;
2789                
2790         } else if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {
2791                 return nsamples; // for midi we always indicate a full read
2792        
2793         } else { //if (stream->spec.format == IEC61883_STREAM_TYPE_SPDIF) {
2794                 return nsamples; // for unsupported we always indicate a full read
2795        
2796         }
2797         return 0;
2798
2799 }
2800
2801 #else
2802
2803 static inline int 
2804 freebob_decode_events_to_stream(freebob_connection_t *connection,
2805                                                                 freebob_stream_t *stream,
2806                                                                 quadlet_t* events,
2807                                                                 unsigned int nsamples,
2808                                                                 unsigned int dbc
2809                                                                 ) {
2810         quadlet_t *target_event;
2811         int do_ringbuffer_write=0;
2812        
2813         assert (stream);
2814         assert (connection);
2815         assert (events);
2816         assert (stream->spec.position < connection->spec.dimension);
2817                
2818         freebob_sample_t *buffer=NULL;
2819         float *floatbuff=NULL;
2820
2821         const float multiplier = 1.0f / (float)(0x7FFFFF);
2822        
2823         int dimension=connection->spec.dimension;
2824        
2825         assert(stream->user_buffer);
2826        
2827         switch(stream->buffer_type) {
2828                 case freebob_buffer_type_per_stream:
2829                 default:
2830 //                      assert(nsamples < dev->options.period_size);
2831                        
2832                         // use the preallocated buffer (at init time)
2833                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2834                        
2835                         do_ringbuffer_write=1;
2836                         break;
2837                                
2838                 case freebob_buffer_type_uint24:
2839                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2840                        
2841                         do_ringbuffer_write=0;
2842                         break;
2843                                
2844                 case freebob_buffer_type_float:
2845                         floatbuff=((float *)(stream->user_buffer))+stream->user_buffer_position;
2846                        
2847                         do_ringbuffer_write=0;
2848                         break;
2849         }
2850        
2851         int j=0;
2852         int written=0;
2853        
2854         if (stream->spec.format== IEC61883_STREAM_TYPE_MBLA) {
2855                 target_event=(quadlet_t *)(events + stream->spec.position);
2856
2857                 // TODO: convert this into function pointer based
2858                 switch(stream->buffer_type) {
2859                         default:
2860                         case freebob_buffer_type_uint24:
2861                                 for(j = 0; j < nsamples; j += 1) { // decode max nsamples
2862                                         *(buffer)=(ntohl((*target_event) ) & 0x00FFFFFF);
2863                 //                      fprintf(stderr,"[%03d, %02d: %08p %08X %08X]\n",j, stream->spec.position, target_event, *target_event, *buffer);
2864                                         buffer++;
2865                                         target_event+=dimension;
2866                                 }
2867                                 break;
2868                         case freebob_buffer_type_float:
2869                                 for(j = 0; j < nsamples; j += 1) { // decode max nsamples               
2870
2871                                         unsigned int v = ntohl(*target_event) & 0x00FFFFFF;
2872                                         // sign-extend highest bit of 24-bit int
2873                                         int tmp = (int)(v << 8) / 256;
2874                
2875                                         *floatbuff = tmp * multiplier;
2876                                
2877                                         floatbuff++;
2878                                         target_event+=dimension;
2879                                 }
2880                                 break;
2881                 }
2882
2883 //              fprintf(stderr,"rb write [%02d: %08p %08p]\n",stream->spec.position, stream, stream->buffer);
2884        
2885 //      fprintf(stderr,"rb write [%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, written);
2886                 if(do_ringbuffer_write) {
2887                         // reset the buffer pointer
2888                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2889                         written=freebob_ringbuffer_write(stream->buffer, (char *)(buffer), nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t);
2890                 } else {
2891                         written=nsamples;
2892                 }
2893                
2894 //      fprintf(stderr,"rb write1[%02d: %08p %08p %08X, %d, %d]\n",stream->spec.position, stream, stream->buffer, *buffer, nsamples, written);
2895                
2896                 return written;
2897        
2898         } else if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {
2899                 return nsamples; // for midi streams we always indicate a full write
2900        
2901         } else {//if (stream->spec.format == IEC61883_STREAM_TYPE_SPDIF) {
2902                 return nsamples; // for unsupported we always indicate a full read
2903        
2904         }
2905        
2906         return 0;
2907
2908
2909 }
2910
2911 static inline int
2912 freebob_encode_stream_to_events(freebob_connection_t *connection,
2913                                                                 freebob_stream_t *stream,
2914                                                                 quadlet_t* events,
2915                                                                 unsigned int nsamples,
2916                                                                 unsigned int dbc
2917                                                                 ) {
2918         quadlet_t *target_event;
2919         //freebob_sample_t buff[nsamples];
2920         int do_ringbuffer_read=0;
2921        
2922         freebob_sample_t *buffer=NULL;
2923         float *floatbuff=NULL;
2924
2925         const float multiplier = (float)(0x7FFFFF00);
2926         int dimension=connection->spec.dimension;
2927        
2928         unsigned int j=0;
2929         unsigned int read=0;
2930
2931         assert (stream);
2932         assert (connection);
2933         assert (events);
2934         assert (stream->spec.position < connection->spec.dimension);
2935        
2936         switch(stream->buffer_type) {
2937                 case freebob_buffer_type_per_stream:
2938                 default:
2939 //                      assert(nsamples < dev->options.period_size);
2940                         // use the preallocated buffer (at init time)
2941                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2942                        
2943                         do_ringbuffer_read=1;
2944                         break;
2945                                
2946                 case freebob_buffer_type_uint24:
2947                         buffer=((freebob_sample_t *)(stream->user_buffer))+stream->user_buffer_position;
2948                        
2949                         do_ringbuffer_read=0;
2950                         break;
2951                                
2952                 case freebob_buffer_type_float:
2953                         floatbuff=((float *)(stream->user_buffer))+stream->user_buffer_position;
2954                        
2955                         do_ringbuffer_read=0;
2956                         break;
2957         }
2958        
2959        
2960         if(stream->spec.format == IEC61883_STREAM_TYPE_MBLA) { // MBLA
2961                 target_event=(quadlet_t *)(events + (stream->spec.position));
2962                
2963                 if(do_ringbuffer_read) {
2964                         read=freebob_ringbuffer_read(stream->buffer, (char *)buffer, nsamples*sizeof(freebob_sample_t))/sizeof(freebob_sample_t);
2965                 } else {
2966                         read=nsamples;
2967                 }
2968                
2969                 // TODO: convert this into function pointer based
2970                 switch(stream->buffer_type) {
2971                         default:
2972                         case freebob_buffer_type_uint24:
2973                                 for(j = 0; j < read; j += 1) { // decode max nsamples
2974                                         *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);
2975                                         buffer++;
2976                                         target_event+=dimension;
2977                                        
2978                 //                      fprintf(stderr,"[%03d, %02d: %08p %08X %08X]\n",j, stream->spec.position, target_event, *target_event, *buffer);
2979
2980                                 }
2981                                 break;
2982                         case freebob_buffer_type_float:
2983                                 for(j = 0; j < read; j += 1) { // decode max nsamples
2984                                         // don't care for overflow
2985                                         float v = *floatbuff * multiplier;  // v: -231 .. 231
2986                                         unsigned int tmp = ((int)v);
2987                                         *target_event = htonl((tmp >> 8) | 0x40000000);
2988                                        
2989                                         floatbuff++;
2990                                         target_event += dimension;
2991                                 }
2992                                 break;
2993                 }
2994                
2995                 /*             
2996                 for(j = 0; j < nsamples; j+=1) {
2997                         *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);
2998                         buffer++;
2999                         target_event+=connection->spec.dimension;
3000                 }
3001                 */
3002                
3003                 return read;
3004                
3005         } else if (stream->spec.format == IEC61883_STREAM_TYPE_MIDI) {
3006                 return nsamples; // for midi we always indicate a full read
3007        
3008         } else { //if (stream->spec.format == IEC61883_STREAM_TYPE_SPDIF) {
3009                 return nsamples; // for unsupported we always indicate a full read
3010        
3011         }
3012         return 0;
3013
3014 }
3015 #endif
3016
3017 /*
3018  * write received events to the stream ringbuffers.
3019  */
3020
3021 int freebob_am824_recv(char *data,
3022                                            int nevents, unsigned int offset, unsigned int dbc,
3023                                freebob_connection_t *connection)
3024 {
3025         int xrun=0;
3026         unsigned int i=0;
3027        
3028         for(i = 0; i < connection->nb_streams; i++) {
3029                 freebob_stream_t *stream = &(connection->streams[i]);
3030                 size_t written=0;
3031                
3032                 assert(stream);
3033                
3034                 stream->user_buffer_position=offset;
3035                
3036                 debugPrintShort(DEBUG_LEVEL_HANDLERS,"[%d: %d ",i,freebob_ringbuffer_write_space(stream->buffer));
3037                 written = freebob_decode_events_to_stream(
3038                         connection,
3039                         stream,
3040                         (quadlet_t *)data,
3041                         nevents,
3042                         dbc
3043                         );
3044
3045                 if (written < nevents) {
3046                         xrun++;
3047                 }
3048                
3049                 debugPrintShort(DEBUG_LEVEL_HANDLERS, "%d %d]",written,freebob_ringbuffer_write_space(stream->buffer));
3050         }
3051        
3052 //      connection->status.frames_left-=nevents;
3053                
3054         debugPrintShort(DEBUG_LEVEL_HANDLERS, "\n");
3055        
3056         return xrun;
3057 }
3058
3059 /*
3060  * get xmit events from ringbuffer
3061  */
3062
3063 int freebob_am824_xmit( char *data,
3064                                                 int nevents, unsigned int offset, unsigned int dbc,
3065                                                 freebob_connection_t *connection)
3066 {
3067         int xrun=0;
3068         unsigned int i=0;
3069        
3070         for(i = 0; i < connection->nb_streams; i++) {
3071                 freebob_stream_t *stream = &(connection->streams[i]);
3072                 size_t read=0;
3073                
3074                 assert(stream);
3075                 debugPrintShort(DEBUG_LEVEL_HANDLERS, "[%d: %d ",i,freebob_ringbuffer_read_space(stream->buffer));
3076                
3077                 stream->user_buffer_position=offset;
3078                
3079                 read = freebob_encode_stream_to_events(
3080                         connection,
3081                         stream,
3082                         (quadlet_t *)data,
3083                         nevents,
3084                         dbc
3085                         );
3086                
3087                 debugPrintShort(DEBUG_LEVEL_HANDLERS, "%d %d]",read,freebob_ringbuffer_read_space(stream->buffer));
3088
3089                 if (read < nevents) {
3090                         xrun++;
3091                 }
3092                
3093         }
3094         debugPrintShort(DEBUG_LEVEL_HANDLERS, "\n");
3095        
3096 //      connection->status.frames_left-=nevents;
3097        
3098         return xrun;
3099 }
3100
3101 void *freebob_streaming_watchdog_thread (void *arg)
3102 {
3103         freebob_device_t *dev = (freebob_device_t *) arg;
3104
3105         dev->watchdog_check = 0;
3106
3107         while (1) {
3108                 sleep (2);
3109                 if (dev->watchdog_check == 0) {
3110
3111                         printError("watchdog: timeout");
3112
3113                         /* kill our process group, try to get a dump */
3114                         kill (-getpgrp(), SIGABRT);
3115                         /*NOTREACHED*/
3116                         exit (1);
3117                 }
3118                 dev->watchdog_check = 0;
3119         }
3120 }
3121
3122 int freebob_streaming_start_watchdog (freebob_device_t *dev)
3123 {
3124         int watchdog_priority = dev->packetizer.priority + 10;
3125         int max_priority = sched_get_priority_max (SCHED_FIFO);
3126
3127         debugPrint(DEBUG_LEVEL_STARTUP, "Starting Watchdog...\n");
3128        
3129         if ((max_priority != -1) &&
3130                         (max_priority < watchdog_priority))
3131                 watchdog_priority = max_priority;
3132        
3133         if (freebob_streaming_create_thread (dev, &dev->watchdog_thread, watchdog_priority,
3134                 TRUE, freebob_streaming_watchdog_thread, dev)) {
3135                         printError ("cannot start watchdog thread");
3136                         return -1;
3137                 }
3138
3139         return 0;
3140 }
3141
3142 void freebob_streaming_stop_watchdog (freebob_device_t *dev)
3143 {
3144         debugPrint(DEBUG_LEVEL_STARTUP, "Stopping Watchdog...\n");
3145        
3146         pthread_cancel (dev->watchdog_thread);
3147         pthread_join (dev->watchdog_thread, NULL);
3148 }
Note: See TracBrowser for help on using the browser.