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

Revision 222, 13.9 kB (checked in by pieterpalmers, 18 years ago)

- makefile rework: move headers in noinst, makes life easier with kdevelop

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  *
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 #include "AmdtpStreamProcessor.h"
30 #include "Port.h"
31 #include "AmdtpPort.h"
32
33 #include <netinet/in.h>
34 #include <assert.h>
35
36
37 namespace FreebobStreaming {
38
39 IMPL_DEBUG_MODULE( AmdtpTransmitStreamProcessor, AmdtpTransmitStreamProcessor, DEBUG_LEVEL_NORMAL );
40 IMPL_DEBUG_MODULE( AmdtpReceiveStreamProcessor, AmdtpReceiveStreamProcessor, DEBUG_LEVEL_NORMAL );
41
42
43 /* transmit */
44 AmdtpTransmitStreamProcessor::AmdtpTransmitStreamProcessor(int channel, int port, int framerate, int dimension)
45         : TransmitStreamProcessor(channel, port, framerate), m_dimension(dimension) {
46
47
48 }
49
50 AmdtpTransmitStreamProcessor::~AmdtpTransmitStreamProcessor() {
51         freebob_ringbuffer_free(m_event_buffer);
52         free(m_cluster_buffer);
53 }
54
55 int AmdtpTransmitStreamProcessor::init() {
56         int fdf=0, syt_interval=0;
57         int m_dbs=0;
58         int err=0;
59
60         // call the parent init
61         // this has to be done before allocating the buffers,
62         // because this sets the buffersizes from the processormanager
63         if((err=TransmitStreamProcessor::init())) {
64                 debugFatal("Could not allocate memory event ringbuffer (%d)",err);
65                 return err;
66         }
67
68
69         switch (m_framerate) {
70         case 32000:
71                 syt_interval = 8;
72                 fdf = IEC61883_FDF_SFC_32KHZ;
73                 break;
74         case 44100:
75                 syt_interval = 8;
76                 fdf = IEC61883_FDF_SFC_44K1HZ;
77                 break;
78         default:
79         case 48000:
80                 syt_interval = 8;
81                 fdf = IEC61883_FDF_SFC_48KHZ;
82                 break;
83         case 88200:
84                 syt_interval = 16;
85                 fdf = IEC61883_FDF_SFC_88K2HZ;
86                 break;
87         case 96000:
88                 syt_interval = 16;
89                 fdf = IEC61883_FDF_SFC_96KHZ;
90                 break;
91         case 176400:
92                 syt_interval = 32;
93                 fdf = IEC61883_FDF_SFC_176K4HZ;
94                 break;
95         case 192000:
96                 syt_interval = 32;
97                 fdf = IEC61883_FDF_SFC_192KHZ;
98                 break;
99         }
100        
101         iec61883_cip_init (
102                 &m_cip_status,
103                 IEC61883_FMT_AMDTP,
104                 fdf,
105                 m_framerate,
106                 m_dbs,
107                 syt_interval);
108
109         // allocate the event buffer
110         if( !(m_event_buffer=freebob_ringbuffer_create(
111                         (m_dimension * m_nb_buffers * m_period) * sizeof(quadlet_t)))) {
112                 debugFatal("Could not allocate memory event ringbuffer");
113 //              return -ENOMEM;
114                 return -1;
115         }
116
117         // allocate the temporary cluster buffer
118         if( !(m_cluster_buffer=(char *)calloc(m_dimension,sizeof(quadlet_t)))) {
119                 debugFatal("Could not allocate temporary cluster buffer");
120                 freebob_ringbuffer_free(m_event_buffer);
121                 return -1;
122 //              return -ENOMEM;
123         }
124
125         // call the parent init
126         return TransmitStreamProcessor::init();
127 }
128
129 void AmdtpTransmitStreamProcessor::setVerboseLevel(int l) {
130         setDebugLevel(l);
131         TransmitStreamProcessor::setVerboseLevel(l);
132 }
133
134
135 int AmdtpTransmitStreamProcessor::getPacket(unsigned char *data, unsigned int *length,
136                       unsigned char *tag, unsigned char *sy,
137                       int cycle, unsigned int dropped, unsigned int max_length) {
138
139         struct iec61883_packet *packet = (struct iec61883_packet *) data;
140        
141         // construct the packet cip
142         int nevents = iec61883_cip_fill_header (getNodeId(), &m_cip_status, packet);
143
144         enum raw1394_iso_disposition retval = RAW1394_ISO_OK;
145
146         if (!(nevents > 0)) {
147                 if (m_cip_status.mode == IEC61883_MODE_BLOCKING_EMPTY) {
148                         *length = 8;
149                         return (int)RAW1394_ISO_OK;
150                 }
151                 else {
152                         nevents = m_cip_status.syt_interval;
153                 }
154         }
155        
156         int read_size=nevents*sizeof(quadlet_t)*m_dimension;
157
158         if ((freebob_ringbuffer_read(m_event_buffer,(char *)(data+8),read_size)) <
159                                 read_size)
160         {
161                 debugWarning("Transmit buffer underrun\n");
162                
163                 // signal underrun
164 //              m_xruns++;
165
166                 retval=RAW1394_ISO_DEFER;
167                 *length=0;
168
169         } else {
170                 retval=RAW1394_ISO_OK;
171                 *length = read_size + 8;
172                
173                 // TODO: we should do all packet buffered processing here
174 //              freebob_streaming_encode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);
175         }
176        
177         *tag = IEC61883_TAG_WITH_CIP;
178         *sy = 0;
179        
180         // update the frame counter
181         m_framecounter+=nevents;
182
183         return (int)retval;
184
185 }
186
187 void AmdtpTransmitStreamProcessor::reset() {
188
189         debugOutput( DEBUG_LEVEL_VERBOSE, "Resetting...\n");
190
191         // reset the event buffer, discard all content
192         freebob_ringbuffer_reset(m_event_buffer);
193        
194         // reset all non-device specific stuff
195         // i.e. the iso stream and the associated ports
196         TransmitStreamProcessor::reset();
197 }
198
199 void AmdtpTransmitStreamProcessor::prepare() {
200
201         debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing...\n");
202
203         // prepare all non-device specific stuff
204         // i.e. the iso stream and the associated ports
205         TransmitStreamProcessor::prepare();
206
207         // after preparing, we should transfer the port buffer contents to the event buffer
208         int i=m_nb_buffers;
209         while(i--) transfer();
210
211 }
212
213 int AmdtpTransmitStreamProcessor::transfer() {
214
215         debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Transferring period...\n");
216         // TODO: improve
217
218         unsigned int write_size=m_period*sizeof(quadlet_t)*m_dimension;
219         char *dummybuffer=(char *)calloc(sizeof(quadlet_t),m_period*m_dimension);
220         transmitBlock(dummybuffer, m_period, 0, 0);
221
222         if (freebob_ringbuffer_write(m_event_buffer,(char *)(dummybuffer),write_size) < write_size) {
223                 debugWarning("Could not write to event buffer\n");
224         }
225
226
227         free(dummybuffer);
228
229         return 0;
230 }
231 /*
232  * write received events to the stream ringbuffers.
233  */
234
235 int AmdtpTransmitStreamProcessor::transmitBlock(char *data,
236                                            unsigned int nevents, unsigned int offset, unsigned int dbc)
237 {
238         int problem=0;
239
240         for ( PortVectorIterator it = m_PeriodPorts.begin();
241           it != m_PeriodPorts.end();
242           ++it )
243     {
244
245                 //FIXME: make this into a static_cast when not DEBUG?
246
247                 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);
248                 assert(pinfo); // this should not fail!!
249
250                 switch(pinfo->getFormat()) {
251                 case AmdtpPortInfo::E_MBLA:
252                         if(encodePortToMBLAEvents(static_cast<AmdtpAudioPort *>(*it), (quadlet_t *)data, offset, nevents, dbc)) {
253                                 debugWarning("Could not encode port %s to MBLA events",(*it)->getName().c_str());
254                                 problem=1;
255                         }
256                         break;
257                 case AmdtpPortInfo::E_SPDIF: // still unimplemented
258                         break;
259         /* for this processor, midi is a packet based port
260                 case AmdtpPortInfo::E_Midi:
261                         break;*/
262                 default: // ignore
263                         break;
264                 }
265     }
266         return problem;
267
268 }
269
270 int AmdtpTransmitStreamProcessor::encodePortToMBLAEvents(AmdtpAudioPort *p, quadlet_t *data,
271                                            unsigned int offset, unsigned int nevents, unsigned int dbc)
272 {
273         unsigned int j=0;
274
275         quadlet_t *target_event;
276
277         target_event=(quadlet_t *)(data + p->getPosition());
278
279         switch(p->getDataType()) {
280                 default:
281                 case Port::E_Int24:
282                         {
283                                 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());
284
285                                 assert(nevents + offset <= p->getBufferSize());
286
287                                 buffer+=offset;
288
289                                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
290                                         *target_event = htonl((*(buffer) & 0x00FFFFFF) | 0x40000000);
291                                         buffer++;
292                                         target_event += m_dimension;
293                                 }
294                         }
295                         break;
296                 case Port::E_Float:
297                         {
298                                 const float multiplier = (float)(0x7FFFFF00);
299                                 float *buffer=(float *)(p->getBufferAddress());
300
301                                 assert(nevents + offset <= p->getBufferSize());
302
303                                 buffer+=offset;
304
305                                 for(j = 0; j < nevents; j += 1) { // decode max nsamples               
306        
307                                         // don't care for overflow
308                                         float v = *buffer * multiplier;  // v: -231 .. 231
309                                         unsigned int tmp = ((int)v);
310                                         *target_event = htonl((tmp >> 8) | 0x40000000);
311                                        
312                                         buffer++;
313                                         target_event += m_dimension;
314                                 }
315                         }
316                         break;
317         }
318
319         return 0;
320 }
321
322 /* --------------------- RECEIVE ----------------------- */
323
324 AmdtpReceiveStreamProcessor::AmdtpReceiveStreamProcessor(int channel, int port, int framerate, int dimension)
325         : ReceiveStreamProcessor(channel, port, framerate), m_dimension(dimension) {
326
327
328 }
329
330 AmdtpReceiveStreamProcessor::~AmdtpReceiveStreamProcessor() {
331         freebob_ringbuffer_free(m_event_buffer);
332         free(m_cluster_buffer);
333
334 }
335
336 int AmdtpReceiveStreamProcessor::init() {
337         int err=0;
338         // call the parent init
339         // this has to be done before allocating the buffers,
340         // because this sets the buffersizes from the processormanager
341         if((err=ReceiveStreamProcessor::init())) {
342                 debugFatal("Could not allocate memory event ringbuffer (%d)",err);
343                 return err;
344         }
345
346         if( !(m_event_buffer=freebob_ringbuffer_create(
347                         (m_dimension * m_nb_buffers * m_period) * sizeof(quadlet_t)))) {
348                 debugFatal("Could not allocate memory event ringbuffer");
349 //              return -ENOMEM;
350                 return -1;
351         }
352
353         // allocate the temporary cluster buffer
354         if( !(m_cluster_buffer=(char *)calloc(m_dimension,sizeof(quadlet_t)))) {
355                 debugFatal("Could not allocate temporary cluster buffer");
356                 freebob_ringbuffer_free(m_event_buffer);
357 //              return -ENOMEM;
358                 return -1;
359         }
360
361         return 0;
362 }
363
364 int AmdtpReceiveStreamProcessor::putPacket(unsigned char *data, unsigned int length,
365                       unsigned char channel, unsigned char tag, unsigned char sy,
366                           unsigned int cycle, unsigned int dropped) {
367
368         enum raw1394_iso_disposition retval=RAW1394_ISO_OK;
369        
370         struct iec61883_packet *packet = (struct iec61883_packet *) data;
371         assert(packet);
372        
373         if((packet->fmt == 0x10) && (packet->fdf != 0xFF) && (packet->dbs>0) && (length>=2*sizeof(quadlet_t))) {
374                 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;
375
376                 unsigned int write_size=nevents*sizeof(quadlet_t)*m_dimension;
377                 // add the data payload to the ringbuffer
378                
379                 if (freebob_ringbuffer_write(m_event_buffer,(char *)(data+8),write_size) < write_size)
380                 {
381                         debugWarning("Buffer overrun!\n");
382                         m_xruns++;
383
384                         retval=RAW1394_ISO_DEFER;
385                 } else {
386                         retval=RAW1394_ISO_OK;
387                         // we cannot offload midi encoding due to the need for a dbc value
388 //                      freebob_streaming_decode_midi(connection,(quadlet_t *)(data+8), nevents, packet->dbc);
389                 }
390
391                 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
392                         "RCV: CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d)\n",
393                         channel, packet->fdf,
394                         packet->syt,
395                         packet->dbs,
396                         packet->dbc,
397                         packet->fmt,
398                         length,
399                         ((length / sizeof (quadlet_t)) - 2)/packet->dbs);
400                
401                 // update the frame counter
402                 m_framecounter+=nevents;
403                
404         } else {
405                 // discard packet
406                 // can be important for sync though
407         }
408
409         return (int)retval;
410 }
411
412 void AmdtpReceiveStreamProcessor::setVerboseLevel(int l) {
413         setDebugLevel(l);
414         ReceiveStreamProcessor::setVerboseLevel(l);
415
416 }
417
418
419 void AmdtpReceiveStreamProcessor::reset() {
420
421         debugOutput( DEBUG_LEVEL_VERBOSE, "Resetting...\n");
422
423         // reset the event buffer, discard all content
424         freebob_ringbuffer_reset(m_event_buffer);
425        
426         // reset all non-device specific stuff
427         // i.e. the iso stream and the associated ports
428         ReceiveStreamProcessor::reset();
429 }
430
431 void AmdtpReceiveStreamProcessor::prepare() {
432
433         debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing...\n");
434
435         // prepare all non-device specific stuff
436         // i.e. the iso stream and the associated ports
437         ReceiveStreamProcessor::prepare();
438 }
439
440 int AmdtpReceiveStreamProcessor::transfer() {
441
442         debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Transferring period...\n");
443 // TODO: implement
444        
445         unsigned int read_size=m_period*sizeof(quadlet_t)*m_dimension;
446         char *dummybuffer=(char *)calloc(sizeof(quadlet_t),m_period*m_dimension);
447         if (freebob_ringbuffer_read(m_event_buffer,(char *)(dummybuffer),read_size) < read_size) {
448                 debugWarning("Could not read from event buffer\n");
449         }
450
451         receiveBlock(dummybuffer, m_period, 0, 0);
452
453         free(dummybuffer);
454
455
456
457         return 0;
458 }
459
460 /*
461  * write received events to the stream ringbuffers.
462  */
463
464 int AmdtpReceiveStreamProcessor::receiveBlock(char *data,
465                                            unsigned int nevents, unsigned int offset, unsigned int dbc)
466 {
467         int problem=0;
468
469         for ( PortVectorIterator it = m_PeriodPorts.begin();
470           it != m_PeriodPorts.end();
471           ++it )
472     {
473
474                 //FIXME: make this into a static_cast when not DEBUG?
475
476                 AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);
477                 assert(pinfo); // this should not fail!!
478
479                 switch(pinfo->getFormat()) {
480                 case AmdtpPortInfo::E_MBLA:
481                         if(decodeMBLAEventsToPort(static_cast<AmdtpAudioPort *>(*it), (quadlet_t *)data, offset, nevents, dbc)) {
482                                 debugWarning("Could not decode packet MBLA to port %s",(*it)->getName().c_str());
483                                 problem=1;
484                         }
485                         break;
486                 case AmdtpPortInfo::E_SPDIF: // still unimplemented
487                         break;
488         /* for this processor, midi is a packet based port
489                 case AmdtpPortInfo::E_Midi:
490                         break;*/
491                 default: // ignore
492                         break;
493                 }
494     }
495         return problem;
496
497 }
498
499 int AmdtpReceiveStreamProcessor::decodeMBLAEventsToPort(AmdtpAudioPort *p, quadlet_t *data,
500                                            unsigned int offset, unsigned int nevents, unsigned int dbc)
501 {
502         unsigned int j=0;
503
504 //      printf("****************\n");
505 //      hexDumpQuadlets(data,m_dimension*4);
506 //      printf("****************\n");
507
508         quadlet_t *target_event;
509
510         target_event=(quadlet_t *)(data + p->getPosition());
511
512         switch(p->getDataType()) {
513                 default:
514                 case Port::E_Int24:
515                         {
516                                 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());
517
518                                 assert(nevents + offset <= p->getBufferSize());
519
520                                 buffer+=offset;
521
522                                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
523                                         *(buffer)=(ntohl((*target_event) ) & 0x00FFFFFF);
524                                         buffer++;
525                                         target_event+=m_dimension;
526                                 }
527                         }
528                         break;
529                 case Port::E_Float:
530                         {
531                                 const float multiplier = 1.0f / (float)(0x7FFFFF);
532                                 float *buffer=(float *)(p->getBufferAddress());
533
534                                 assert(nevents + offset <= p->getBufferSize());
535
536                                 buffer+=offset;
537
538                                 for(j = 0; j < nevents; j += 1) { // decode max nsamples               
539        
540                                         unsigned int v = ntohl(*target_event) & 0x00FFFFFF;
541                                         // sign-extend highest bit of 24-bit int
542                                         int tmp = (int)(v << 8) / 256;
543                
544                                         *buffer = tmp * multiplier;
545                                
546                                         buffer++;
547                                         target_event+=m_dimension;
548                                 }
549                         }
550                         break;
551         }
552
553         return 0;
554 }
555
556 } // end of namespace FreebobStreaming
Note: See TracBrowser for help on using the browser.