root/branches/ppalmers-streaming/src/libstreaming/amdtp/AmdtpReceiveStreamProcessor.cpp

Revision 712, 22.1 kB (checked in by ppalmers, 15 years ago)

almost there...

Line 
1 /*
2  * Copyright (C) 2005-2007 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License version 2.1, as published by the Free Software Foundation;
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  * MA 02110-1301 USA
22  */
23
24 #include "AmdtpReceiveStreamProcessor.h"
25 #include "AmdtpPort.h"
26
27 #include "../util/cycletimer.h"
28
29 #include <netinet/in.h>
30 #include <assert.h>
31
32 // in ticks
33 // as per AMDTP2.1:
34 // 354.17us + 125us @ 24.576ticks/usec = 11776.08192 ticks
35 #define DEFAULT_TRANSFER_DELAY (11776U)
36
37 #define TRANSMIT_TRANSFER_DELAY DEFAULT_TRANSFER_DELAY
38
39 namespace Streaming {
40
41 /* --------------------- RECEIVE ----------------------- */
42
43 AmdtpReceiveStreamProcessor::AmdtpReceiveStreamProcessor(int port, int framerate, int dimension)
44     : ReceiveStreamProcessor(port, framerate)
45     , m_dimension(dimension)
46     , m_last_timestamp(0)
47     , m_last_timestamp2(0)
48     , m_dropped(0)
49 {}
50
51 bool AmdtpReceiveStreamProcessor::init() {
52
53     // call the parent init
54     // this has to be done before allocating the buffers,
55     // because this sets the buffersizes from the processormanager
56     if(!ReceiveStreamProcessor::init()) {
57         debugFatal("Could not do base class init (%d)\n",this);
58         return false;
59     }
60     return true;
61 }
62
63 enum raw1394_iso_disposition
64 AmdtpReceiveStreamProcessor::putPacket(unsigned char *data, unsigned int length,
65                   unsigned char channel, unsigned char tag, unsigned char sy,
66                   unsigned int cycle, unsigned int dropped) {
67
68     enum raw1394_iso_disposition retval=RAW1394_ISO_OK;
69
70     int dropped_cycles=diffCycles(cycle, m_last_cycle) - 1;
71     if (dropped_cycles < 0) debugWarning("(%p) dropped < 1 (%d)\n", this, dropped_cycles);
72     else m_dropped += dropped_cycles;
73     if (dropped_cycles > 0) debugWarning("(%p) dropped %d packets on cycle %u\n", this, dropped_cycles, cycle);
74
75     m_last_cycle=cycle;
76
77     struct iec61883_packet *packet = (struct iec61883_packet *) data;
78     assert(packet);
79
80 #ifdef DEBUG
81     if(dropped>0) {
82         debugWarning("(%p) Dropped %d packets on cycle %d\n", this, dropped, cycle);
83     }
84
85     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"ch%2u: CY=%4u, SYT=%08X (%4ucy + %04uticks) (running=%d)\n",
86         channel, cycle, ntohs(packet->syt),
87         CYCLE_TIMER_GET_CYCLES(ntohs(packet->syt)), CYCLE_TIMER_GET_OFFSET(ntohs(packet->syt)),
88         m_running);
89
90     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
91         "RCV: CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d\n",
92         channel, packet->fdf,
93         packet->syt,
94         packet->dbs,
95         packet->dbc,
96         packet->fmt,
97         length);
98
99 #endif
100
101     // check if this is a valid packet
102     if((packet->syt != 0xFFFF)
103        && (packet->fdf != 0xFF)
104        && (packet->fmt == 0x10)
105        && (packet->dbs>0)
106        && (length>=2*sizeof(quadlet_t))) {
107
108         unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;
109
110         //=> store the previous timestamp
111         m_last_timestamp2=m_last_timestamp;
112
113         uint64_t nowX = m_handler->getCycleTimer();
114         //=> convert the SYT to a full timestamp in ticks
115         m_last_timestamp=sytRecvToFullTicks((uint32_t)ntohs(packet->syt),
116                                         cycle, nowX);
117
118         int64_t diffx = diffTicks(m_last_timestamp, m_last_timestamp2);
119         if (abs(diffx) > m_syt_interval * m_data_buffer->getRate() * 1.1) {
120             uint32_t now=m_handler->getCycleTimer();
121             uint32_t syt = (uint32_t)ntohs(packet->syt);
122             uint32_t now_ticks=CYCLE_TIMER_TO_TICKS(now);
123            
124             debugOutput(DEBUG_LEVEL_VERBOSE, "diff=%06lld TS=%011llu TS2=%011llu\n",
125                 diffx, m_last_timestamp, m_last_timestamp2);
126             debugOutput(DEBUG_LEVEL_VERBOSE, "[1] cy=%04d dropped=%05llu syt=%04llX NOW=%08llX => TS=%011llu\n",
127                 m_last_good_cycle, m_last_dropped, m_last_syt, m_last_now, m_last_timestamp2);
128             debugOutput(DEBUG_LEVEL_VERBOSE, "[2] cy=%04d dropped=%05d syt=%04X NOW=%08llX => TS=%011llu\n",
129                 cycle, dropped_cycles, ntohs(packet->syt), nowX, m_last_timestamp);
130
131             uint32_t test_ts=sytRecvToFullTicks(syt, cycle, now);
132
133             debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: SYT=%08X,            CY=%04d OFF=%04d\n",
134                 cycle, syt, CYCLE_TIMER_GET_CYCLES(syt), CYCLE_TIMER_GET_OFFSET(syt)
135                 );
136             debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: NOW=%011lu, SEC=%03u CY=%04u OFF=%04u\n",
137                 cycle, now_ticks, CYCLE_TIMER_GET_SECS(now), CYCLE_TIMER_GET_CYCLES(now), CYCLE_TIMER_GET_OFFSET(now)
138                 );
139             debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: TSS=%011lu, SEC=%03u CY=%04u OFF=%04u\n",
140                 cycle, test_ts, TICKS_TO_SECS(test_ts), TICKS_TO_CYCLES(test_ts), TICKS_TO_OFFSET(test_ts)
141                 );
142                
143             int64_t diff_ts = diffTicks(now_ticks, test_ts);
144             debugOutput(DEBUG_LEVEL_VERBOSE, "DIFF  : TCK=%011lld, SEC=%03llu CY=%04llu OFF=%04llu\n",
145                 diff_ts,
146                 TICKS_TO_SECS((uint64_t)diff_ts),
147                 TICKS_TO_CYCLES((uint64_t)diff_ts),
148                 TICKS_TO_OFFSET((uint64_t)diff_ts)
149                 );
150         }
151         m_last_syt = ntohs(packet->syt);
152         m_last_now = nowX;
153         m_last_good_cycle = cycle;
154         m_last_dropped = dropped_cycles;
155
156         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "RECV: CY=%04u TS=%011llu\n",
157                 cycle, m_last_timestamp);
158
159         // we have to keep in mind that there are also
160         // some packets buffered by the ISO layer,
161         // at most x=m_handler->getWakeupInterval()
162         // these contain at most x*syt_interval
163         // frames, meaning that we might receive
164         // this packet x*syt_interval*ticks_per_frame
165         // later than expected (the real receive time)
166         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"STMP: %lluticks | buff=%d, syt_interval=%d, tpf=%f\n",
167             m_last_timestamp, m_handler->getWakeupInterval(),m_syt_interval,getTicksPerFrame());
168
169         //=> signal that we're running (if we are)
170         if(!m_running && nevents && m_last_timestamp2 && m_last_timestamp) {
171             debugOutput(DEBUG_LEVEL_VERBOSE,"Receive StreamProcessor %p started running at %d\n", this, cycle);
172             m_running=true;
173             m_data_buffer->setBufferTailTimestamp(m_last_timestamp);
174             // we don't want this first sample to be written
175             return RAW1394_ISO_OK;
176         }
177
178         // if we are not running yet, there is nothing more to do
179         if(!m_running) {
180             return RAW1394_ISO_OK;
181         }
182         #ifdef DEBUG_OFF
183         if((cycle % 1000) == 0) {
184             uint32_t now=m_handler->getCycleTimer();
185             uint32_t syt = (uint32_t)ntohs(packet->syt);
186             uint32_t now_ticks=CYCLE_TIMER_TO_TICKS(now);
187
188             uint32_t test_ts=sytRecvToFullTicks(syt, cycle, now);
189
190             debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: SYT=%08X,            CY=%02d OFF=%04d\n",
191                 cycle, syt, CYCLE_TIMER_GET_CYCLES(syt), CYCLE_TIMER_GET_OFFSET(syt)
192                 );
193             debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: NOW=%011lu, SEC=%03u CY=%02u OFF=%04u\n",
194                 cycle, now_ticks, CYCLE_TIMER_GET_SECS(now), CYCLE_TIMER_GET_CYCLES(now), CYCLE_TIMER_GET_OFFSET(now)
195                 );
196             debugOutput(DEBUG_LEVEL_VERBOSE, "R %04d: TSS=%011lu, SEC=%03u CY=%02u OFF=%04u\n",
197                 cycle, test_ts, TICKS_TO_SECS(test_ts), TICKS_TO_CYCLES(test_ts), TICKS_TO_OFFSET(test_ts)
198                 );
199         }
200         #endif
201
202         #ifdef DEBUG
203             // keep track of the lag
204             uint32_t now=m_handler->getCycleTimer();
205             int32_t diff = diffCycles( cycle,  ((int)CYCLE_TIMER_GET_CYCLES(now)) );
206             m_PacketStat.mark(diff);
207         #endif
208
209         //=> process the packet
210         // add the data payload to the ringbuffer
211        
212         if(dropped_cycles) {
213             debugWarning("(%p) Correcting timestamp for dropped cycles, discarding packet...\n", this);
214             m_data_buffer->setBufferTailTimestamp(m_last_timestamp);
215             // we don't want this first sample to be written
216             return RAW1394_ISO_OK;
217         }
218        
219         if(m_data_buffer->writeFrames(nevents, (char *)(data+8), m_last_timestamp)) {
220             retval=RAW1394_ISO_OK;
221
222             // process all ports that should be handled on a per-packet base
223             // this is MIDI for AMDTP (due to the need of DBC)
224             if (!decodePacketPorts((quadlet_t *)(data+8), nevents, packet->dbc)) {
225                 debugWarning("Problem decoding Packet Ports\n");
226                 retval=RAW1394_ISO_DEFER;
227             }
228
229         } else {
230
231 //             debugWarning("Receive buffer overrun (cycle %d, FC=%d, PC=%d)\n",
232 //                  cycle, m_data_buffer->getFrameCounter(), m_handler->getPacketCount());
233
234             m_xruns++;
235
236             retval=RAW1394_ISO_DEFER;
237         }
238     }
239
240     return retval;
241 }
242
243 void AmdtpReceiveStreamProcessor::dumpInfo() {
244     StreamProcessor::dumpInfo();
245 }
246
247 bool AmdtpReceiveStreamProcessor::reset() {
248
249     debugOutput( DEBUG_LEVEL_VERBOSE, "Resetting...\n");
250
251     m_PeriodStat.reset();
252     m_PacketStat.reset();
253     m_WakeupStat.reset();
254
255     m_data_buffer->setTickOffset(0);
256
257     // reset all non-device specific stuff
258     // i.e. the iso stream and the associated ports
259     if(!ReceiveStreamProcessor::reset()) {
260             debugFatal("Could not do base class reset\n");
261             return false;
262     }
263     return true;
264 }
265
266 bool AmdtpReceiveStreamProcessor::prepare() {
267
268     m_PeriodStat.setName("RCV PERIOD");
269     m_PacketStat.setName("RCV PACKET");
270     m_WakeupStat.setName("RCV WAKEUP");
271
272     debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this);
273
274     // prepare all non-device specific stuff
275     // i.e. the iso stream and the associated ports
276     if(!ReceiveStreamProcessor::prepare()) {
277         debugFatal("Could not prepare base class\n");
278         return false;
279     }
280
281     switch (m_framerate) {
282     case 32000:
283         m_syt_interval = 8;
284         break;
285     case 44100:
286         m_syt_interval = 8;
287         break;
288     default:
289     case 48000:
290         m_syt_interval = 8;
291         break;
292     case 88200:
293         m_syt_interval = 16;
294         break;
295     case 96000:
296         m_syt_interval = 16;
297         break;
298     case 176400:
299         m_syt_interval = 32;
300         break;
301     case 192000:
302         m_syt_interval = 32;
303         break;
304     }
305
306     // prepare the framerate estimate
307     float ticks_per_frame = (TICKS_PER_SECOND*1.0) / ((float)m_framerate);
308     m_ticks_per_frame=ticks_per_frame;
309
310     debugOutput(DEBUG_LEVEL_VERBOSE,"Initializing remote ticks/frame to %f\n",ticks_per_frame);
311
312     // initialize internal buffer
313     unsigned int ringbuffer_size_frames=m_nb_buffers * m_period;
314
315     assert(m_data_buffer);
316     m_data_buffer->setBufferSize(ringbuffer_size_frames * 2);
317     m_data_buffer->setEventSize(sizeof(quadlet_t));
318     m_data_buffer->setEventsPerFrame(m_dimension);
319
320     // the buffer is written every syt_interval
321     m_data_buffer->setUpdatePeriod(m_syt_interval);
322     m_data_buffer->setNominalRate(ticks_per_frame);
323
324     m_data_buffer->setWrapValue(128L*TICKS_PER_SECOND);
325
326     m_data_buffer->prepare();
327
328     // set the parameters of ports we can:
329     // we want the audio ports to be period buffered,
330     // and the midi ports to be packet buffered
331     for ( PortVectorIterator it = m_Ports.begin();
332           it != m_Ports.end();
333           ++it )
334     {
335         debugOutput(DEBUG_LEVEL_VERBOSE, "Setting up port %s\n",(*it)->getName().c_str());
336         if(!(*it)->setBufferSize(m_period)) {
337             debugFatal("Could not set buffer size to %d\n",m_period);
338             return false;
339         }
340
341         switch ((*it)->getPortType()) {
342             case Port::E_Audio:
343                 if(!(*it)->setSignalType(Port::E_PeriodSignalled)) {
344                     debugFatal("Could not set signal type to PeriodSignalling");
345                     return false;
346                 }
347                 // buffertype and datatype are dependant on the API
348                 debugWarning("---------------- ! Doing hardcoded dummy setup ! --------------\n");
349                 // buffertype and datatype are dependant on the API
350                 if(!(*it)->setBufferType(Port::E_PointerBuffer)) {
351                     debugFatal("Could not set buffer type");
352                     return false;
353                 }
354                 if(!(*it)->useExternalBuffer(true)) {
355                     debugFatal("Could not set external buffer usage");
356                     return false;
357                 }
358                 if(!(*it)->setDataType(Port::E_Float)) {
359                     debugFatal("Could not set data type");
360                     return false;
361                 }
362                 break;
363             case Port::E_Midi:
364                 if(!(*it)->setSignalType(Port::E_PacketSignalled)) {
365                     debugFatal("Could not set signal type to PacketSignalling");
366                     return false;
367                 }
368                 // buffertype and datatype are dependant on the API
369                 // buffertype and datatype are dependant on the API
370                 debugWarning("---------------- ! Doing hardcoded test setup ! --------------\n");
371                 // buffertype and datatype are dependant on the API
372                 if(!(*it)->setBufferType(Port::E_RingBuffer)) {
373                     debugFatal("Could not set buffer type");
374                     return false;
375                 }
376                 if(!(*it)->setDataType(Port::E_MidiEvent)) {
377                     debugFatal("Could not set data type");
378                     return false;
379                 }
380                 break;
381             default:
382                 debugWarning("Unsupported port type specified\n");
383                 break;
384         }
385     }
386
387     // the API specific settings of the ports should already be set,
388     // as this is called from the processorManager->prepare()
389     // so we can init the ports
390     if(!initPorts()) {
391         debugFatal("Could not initialize ports!\n");
392         return false;
393     }
394
395     if(!preparePorts()) {
396         debugFatal("Could not initialize ports!\n");
397         return false;
398     }
399
400     debugOutput( DEBUG_LEVEL_VERBOSE, "Prepared for:\n");
401     debugOutput( DEBUG_LEVEL_VERBOSE, " Samplerate: %d, DBS: %d, SYT: %d\n",
402              m_framerate,m_dimension,m_syt_interval);
403     debugOutput( DEBUG_LEVEL_VERBOSE, " PeriodSize: %d, NbBuffers: %d\n",
404              m_period,m_nb_buffers);
405     debugOutput( DEBUG_LEVEL_VERBOSE, " Port: %d, Channel: %d\n",
406              m_port,m_channel);
407
408     return true;
409
410 }
411
412 bool AmdtpReceiveStreamProcessor::prepareForStart() {
413     disable();
414     return true;
415 }
416
417 bool AmdtpReceiveStreamProcessor::prepareForStop() {
418     disable();
419     return true;
420 }
421
422 bool AmdtpReceiveStreamProcessor::getFrames(unsigned int nbframes, int64_t ts) {
423     m_PeriodStat.mark(m_data_buffer->getBufferFill());
424
425 #ifdef DEBUG
426     uint64_t ts_head;
427     signed int fc;
428     int32_t lag_ticks;
429     float lag_frames;
430
431     // in order to sync up multiple received streams, we should
432     // use the ts parameter. It specifies the time of the block's
433     // first sample.
434    
435     ffado_timestamp_t ts_head_tmp;
436     m_data_buffer->getBufferHeadTimestamp(&ts_head_tmp, &fc);
437     ts_head=(uint64_t)ts_head_tmp;
438     lag_ticks=diffTicks(ts, ts_head);
439     float rate=m_data_buffer->getRate();
440    
441     assert(rate!=0.0);
442    
443     lag_frames=(((float)lag_ticks)/rate);
444    
445     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "stream (%p): drifts %6d ticks = %10.5f frames (rate=%10.5f), %lld, %llu, %d\n",
446                  this, lag_ticks, lag_frames,rate, ts, ts_head, fc);
447
448     if (lag_frames>=1.0) {
449         // the stream lags
450         debugWarning( "stream (%p): lags  with %6d ticks = %10.5f frames (rate=%10.5f), %lld, %llu, %d\n",
451                       this, lag_ticks, lag_frames,rate, ts, ts_head, fc);
452     } else if (lag_frames<=-1.0) {
453         // the stream leads
454         debugWarning( "stream (%p): leads with %6d ticks = %10.5f frames (rate=%10.5f), %lld, %llu, %d\n",
455                       this, lag_ticks, lag_frames,rate, ts, ts_head, fc);
456     }
457 #endif
458     // ask the buffer to process nbframes of frames
459     // using it's registered client's processReadBlock(),
460     // which should be ours
461     m_data_buffer->blockProcessReadFrames(nbframes);
462
463     return true;
464 }
465
466 bool AmdtpReceiveStreamProcessor::getFramesDry(unsigned int nbframes, int64_t ts) {
467     m_PeriodStat.mark(m_data_buffer->getBufferFill());
468     int frames_to_ditch=(int)(nbframes);
469     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "stream (%p): dry run %d frames (@ ts=%lld)\n",
470                  this, frames_to_ditch, ts);
471     char dummy[m_data_buffer->getBytesPerFrame()]; // one frame of garbage
472
473     while (frames_to_ditch--) {
474         m_data_buffer->readFrames(1, dummy);
475     }
476     return true;
477 }
478
479 /**
480  * \brief write received events to the stream ringbuffers.
481  */
482 bool AmdtpReceiveStreamProcessor::processReadBlock(char *data,
483                        unsigned int nevents, unsigned int offset)
484 {
485     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "(%p)->processReadBlock(%u, %u)\n",this,nevents,offset);
486
487     bool no_problem=true;
488
489     for ( PortVectorIterator it = m_PeriodPorts.begin();
490           it != m_PeriodPorts.end();
491           ++it )
492     {
493
494         if((*it)->isDisabled()) {continue;};
495
496         //FIXME: make this into a static_cast when not DEBUG?
497
498         AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);
499         assert(pinfo); // this should not fail!!
500
501         switch(pinfo->getFormat()) {
502         case AmdtpPortInfo::E_MBLA:
503             if(decodeMBLAEventsToPort(static_cast<AmdtpAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) {
504                 debugWarning("Could not decode packet MBLA to port %s",(*it)->getName().c_str());
505                 no_problem=false;
506             }
507             break;
508         case AmdtpPortInfo::E_SPDIF: // still unimplemented
509             break;
510     /* for this processor, midi is a packet based port
511         case AmdtpPortInfo::E_Midi:
512             break;*/
513         default: // ignore
514             break;
515         }
516     }
517     return no_problem;
518
519 }
520
521 /**
522  * @brief decode a packet for the packet-based ports
523  *
524  * @param data Packet data
525  * @param nevents number of events in data (including events of other ports & port types)
526  * @param dbc DataBlockCount value for this packet
527  * @return true if all successfull
528  */
529 bool AmdtpReceiveStreamProcessor::decodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc)
530 {
531     bool ok=true;
532
533     quadlet_t *target_event=NULL;
534     unsigned int j;
535
536     for ( PortVectorIterator it = m_PacketPorts.begin();
537           it != m_PacketPorts.end();
538           ++it )
539     {
540
541 #ifdef DEBUG
542         AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);
543         assert(pinfo); // this should not fail!!
544
545         // the only packet type of events for AMDTP is MIDI in mbla
546         assert(pinfo->getFormat()==AmdtpPortInfo::E_Midi);
547 #endif
548         AmdtpMidiPort *mp=static_cast<AmdtpMidiPort *>(*it);
549
550         // we decode this directly (no function call) due to the high frequency
551         /* idea:
552         spec says: current_midi_port=(dbc+j)%8;
553         => if we start at (dbc+stream->location-1)%8,
554         we'll start at the right event for the midi port.
555         => if we increment j with 8, we stay at the right event.
556         */
557         // FIXME: as we know in advance how big a packet is (syt_interval) we can
558         //        predict how much loops will be present here
559         for(j = (dbc & 0x07)+mp->getLocation(); j < nevents; j += 8) {
560             target_event=(quadlet_t *)(data + ((j * m_dimension) + mp->getPosition()));
561             quadlet_t sample_int=ntohl(*target_event);
562             // FIXME: this assumes that 2X and 3X speed isn't used,
563             // because only the 1X slot is put into the ringbuffer
564             if(IEC61883_AM824_GET_LABEL(sample_int) != IEC61883_AM824_LABEL_MIDI_NO_DATA) {
565                 sample_int=(sample_int >> 16) & 0x000000FF;
566                 if(!mp->writeEvent(&sample_int)) {
567                     debugWarning("Packet port events lost\n");
568                     ok=false;
569                 }
570             }
571         }
572
573     }
574
575     return ok;
576 }
577
578 int AmdtpReceiveStreamProcessor::decodeMBLAEventsToPort(AmdtpAudioPort *p, quadlet_t *data,
579                        unsigned int offset, unsigned int nevents)
580 {
581     unsigned int j=0;
582
583 //     printf("****************\n");
584 //     hexDumpQuadlets(data,m_dimension*4);
585 //     printf("****************\n");
586
587     quadlet_t *target_event;
588
589     target_event=(quadlet_t *)(data + p->getPosition());
590
591     switch(p->getDataType()) {
592         default:
593         case Port::E_Int24:
594             {
595                 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());
596
597                 assert(nevents + offset <= p->getBufferSize());
598
599                 buffer+=offset;
600
601                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
602                     *(buffer)=(ntohl((*target_event) ) & 0x00FFFFFF);
603                     buffer++;
604                     target_event+=m_dimension;
605                 }
606             }
607             break;
608         case Port::E_Float:
609             {
610                 const float multiplier = 1.0f / (float)(0x7FFFFF);
611                 float *buffer=(float *)(p->getBufferAddress());
612
613                 assert(nevents + offset <= p->getBufferSize());
614
615                 buffer+=offset;
616
617                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
618
619                     unsigned int v = ntohl(*target_event) & 0x00FFFFFF;
620                     // sign-extend highest bit of 24-bit int
621                     int tmp = (int)(v << 8) / 256;
622
623                     *buffer = tmp * multiplier;
624
625                     buffer++;
626                     target_event+=m_dimension;
627                 }
628             }
629             break;
630     }
631
632     return 0;
633 }
634
635 } // end of namespace Streaming
Note: See TracBrowser for help on using the browser.