root/branches/libfreebob-2.0/src/libstreaming/MotuStreamProcessor.cpp

Revision 268, 33.3 kB (checked in by jwoithe, 18 years ago)

StreamProcessor::m_framecounter is now signed again, since the ability to go
negative is utilised for some devices in certain circumstances.

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,2006 Pieter Palmers <pieterpalmers@users.sourceforge.net>
10  *   Copyright (C) 2005,2006 Pieter Palmers <pieterpalmers@users.sourceforge.net>
11  *
12  *   This program is free software {} you can redistribute it and/or modify
13  *   it under the terms of the GNU General Public License as published by
14  *   the Free Software Foundation {} either version 2 of the License, or
15  *   (at your option) any later version.
16  *
17  *   This program is distributed in the hope that it will be useful,
18  *   but WITHOUT ANY WARRANTY {} without even the implied warranty of
19  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *   GNU General Public License for more details.
21  *
22  *   You should have received a copy of the GNU General Public License
23  *   along with this program {} if not, write to the Free Software
24  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  *
27  *
28  */
29
30
31 #include "MotuStreamProcessor.h"
32 #include "Port.h"
33 #include "MotuPort.h"
34
35 #include <netinet/in.h>
36
37 namespace FreebobStreaming {
38
39 IMPL_DEBUG_MODULE( MotuTransmitStreamProcessor, MotuTransmitStreamProcessor, DEBUG_LEVEL_NORMAL );
40 IMPL_DEBUG_MODULE( MotuReceiveStreamProcessor, MotuReceiveStreamProcessor, DEBUG_LEVEL_NORMAL );
41
42 // A macro to extract specific bits from a native endian quadlet
43 #define get_bits(_d,_start,_len) (((_d)>>((_start)-(_len)+1)) & ((1<<(_len))-1))
44
45
46 /* transmit */
47 MotuTransmitStreamProcessor::MotuTransmitStreamProcessor(int port, int framerate)
48         : TransmitStreamProcessor(port, framerate),m_dimension(0) {
49
50
51 }
52
53 MotuTransmitStreamProcessor::~MotuTransmitStreamProcessor() {
54         freebob_ringbuffer_free(m_event_buffer);
55         free(m_cluster_buffer);
56 }
57
58 bool MotuTransmitStreamProcessor::init() {
59
60         debugOutput( DEBUG_LEVEL_VERBOSE, "Initializing (%p)...\n");
61         // call the parent init
62         // this has to be done before allocating the buffers,
63         // because this sets the buffersizes from the processormanager
64         if(!TransmitStreamProcessor::init()) {
65                 debugFatal("Could not do base class init (%p)\n",this);
66                 return false;
67         }
68        
69
70         return true;
71 }
72
73 void MotuTransmitStreamProcessor::setVerboseLevel(int l) {
74         setDebugLevel(l); // sets the debug level of the current object
75         TransmitStreamProcessor::setVerboseLevel(l); // also set the level of the base class
76 }
77
78
79 enum raw1394_iso_disposition
80 MotuTransmitStreamProcessor::getPacket(unsigned char *data, unsigned int *length,
81                       unsigned char *tag, unsigned char *sy,
82                       int cycle, unsigned int dropped, unsigned int max_length) {
83
84         enum raw1394_iso_disposition retval = RAW1394_ISO_OK;
85        
86         // signal that we are running
87         // this is to allow the manager to wait untill all streams are up&running
88         // it can take some time before the devices start to transmit.
89         // if we would transmit ourselves, we'd have instant buffer underrun
90         // this works in cooperation with the m_disabled value
91        
92         // TODO: add code here to detect that a stream is running
93         // NOTE: xmit streams are most likely 'always' ready
94         m_running=true;
95        
96         // don't process the stream when it is not enabled.
97         // however, maybe we do have to generate (semi) valid packets
98         if(m_disabled) {
99                 *length = 0;
100                 *tag = 1; // TODO: is this correct for MOTU?
101                 *sy = 0;
102                 return RAW1394_ISO_OK;
103         }
104
105 // FIXME: for now always just return NULL packets
106 *length = 0;
107 *tag = 0;
108 *sy = 0;
109 return RAW1394_ISO_OK;
110        
111     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "get packet...\n");
112        
113         // construct the packet cip
114
115     // TODO: calculate read_size here.
116     // note: an 'event' is one sample from all channels + possibly other midi and control data
117     int nevents=0; // TODO: determine
118         unsigned int read_size=nevents*m_dimension*sizeof(quadlet_t); // assumes each channel takes one quadlet
119
120     // we read the packet data from a ringbuffer, because of efficiency
121     // that allows us to construct the packets one period at once
122         if ((freebob_ringbuffer_read(m_event_buffer,(char *)(data+8),read_size)) <
123                                 read_size)
124         {
125         /* there is no more data in the ringbuffer */
126         debugWarning("Transmit buffer underrun (cycle %d, FC=%d, PC=%d)\n",
127                  cycle, m_framecounter, m_handler->getPacketCount());
128        
129         // signal underrun
130         m_xruns++;
131
132         retval=RAW1394_ISO_DEFER; // make raw1394_loop_iterate exit its inner loop
133         *length=0;
134         nevents=0;
135
136     } else {
137         retval=RAW1394_ISO_OK;
138         *length = read_size + 8;
139        
140         // process all ports that should be handled on a per-packet base
141         // this is MIDI for AMDTP (due to the need of DBC, which is lost
142         // when putting the events in the ringbuffer)
143         // for motu this might also be control data, however as control
144         // data isn't time specific I would also include it in the period
145         // based processing
146        
147         int dbc=0;//get this from your packet, if you need it. otherwise change encodePacketPorts
148         if (!encodePacketPorts((quadlet_t *)(data+8), nevents, dbc)) {
149             debugWarning("Problem encoding Packet Ports\n");
150         }
151     }
152    
153     *tag = 1; // TODO: is this correct for MOTU?
154     *sy = 0;
155    
156     // update the frame counter
157     incrementFrameCounter(nevents);
158     // keep this at the end, because otherwise the raw1394_loop_iterate functions inner loop
159     // keeps requesting packets, that are not nescessarily ready
160     if(m_framecounter>(signed int)m_period) {
161        retval=RAW1394_ISO_DEFER;
162     }
163        
164     return retval;
165
166 }
167
168 bool MotuTransmitStreamProcessor::isOnePeriodReady()
169 {
170      // TODO: this is the way you can implement sync
171      //       only when this returns true, one period will be
172      //       transferred to the audio api side.
173      //       you can delay this moment as long as you
174      //       want (provided that there is enough buffer space)
175      
176      // this implementation just waits until there is one period of samples
177      // transmitted from the buffer
178      return (m_framecounter > (signed int)m_period);
179 }
180  
181 bool MotuTransmitStreamProcessor::prefill() {
182     // this is needed because otherwise there is no data to be
183     // sent when the streaming starts
184    
185     int i=m_nb_buffers;
186     while(i--) {
187         if(!transferSilence(m_period)) {
188             debugFatal("Could not prefill transmit stream\n");
189             return false;
190         }
191     }
192    
193     return true;
194    
195 }
196
197 bool MotuTransmitStreamProcessor::reset() {
198
199     debugOutput( DEBUG_LEVEL_VERBOSE, "Resetting...\n");
200
201     // reset the event buffer, discard all content
202     freebob_ringbuffer_reset(m_event_buffer);
203    
204     // reset all non-device specific stuff
205     // i.e. the iso stream and the associated ports
206     if(!TransmitStreamProcessor::reset()) {
207         debugFatal("Could not do base class reset\n");
208         return false;
209     }
210
211     // we should prefill the event buffer
212     if (!prefill()) {
213         debugFatal("Could not prefill buffers\n");
214         return false;   
215     }
216
217     return true;
218 }
219
220 bool MotuTransmitStreamProcessor::prepare() {
221    
222     debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing...\n");
223    
224     // prepare all non-device specific stuff
225     // i.e. the iso stream and the associated ports
226     if(!TransmitStreamProcessor::prepare()) {
227         debugFatal("Could not prepare base class\n");
228         return false;
229     }
230
231         m_PeriodStat.setName("XMT PERIOD");
232         m_PacketStat.setName("XMT PACKET");
233         m_WakeupStat.setName("XMT WAKEUP");
234    
235     // allocate the event buffer
236     unsigned int ringbuffer_size_frames=m_nb_buffers * m_period;
237    
238     if( !(m_event_buffer=freebob_ringbuffer_create(
239             (m_dimension * ringbuffer_size_frames) * sizeof(quadlet_t)))) {
240         debugFatal("Could not allocate memory event ringbuffer");
241         return false;
242     }
243
244     // allocate the temporary cluster buffer
245     // this is needed for the efficient transfer() routine
246     // it's size has to be equal to one 'event'
247     if( !(m_cluster_buffer=(char *)calloc(m_dimension,sizeof(quadlet_t)))) {
248         debugFatal("Could not allocate temporary cluster buffer");
249         freebob_ringbuffer_free(m_event_buffer);
250         return false;
251     }
252
253     // set the parameters of ports we can:
254     // we want the audio ports to be period buffered,
255     // and the midi ports to be packet buffered
256     for ( PortVectorIterator it = m_Ports.begin();
257           it != m_Ports.end();
258           ++it )
259     {
260         debugOutput(DEBUG_LEVEL_VERBOSE, "Setting up port %s\n",(*it)->getName().c_str());
261         if(!(*it)->setBufferSize(m_period)) {
262             debugFatal("Could not set buffer size to %d\n",m_period);
263             return false;
264         }
265        
266        
267         switch ((*it)->getPortType()) {
268             case Port::E_Audio:
269                 if(!(*it)->setSignalType(Port::E_PeriodSignalled)) {
270                     debugFatal("Could not set signal type to PeriodSignalling");
271                     return false;
272                 }
273                
274                 break;
275             case Port::E_Midi:
276                 if(!(*it)->setSignalType(Port::E_PacketSignalled)) {
277                     debugFatal("Could not set signal type to PacketSignalling");
278                     return false;
279                 }
280                
281                 break;
282                
283             case Port::E_Control:
284                 if(!(*it)->setSignalType(Port::E_PeriodSignalled)) {
285                     debugFatal("Could not set signal type to PeriodSignalling");
286                     return false;
287                 }
288                
289                 break;
290             default:
291                 debugWarning("Unsupported port type specified\n");
292                 break;
293         }
294     }
295
296     // the API specific settings of the ports are already set before
297     // this routine is called, therefore we can init&prepare the ports
298     if(!initPorts()) {
299         debugFatal("Could not initialize ports!\n");
300         return false;
301     }
302
303     if(!preparePorts()) {
304         debugFatal("Could not initialize ports!\n");
305         return false;
306     }
307
308     // we should prefill the event buffer
309     if (!prefill()) {
310         debugFatal("Could not prefill buffers\n");
311         return false;   
312     }
313
314     return true;
315
316 }
317
318 bool MotuTransmitStreamProcessor::transferSilence(unsigned int size) {
319    
320     // this function should tranfer 'size' frames of 'silence' to the event buffer
321     unsigned int write_size=size*sizeof(quadlet_t)*m_dimension;
322     char *dummybuffer=(char *)calloc(sizeof(quadlet_t),size*m_dimension);
323
324     transmitSilenceBlock(dummybuffer, size, 0);
325
326     if (freebob_ringbuffer_write(m_event_buffer,(char *)(dummybuffer),write_size) < write_size) {
327         debugWarning("Could not write to event buffer\n");
328     }
329    
330     free(dummybuffer);
331    
332     return true;
333 }
334
335 bool MotuTransmitStreamProcessor::transfer() {
336     m_PeriodStat.mark(freebob_ringbuffer_read_space(m_event_buffer)/(4*m_dimension));
337
338     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Transferring period...\n");
339     // TODO: improve
340 /* a naive implementation would look like this:
341
342     unsigned int write_size=m_period*sizeof(quadlet_t)*m_dimension;
343     char *dummybuffer=(char *)calloc(sizeof(quadlet_t),m_period*m_dimension);
344    
345     transmitBlock(dummybuffer, m_period, 0, 0);
346
347     if (freebob_ringbuffer_write(m_event_buffer,(char *)(dummybuffer),write_size) < write_size) {
348         debugWarning("Could not write to event buffer\n");
349     }
350
351
352     free(dummybuffer);
353 */
354 /* but we're not that naive anymore... */
355     int xrun;
356     unsigned int offset=0;
357
358 // FIXME: just return until we've got the transmit side of things functional
359 return true;
360
361     freebob_ringbuffer_data_t vec[2];
362     // we received one period of frames
363     // this is period_size*dimension of events
364     unsigned int events2write=m_period*m_dimension;
365     unsigned int bytes2write=events2write*sizeof(quadlet_t);
366
367     /* write events2write bytes to the ringbuffer
368     *  first see if it can be done in one read.
369     *  if so, ok.
370     *  otherwise write up to a multiple of clusters directly to the buffer
371     *  then do the buffer wrap around using ringbuffer_write
372     *  then write the remaining data directly to the buffer in a third pass
373     *  Make sure that we cannot end up on a non-cluster aligned position!
374     */
375     unsigned int cluster_size=m_dimension*sizeof(quadlet_t);
376
377     while(bytes2write>0) {
378         int byteswritten=0;
379        
380         unsigned int frameswritten=(m_period*cluster_size-bytes2write)/cluster_size;
381         offset=frameswritten;
382        
383         freebob_ringbuffer_get_write_vector(m_event_buffer, vec);
384            
385         if(vec[0].len==0) { // this indicates a full event buffer
386             debugError("XMT: Event buffer overrun in processor %p\n",this);
387             break;
388         }
389            
390         /* if we don't take care we will get stuck in an infinite loop
391         * because we align to a cluster boundary later
392         * the remaining nb of bytes in one write operation can be
393         * smaller than one cluster
394         * this can happen because the ringbuffer size is always a power of 2
395         */
396         if(vec[0].len<cluster_size) {
397            
398             // encode to the temporary buffer
399             xrun = transmitBlock(m_cluster_buffer, 1, offset);
400            
401             if(xrun<0) {
402                 // xrun detected
403                 debugError("XMT: Frame buffer underrun in processor %p\n",this);
404                 break;
405             }
406                
407             // use the ringbuffer function to write one cluster
408             // the write function handles the wrap around.
409             freebob_ringbuffer_write(m_event_buffer,
410                          m_cluster_buffer,
411                          cluster_size);
412                
413             // we advanced one cluster_size
414             bytes2write-=cluster_size;
415                
416         } else { //
417            
418             if(bytes2write>vec[0].len) {
419                 // align to a cluster boundary
420                 byteswritten=vec[0].len-(vec[0].len%cluster_size);
421             } else {
422                 byteswritten=bytes2write;
423             }
424                
425             xrun = transmitBlock(vec[0].buf,
426                          byteswritten/cluster_size,
427                          offset);
428            
429             if(xrun<0) {
430                     // xrun detected
431                 debugError("XMT: Frame buffer underrun in processor %p\n",this);
432                 break;
433             }
434
435             freebob_ringbuffer_write_advance(m_event_buffer, byteswritten);
436             bytes2write -= byteswritten;
437         }
438
439         // the bytes2write should always be cluster aligned
440         assert(bytes2write%cluster_size==0);
441
442     }
443
444     return true;
445 }
446 /*
447  * write received events to the stream ringbuffers.
448  */
449
450 int MotuTransmitStreamProcessor::transmitBlock(char *data,
451                        unsigned int nevents, unsigned int offset)
452 {
453     int problem=0;
454
455     for ( PortVectorIterator it = m_PeriodPorts.begin();
456           it != m_PeriodPorts.end();
457           ++it )
458     {
459         // if this port is disabled, don't process it
460         if((*it)->isDisabled()) {continue;};
461        
462         //FIXME: make this into a static_cast when not DEBUG?
463
464         MotuPortInfo *pinfo=dynamic_cast<MotuPortInfo *>(*it);
465         assert(pinfo); // this should not fail!!
466
467 /*      This is the AMDTP way, the motu way is different
468         Leaving this in as reference
469        
470         switch(pinfo->getFormat()) {
471        
472        
473         case MotuPortInfo::E_MBLA:
474             if(encodePortToMBLAEvents(static_cast<MotuAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) {
475                 debugWarning("Could not encode port %s to MBLA events",(*it)->getName().c_str());
476                 problem=1;
477             }
478             break;
479         case MotuPortInfo::E_SPDIF: // still unimplemented
480             break;
481         default: // ignore
482             break;
483         }
484 */
485     }
486     return problem;
487
488 }
489
490 int MotuTransmitStreamProcessor::transmitSilenceBlock(char *data,
491                        unsigned int nevents, unsigned int offset)
492 {
493     int problem=0;
494
495     for ( PortVectorIterator it = m_PeriodPorts.begin();
496           it != m_PeriodPorts.end();
497           ++it )
498     {
499
500         //FIXME: make this into a static_cast when not DEBUG?
501
502         MotuPortInfo *pinfo=dynamic_cast<MotuPortInfo *>(*it);
503         assert(pinfo); // this should not fail!!
504
505 /* this is the same as the non-silence version, except that is doesn't read from the port buffers
506         switch(pinfo->getFormat()) {
507        
508
509         case MotuPortInfo::E_MBLA:
510             if(encodeSilencePortToMBLAEvents(static_cast<MotuAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) {
511                 debugWarning("Could not encode port %s to MBLA events",(*it)->getName().c_str());
512                 problem=1;
513             }
514             break;
515         case MotuPortInfo::E_SPDIF: // still unimplemented
516             break;
517         default: // ignore
518             break;
519         }
520         */
521     }
522     return problem;
523
524 }
525
526 /**
527  * @brief decode a packet for the packet-based ports
528  *
529  * @param data Packet data
530  * @param nevents number of events in data (including events of other ports & port types)
531  * @param dbc DataBlockCount value for this packet
532  * @return true if all successfull
533  */
534 bool MotuTransmitStreamProcessor::encodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc)
535 {
536     bool ok=true;
537     char byte;
538    
539     quadlet_t *target_event=NULL;
540     int j;
541
542     for ( PortVectorIterator it = m_PacketPorts.begin();
543           it != m_PacketPorts.end();
544           ++it )
545     {
546
547 #ifdef DEBUG
548         MotuPortInfo *pinfo=dynamic_cast<MotuPortInfo *>(*it);
549         assert(pinfo); // this should not fail!!
550
551         // the only packet type of events for AMDTP is MIDI in mbla
552 //         assert(pinfo->getFormat()==MotuPortInfo::E_Midi);
553 #endif
554        
555         MotuMidiPort *mp=static_cast<MotuMidiPort *>(*it);
556        
557         // TODO: decode the midi (or other type) stuff here
558
559     }
560        
561     return ok;
562 }
563
564 /* Left in as reference, this is highly AMDTP related
565
566 basic idea:
567
568 iterate over the ports
569 - get port buffer address
570 - loop over events
571   * pick right sample in event based upon PortInfo
572   * convert sample from Port format (E_Int24, E_Float, ..) to native format
573
574 not that in order to use the 'efficient' transfer method, you have to make sure that
575 you can start from an offset (expressed in frames).
576
577 int MotuTransmitStreamProcessor::encodePortToMBLAEvents(MotuAudioPort *p, quadlet_t *data,
578                        unsigned int offset, unsigned int nevents)
579 {
580     unsigned int j=0;
581
582     quadlet_t *target_event;
583
584     target_event=(quadlet_t *)(data + p->getPosition());
585
586     switch(p->getDataType()) {
587         default:
588         case Port::E_Int24:
589             {
590                 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());
591
592                 assert(nevents + offset <= p->getBufferSize());
593
594                 buffer+=offset;
595
596                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
597                     *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);
598                     buffer++;
599                     target_event += m_dimension;
600                 }
601             }
602             break;
603         case Port::E_Float:
604             {
605                 const float multiplier = (float)(0x7FFFFF00);
606                 float *buffer=(float *)(p->getBufferAddress());
607
608                 assert(nevents + offset <= p->getBufferSize());
609
610                 buffer+=offset;
611
612                 for(j = 0; j < nevents; j += 1) { // decode max nsamples               
613    
614                     // don't care for overflow
615                     float v = *buffer * multiplier;  // v: -231 .. 231
616                     unsigned int tmp = ((int)v);
617                     *target_event = htonl((tmp >> 8) | 0x40000000);
618                    
619                     buffer++;
620                     target_event += m_dimension;
621                 }
622             }
623             break;
624     }
625
626     return 0;
627 }
628 */
629 /*
630 int MotuTransmitStreamProcessor::encodeSilencePortToMBLAEvents(MotuAudioPort *p, quadlet_t *data,
631                        unsigned int offset, unsigned int nevents)
632 {
633     unsigned int j=0;
634
635     quadlet_t *target_event;
636
637     target_event=(quadlet_t *)(data + p->getPosition());
638
639     switch(p->getDataType()) {
640         default:
641         case Port::E_Int24:
642         case Port::E_Float:
643             {
644                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
645                     *target_event = htonl(0x40000000);
646                     target_event += m_dimension;
647                 }
648             }
649             break;
650     }
651
652     return 0;
653 }
654 */
655
656 /* --------------------- RECEIVE ----------------------- */
657
658 MotuReceiveStreamProcessor::MotuReceiveStreamProcessor(int port, int framerate)
659     : ReceiveStreamProcessor(port, framerate), m_dimension(0) {
660
661
662 }
663
664 MotuReceiveStreamProcessor::~MotuReceiveStreamProcessor() {
665     freebob_ringbuffer_free(m_event_buffer);
666     free(m_cluster_buffer);
667
668 }
669
670 bool MotuReceiveStreamProcessor::init() {
671
672     // call the parent init
673     // this has to be done before allocating the buffers,
674     // because this sets the buffersizes from the processormanager
675     if(!ReceiveStreamProcessor::init()) {
676         debugFatal("Could not do base class init (%d)\n",this);
677         return false;
678     }
679
680     return true;
681 }
682
683 enum raw1394_iso_disposition
684 MotuReceiveStreamProcessor::putPacket(unsigned char *data, unsigned int length,
685                   unsigned char channel, unsigned char tag, unsigned char sy,
686                   unsigned int cycle, unsigned int dropped) {
687    
688     enum raw1394_iso_disposition retval=RAW1394_ISO_OK;
689
690     // If the packet length is 8 bytes (ie: just a CIP-like header) there is
691     // no isodata.
692     if (length > 8) {
693         // Note: a freebob "event" is equivalent to an ieee1394 iso data
694         // block.  We'll try to stick to freebob terminology.
695         quadlet_t *quadlet = (quadlet_t *)data;
696         unsigned int dbs = get_bits(ntohl(quadlet[0]), 23, 8);  // ISO data block size in terms of fdf_size
697         unsigned int fdf_size = get_bits(ntohl(quadlet[1]), 23, 8) == 0x22 ? 32:0; // ISO block unit size in bits
698         unsigned int event_length = (fdf_size * dbs) / 8;       // Event (aka ISO block) size in bytes
699         unsigned int n_events = (length-8) / event_length;
700
701         // Don't even attempt to process a packet if it isn't what we expect
702         // from a MOTU
703         if (tag!=1 || fdf_size!=32) {
704                 return RAW1394_ISO_OK;
705         }
706        
707         // Signal that we're running
708         if (n_events) m_running=true;
709
710         // Don't process the stream when it is not enabled.
711         if (m_disabled) {
712                 return RAW1394_ISO_OK;
713         }
714        
715         debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "put packet...\n");
716
717         // Add the data payload (events) to the ringbuffer.  We'll just copy
718         // everything including the 4 byte timestamp at the start of each
719         // event (that is, everything except the CIP-like header).  The
720         // demultiplexer can deal with the complexities such as the channel
721         // 24-bit data.
722         unsigned int write_size = length-8;
723         if (freebob_ringbuffer_write(m_event_buffer,(char *)(data+8),write_size) < write_size) {
724                 debugWarning("Receive buffer overrun (cycle %d, FC=%d, PC=%d)\n",
725                         cycle, m_framecounter, m_handler->getPacketCount());
726                 m_xruns++;
727
728                 retval=RAW1394_ISO_DEFER;
729         } else {
730                 retval=RAW1394_ISO_OK;
731                 // Process all ports that should be handled on a per-packet basis
732                 // This is MIDI for AMDTP (due to the need of DBC)
733                 int dbc = get_bits(ntohl(quadlet[0]), 8, 8);  // Low byte of CIP quadlet 0
734                 if (!decodePacketPorts((quadlet_t *)(data+8), n_events, dbc)) {
735                         debugWarning("Problem decoding Packet Ports\n");
736                         retval=RAW1394_ISO_DEFER;
737                 }
738                 // time stamp processing can be done here
739         }
740
741         // update the frame counter
742         incrementFrameCounter(n_events);
743         // keep this at the end, because otherwise the raw1394_loop_iterate functions inner loop
744         // keeps requesting packets without going to the xmit handler, leading to xmit starvation
745         if(m_framecounter>(signed int)m_period) {
746                 retval=RAW1394_ISO_DEFER;
747         }
748        
749     } else { // no events in packet
750         // discard packet
751         // can be important for sync though
752     }
753    
754     return retval;
755 }
756
757 bool MotuReceiveStreamProcessor::isOnePeriodReady() {
758      // TODO: this is the way you can implement sync
759      //       only when this returns true, one period will be
760      //       transferred to the audio api side.
761      //       you can delay this moment as long as you
762      //       want (provided that there is enough buffer space)
763      
764      // this implementation just waits until there is one period of samples
765      // received into the buffer
766     if(m_framecounter > (signed int)m_period) {
767         return true;
768     }
769     return false;
770 }
771
772 void MotuReceiveStreamProcessor::setVerboseLevel(int l) {
773         setDebugLevel(l);
774         ReceiveStreamProcessor::setVerboseLevel(l);
775
776 }
777
778
779 bool MotuReceiveStreamProcessor::reset() {
780
781         debugOutput( DEBUG_LEVEL_VERBOSE, "Resetting...\n");
782
783         // reset the event buffer, discard all content
784         freebob_ringbuffer_reset(m_event_buffer);
785
786         // reset all non-device specific stuff
787         // i.e. the iso stream and the associated ports
788         if(!ReceiveStreamProcessor::reset()) {
789                 debugFatal("Could not do base class reset\n");
790                 return false;
791         }
792        
793         return true;
794 }
795
796 bool MotuReceiveStreamProcessor::prepare() {
797
798         // prepare all non-device specific stuff
799         // i.e. the iso stream and the associated ports
800         if(!ReceiveStreamProcessor::prepare()) {
801                 debugFatal("Could not prepare base class\n");
802                 return false;
803         }
804
805         debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing...\n");
806
807         m_PeriodStat.setName("RCV PERIOD");
808         m_PacketStat.setName("RCV PACKET");
809         m_WakeupStat.setName("RCV WAKEUP");
810
811     // setup any specific stuff here
812
813         // allocate the event buffer
814         unsigned int ringbuffer_size_frames=m_nb_buffers * m_period;
815
816         if( !(m_event_buffer=freebob_ringbuffer_create(
817                 (m_dimension * ringbuffer_size_frames) * sizeof(quadlet_t)))) {
818                 debugFatal("Could not allocate memory event ringbuffer");
819                 return false;
820         }
821
822         // allocate the temporary cluster buffer
823         if( !(m_cluster_buffer=(char *)calloc(m_dimension,sizeof(quadlet_t)))) {
824                 debugFatal("Could not allocate temporary cluster buffer");
825                 freebob_ringbuffer_free(m_event_buffer);
826                 return false;
827         }
828
829         // set the parameters of ports we can:
830         // we want the audio ports to be period buffered,
831         // and the midi ports to be packet buffered
832         for ( PortVectorIterator it = m_Ports.begin();
833                   it != m_Ports.end();
834                   ++it )
835         {
836                 debugOutput(DEBUG_LEVEL_VERBOSE, "Setting up port %s\n",(*it)->getName().c_str());
837                
838                 if(!(*it)->setBufferSize(m_period)) {
839                         debugFatal("Could not set buffer size to %d\n",m_period);
840                         return false;
841                 }
842
843                 switch ((*it)->getPortType()) {
844                         case Port::E_Audio:
845                                 if(!(*it)->setSignalType(Port::E_PeriodSignalled)) {
846                                         debugFatal("Could not set signal type to PeriodSignalling");
847                                         return false;
848                                 }
849                                 break;
850                         case Port::E_Midi:
851                                 if(!(*it)->setSignalType(Port::E_PacketSignalled)) {
852                                         debugFatal("Could not set signal type to PacketSignalling");
853                                         return false;
854                                 }
855                                 break;
856                         case Port::E_Control:
857                                 if(!(*it)->setSignalType(Port::E_PeriodSignalled)) {
858                                         debugFatal("Could not set signal type to PeriodSignalling");
859                                         return false;
860                                 }
861                                 break;
862                         default:
863                                 debugWarning("Unsupported port type specified\n");
864                                 break;
865                 }
866
867         }
868
869     // the API specific settings of the ports are already set before
870     // this routine is called, therefore we can init&prepare the ports
871         if(!initPorts()) {
872                 debugFatal("Could not initialize ports!\n");
873                 return false;
874         }
875
876         if(!preparePorts()) {
877                 debugFatal("Could not initialize ports!\n");
878                 return false;
879         }
880        
881         return true;
882
883 }
884
885 bool MotuReceiveStreamProcessor::transfer() {
886
887     // the same idea as the transmit processor
888    
889         debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Transferring period...\n");
890        
891 /* another naive section:       
892         unsigned int read_size=m_period*sizeof(quadlet_t)*m_dimension;
893         char *dummybuffer=(char *)calloc(sizeof(quadlet_t),m_period*m_dimension);
894         if (freebob_ringbuffer_read(m_event_buffer,(char *)(dummybuffer),read_size) < read_size) {
895                 debugWarning("Could not read from event buffer\n");
896         }
897
898         receiveBlock(dummybuffer, m_period, 0);
899
900         free(dummybuffer);
901 */
902         int xrun;
903         unsigned int offset=0;
904        
905         freebob_ringbuffer_data_t vec[2];
906         // we received one period of frames on each connection
907         // this is period_size*dimension of events
908
909         unsigned int events2read=m_period*m_dimension;
910         unsigned int bytes2read=events2read*sizeof(quadlet_t);
911
912 // FIXME: remove once the stuff below has been tweaked for the MOTU
913 return true;
914
915         /* read events2read bytes from the ringbuffer
916         *  first see if it can be done in one read.
917         *  if so, ok.
918         *  otherwise read up to a multiple of clusters directly from the buffer
919         *  then do the buffer wrap around using ringbuffer_read
920         *  then read the remaining data directly from the buffer in a third pass
921         *  Make sure that we cannot end up on a non-cluster aligned position!
922         */
923         unsigned int cluster_size=m_dimension*sizeof(quadlet_t);
924        
925         while(bytes2read>0) {
926                 unsigned int framesread=(m_period*cluster_size-bytes2read)/cluster_size;
927                 offset=framesread;
928                
929                 int bytesread=0;
930
931                 freebob_ringbuffer_get_read_vector(m_event_buffer, vec);
932                        
933                 if(vec[0].len==0) { // this indicates an empty event buffer
934                         debugError("RCV: Event buffer underrun in processor %p\n",this);
935                         break;
936                 }
937                        
938                 /* if we don't take care we will get stuck in an infinite loop
939                 * because we align to a cluster boundary later
940                 * the remaining nb of bytes in one read operation can be smaller than one cluster
941                 * this can happen because the ringbuffer size is always a power of 2
942                         */
943                 if(vec[0].len<cluster_size) {
944                         // use the ringbuffer function to read one cluster
945                         // the read function handles wrap around
946                         freebob_ringbuffer_read(m_event_buffer,m_cluster_buffer,cluster_size);
947
948                         xrun = receiveBlock(m_cluster_buffer, 1, offset);
949                                
950                         if(xrun<0) {
951                                 // xrun detected
952                                 debugError("RCV: Frame buffer overrun in processor %p\n",this);
953                                 break;
954                         }
955                                
956                                 // we advanced one cluster_size
957                         bytes2read-=cluster_size;
958                                
959                 } else { //
960                        
961                         if(bytes2read>vec[0].len) {
962                                         // align to a cluster boundary
963                                 bytesread=vec[0].len-(vec[0].len%cluster_size);
964                         } else {
965                                 bytesread=bytes2read;
966                         }
967                                
968                         xrun = receiveBlock(vec[0].buf, bytesread/cluster_size, offset);
969                                
970                         if(xrun<0) {
971                                         // xrun detected
972                                 debugError("RCV: Frame buffer overrun in processor %p\n",this);
973                                 break;
974                         }
975
976                         freebob_ringbuffer_read_advance(m_event_buffer, bytesread);
977                         bytes2read -= bytesread;
978                 }
979                        
980                 // the bytes2read should always be cluster aligned
981                 assert(bytes2read%cluster_size==0);
982         }
983
984         return true;
985 }
986
987 /**
988  * \brief write received events to the port ringbuffers.
989  */
990 int MotuReceiveStreamProcessor::receiveBlock(char *data,
991                                            unsigned int nevents, unsigned int offset)
992 {
993         int problem=0;
994
995         for ( PortVectorIterator it = m_PeriodPorts.begin();
996           it != m_PeriodPorts.end();
997           ++it )
998     {
999
1000         if((*it)->isDisabled()) {continue;};
1001
1002                 //FIXME: make this into a static_cast when not DEBUG?
1003
1004                 MotuPortInfo *pinfo=dynamic_cast<MotuPortInfo *>(*it);
1005                 assert(pinfo); // this should not fail!!
1006                
1007 /* AMDTP, left as reference
1008                 switch(pinfo->getFormat()) {
1009                
1010                 case MotuPortInfo::E_MBLA:
1011                         if(decodeMBLAEventsToPort(static_cast<MotuAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) {
1012                                 debugWarning("Could not decode packet MBLA to port %s",(*it)->getName().c_str());
1013                                 problem=1;
1014                         }
1015                         break;
1016                 case MotuPortInfo::E_SPDIF: // still unimplemented
1017                         break;
1018         // midi is a packet based port, don't process
1019         //      case MotuPortInfo::E_Midi:
1020         //              break;
1021
1022                 default: // ignore
1023                         break;
1024                 }
1025 */
1026     }
1027         return problem;
1028
1029 }
1030
1031 /**
1032  * @brief decode a packet for the packet-based ports
1033  *
1034  * @param data Packet data
1035  * @param nevents number of events in data (including events of other ports & port types)
1036  * @param dbc DataBlockCount value for this packet
1037  * @return true if all successfull
1038  */
1039 bool MotuReceiveStreamProcessor::decodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc)
1040 {
1041         bool ok=true;
1042        
1043         quadlet_t *target_event=NULL;
1044         int j;
1045        
1046         for ( PortVectorIterator it = m_PacketPorts.begin();
1047           it != m_PacketPorts.end();
1048           ++it )
1049         {
1050
1051 #ifdef DEBUG
1052                 MotuPortInfo *pinfo=dynamic_cast<MotuPortInfo *>(*it);
1053                 assert(pinfo); // this should not fail!!
1054
1055                 // the only packet type of events for AMDTP is MIDI in mbla
1056 //              assert(pinfo->getFormat()==MotuPortInfo::E_Midi);
1057 #endif
1058                 MotuMidiPort *mp=static_cast<MotuMidiPort *>(*it);
1059                
1060
1061         // do decoding here
1062
1063         }
1064        
1065         return ok;
1066 }
1067
1068 /* for reference
1069
1070 int MotuReceiveStreamProcessor::decodeMBLAEventsToPort(MotuAudioPort *p, quadlet_t *data,
1071                                            unsigned int offset, unsigned int nevents)
1072 {
1073         unsigned int j=0;
1074
1075 //      printf("****************\n");
1076 //      hexDumpQuadlets(data,m_dimension*4);
1077 //      printf("****************\n");
1078
1079         quadlet_t *target_event;
1080
1081         target_event=(quadlet_t *)(data + p->getPosition());
1082
1083         switch(p->getDataType()) {
1084                 default:
1085                 case Port::E_Int24:
1086                         {
1087                                 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());
1088
1089                                 assert(nevents + offset <= p->getBufferSize());
1090
1091                                 buffer+=offset;
1092
1093                                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
1094                                         *(buffer)=(ntohl((*target_event) ) & 0x00FFFFFF);
1095                                         buffer++;
1096                                         target_event+=m_dimension;
1097                                 }
1098                         }
1099                         break;
1100                 case Port::E_Float:
1101                         {
1102                                 const float multiplier = 1.0f / (float)(0x7FFFFF);
1103                                 float *buffer=(float *)(p->getBufferAddress());
1104
1105                                 assert(nevents + offset <= p->getBufferSize());
1106
1107                                 buffer+=offset;
1108
1109                                 for(j = 0; j < nevents; j += 1) { // decode max nsamples               
1110        
1111                                         unsigned int v = ntohl(*target_event) & 0x00FFFFFF;
1112                                         // sign-extend highest bit of 24-bit int
1113                                         int tmp = (int)(v << 8) / 256;
1114                
1115                                         *buffer = tmp * multiplier;
1116                                
1117                                         buffer++;
1118                                         target_event+=m_dimension;
1119                                 }
1120                         }
1121                         break;
1122         }
1123
1124         return 0;
1125 }
1126 */
1127 } // end of namespace FreebobStreaming
Note: See TracBrowser for help on using the browser.