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

Revision 249, 32.1 kB (checked in by pieterpalmers, 18 years ago)

- Extensive documentation update.

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