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

Revision 719, 12.6 kB (checked in by ppalmers, 15 years ago)

backup commit

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 #include "../StreamProcessorManager.h"
27
28 #include "../util/cycletimer.h"
29
30 #include <netinet/in.h>
31 #include <assert.h>
32
33 // in ticks
34 // as per AMDTP2.1:
35 // 354.17us + 125us @ 24.576ticks/usec = 11776.08192 ticks
36 #define DEFAULT_TRANSFER_DELAY (11776U)
37
38 #define TRANSMIT_TRANSFER_DELAY DEFAULT_TRANSFER_DELAY
39
40 namespace Streaming {
41
42 /* --------------------- RECEIVE ----------------------- */
43
44 AmdtpReceiveStreamProcessor::AmdtpReceiveStreamProcessor(int port, int dimension)
45     : StreamProcessor(ePT_Receive , port)
46     , m_dimension(dimension)
47 {}
48
49
50 unsigned int
51 AmdtpReceiveStreamProcessor::getPacketsPerPeriod()
52 {
53     return (m_manager->getPeriodSize())/m_syt_interval;
54 }
55
56 bool AmdtpReceiveStreamProcessor::prepareChild() {
57
58     m_PeriodStat.setName("RCV PERIOD");
59     m_PacketStat.setName("RCV PACKET");
60     m_WakeupStat.setName("RCV WAKEUP");
61
62     debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this);
63
64     switch (m_manager->getNominalRate()) {
65         case 32000:
66         case 44100:
67         case 48000:
68             m_syt_interval = 8;
69             break;
70         case 88200:
71         case 96000:
72             m_syt_interval = 16;
73             break;
74         case 176400:
75         case 192000:
76             m_syt_interval = 32;
77             break;
78         default:
79             debugError("Unsupported rate: %d\n", m_manager->getNominalRate());
80             return false;
81     }
82
83     debugOutput( DEBUG_LEVEL_VERBOSE, "Prepared for:\n");
84     debugOutput( DEBUG_LEVEL_VERBOSE, " Samplerate: %d, DBS: %d, SYT: %d\n",
85              m_manager->getNominalRate(), m_dimension, m_syt_interval);
86     debugOutput( DEBUG_LEVEL_VERBOSE, " PeriodSize: %d, NbBuffers: %d\n",
87              m_manager->getPeriodSize(), m_manager->getNbBuffers());
88     debugOutput( DEBUG_LEVEL_VERBOSE, " Port: %d, Channel: %d\n",
89              m_port,m_channel);
90
91     return true;
92 }
93
94
95 /**
96  * Processes packet header to extract timestamps and so on
97  * @param data
98  * @param length
99  * @param channel
100  * @param tag
101  * @param sy
102  * @param cycle
103  * @param dropped
104  * @return true if this is a valid packet, false if not
105  */
106 bool
107 AmdtpReceiveStreamProcessor::processPacketHeader(unsigned char *data, unsigned int length,
108                   unsigned char channel, unsigned char tag, unsigned char sy,
109                   unsigned int cycle, unsigned int dropped)
110 {
111     struct iec61883_packet *packet = (struct iec61883_packet *) data;
112     assert(packet);
113     bool retval = (packet->syt != 0xFFFF) &&
114                   (packet->fdf != 0xFF) &&
115                   (packet->fmt == 0x10) &&
116                   (packet->dbs > 0) &&
117                   (length >= 2*sizeof(quadlet_t));
118     if(retval) {
119         uint64_t now = m_handler->getCycleTimer();
120         //=> convert the SYT to a full timestamp in ticks
121         m_last_timestamp = sytRecvToFullTicks((uint32_t)ntohs(packet->syt),
122                                               cycle, now);
123     }
124     return retval;
125 }
126
127 /**
128  * extract the data from the packet
129  * @pre the IEC61883 packet is valid according to isValidPacket
130  * @param data
131  * @param length
132  * @param channel
133  * @param tag
134  * @param sy
135  * @param cycle
136  * @param dropped
137  * @return true if successful, false if xrun
138  */
139 bool
140 AmdtpReceiveStreamProcessor::processPacketData(unsigned char *data, unsigned int length,
141                   unsigned char channel, unsigned char tag, unsigned char sy,
142                   unsigned int cycle, unsigned int dropped_cycles) {
143     struct iec61883_packet *packet = (struct iec61883_packet *) data;
144     assert(packet);
145
146     unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs;
147
148     // we have to keep in mind that there are also
149     // some packets buffered by the ISO layer,
150     // at most x=m_handler->getWakeupInterval()
151     // these contain at most x*syt_interval
152     // frames, meaning that we might receive
153     // this packet x*syt_interval*ticks_per_frame
154     // later than expected (the real receive time)
155     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"STMP: %lluticks | buff=%d, syt_interval=%d, tpf=%f\n",
156         m_last_timestamp, m_handler->getWakeupInterval(), m_syt_interval, getTicksPerFrame());
157
158     if(m_data_buffer->writeFrames(nevents, (char *)(data+8), m_last_timestamp)) {
159         // process all ports that should be handled on a per-packet base
160         // this is MIDI for AMDTP (due to the need of DBC)
161         if (!decodePacketPorts((quadlet_t *)(data+8), nevents, packet->dbc)) {
162             debugWarning("Problem decoding Packet Ports\n");
163         }
164         return true;
165     } else {
166         return false;
167     }
168 }
169
170 /***********************************************
171  * Encoding/Decoding API                       *
172  ***********************************************/
173 /**
174  * @brief write received events to the stream ringbuffers.
175  */
176 bool AmdtpReceiveStreamProcessor::processReadBlock(char *data,
177                        unsigned int nevents, unsigned int offset)
178 {
179     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "(%p)->processReadBlock(%u, %u)\n",this,nevents,offset);
180
181     bool no_problem=true;
182
183     for ( PortVectorIterator it = m_PeriodPorts.begin();
184           it != m_PeriodPorts.end();
185           ++it )
186     {
187         if((*it)->isDisabled()) {continue;};
188
189         //FIXME: make this into a static_cast when not DEBUG?
190
191         AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);
192         assert(pinfo); // this should not fail!!
193
194         switch(pinfo->getFormat()) {
195         case AmdtpPortInfo::E_MBLA:
196             if(decodeMBLAEventsToPort(static_cast<AmdtpAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) {
197                 debugWarning("Could not decode packet MBLA to port %s",(*it)->getName().c_str());
198                 no_problem=false;
199             }
200             break;
201         case AmdtpPortInfo::E_SPDIF: // still unimplemented
202             break;
203     /* for this processor, midi is a packet based port
204         case AmdtpPortInfo::E_Midi:
205             break;*/
206         default: // ignore
207             break;
208         }
209     }
210     return no_problem;
211 }
212
213 /**
214  * @brief write silence events to the stream ringbuffers.
215  */
216 bool AmdtpReceiveStreamProcessor::provideSilenceBlock(unsigned int nevents, unsigned int offset)
217 {
218     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "(%p)->proviceSilenceBlock(%u, %u)\n", this, nevents, offset);
219
220     bool no_problem=true;
221
222     for ( PortVectorIterator it = m_PeriodPorts.begin();
223           it != m_PeriodPorts.end();
224           ++it )
225     {
226         if((*it)->isDisabled()) {continue;};
227         //FIXME: make this into a static_cast when not DEBUG?
228         AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);
229         assert(pinfo); // this should not fail!!
230
231         switch(pinfo->getFormat()) {
232         case AmdtpPortInfo::E_MBLA:
233             if(provideSilenceToPort(static_cast<AmdtpAudioPort *>(*it), offset, nevents)) {
234                 debugWarning("Could not put silence into to port %s",(*it)->getName().c_str());
235                 no_problem=false;
236             }
237             break;
238         case AmdtpPortInfo::E_SPDIF: // still unimplemented
239             break;
240     /* for this processor, midi is a packet based port
241         case AmdtpPortInfo::E_Midi:
242             break;*/
243         default: // ignore
244             break;
245         }
246     }
247     return no_problem;
248 }
249
250 /**
251  * @brief decode a packet for the packet-based ports
252  *
253  * @param data Packet data
254  * @param nevents number of events in data (including events of other ports & port types)
255  * @param dbc DataBlockCount value for this packet
256  * @return true if all successfull
257  */
258 bool AmdtpReceiveStreamProcessor::decodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc)
259 {
260     bool ok=true;
261
262     quadlet_t *target_event=NULL;
263     unsigned int j;
264
265     for ( PortVectorIterator it = m_PacketPorts.begin();
266           it != m_PacketPorts.end();
267           ++it )
268     {
269
270 #ifdef DEBUG
271         AmdtpPortInfo *pinfo=dynamic_cast<AmdtpPortInfo *>(*it);
272         assert(pinfo); // this should not fail!!
273
274         // the only packet type of events for AMDTP is MIDI in mbla
275         assert(pinfo->getFormat()==AmdtpPortInfo::E_Midi);
276 #endif
277         AmdtpMidiPort *mp=static_cast<AmdtpMidiPort *>(*it);
278
279         // we decode this directly (no function call) due to the high frequency
280         /* idea:
281         spec says: current_midi_port=(dbc+j)%8;
282         => if we start at (dbc+stream->location-1)%8,
283         we'll start at the right event for the midi port.
284         => if we increment j with 8, we stay at the right event.
285         */
286         // FIXME: as we know in advance how big a packet is (syt_interval) we can
287         //        predict how much loops will be present here
288         for(j = (dbc & 0x07)+mp->getLocation(); j < nevents; j += 8) {
289             target_event=(quadlet_t *)(data + ((j * m_dimension) + mp->getPosition()));
290             quadlet_t sample_int=ntohl(*target_event);
291             // FIXME: this assumes that 2X and 3X speed isn't used,
292             // because only the 1X slot is put into the ringbuffer
293             if(IEC61883_AM824_GET_LABEL(sample_int) != IEC61883_AM824_LABEL_MIDI_NO_DATA) {
294                 sample_int=(sample_int >> 16) & 0x000000FF;
295                 if(!mp->writeEvent(&sample_int)) {
296                     debugWarning("Packet port events lost\n");
297                     ok=false;
298                 }
299             }
300         }
301
302     }
303
304     return ok;
305 }
306
307 int
308 AmdtpReceiveStreamProcessor::decodeMBLAEventsToPort(
309                        AmdtpAudioPort *p, quadlet_t *data,
310                        unsigned int offset, unsigned int nevents)
311 {
312     unsigned int j=0;
313     quadlet_t *target_event;
314
315     target_event=(quadlet_t *)(data + p->getPosition());
316
317     switch(p->getDataType()) {
318         default:
319         case Port::E_Int24:
320             {
321                 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());
322
323                 assert(nevents + offset <= p->getBufferSize());
324
325                 buffer+=offset;
326
327                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
328                     *(buffer)=(ntohl((*target_event) ) & 0x00FFFFFF);
329                     buffer++;
330                     target_event+=m_dimension;
331                 }
332             }
333             break;
334         case Port::E_Float:
335             {
336                 const float multiplier = 1.0f / (float)(0x7FFFFF);
337                 float *buffer=(float *)(p->getBufferAddress());
338
339                 assert(nevents + offset <= p->getBufferSize());
340
341                 buffer+=offset;
342
343                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
344
345                     unsigned int v = ntohl(*target_event) & 0x00FFFFFF;
346                     // sign-extend highest bit of 24-bit int
347                     int tmp = (int)(v << 8) / 256;
348
349                     *buffer = tmp * multiplier;
350
351                     buffer++;
352                     target_event+=m_dimension;
353                 }
354             }
355             break;
356     }
357
358     return 0;
359 }
360
361 int
362 AmdtpReceiveStreamProcessor::provideSilenceToPort(
363                        AmdtpAudioPort *p, unsigned int offset, unsigned int nevents)
364 {
365     unsigned int j=0;
366     switch(p->getDataType()) {
367         default:
368         case Port::E_Int24:
369             {
370                 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());
371                 assert(nevents + offset <= p->getBufferSize());
372                 buffer+=offset;
373
374                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
375                     *(buffer)=0;
376                     buffer++;
377                 }
378             }
379             break;
380         case Port::E_Float:
381             {
382                 float *buffer=(float *)(p->getBufferAddress());
383                 assert(nevents + offset <= p->getBufferSize());
384                 buffer+=offset;
385
386                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
387                     *buffer = 0.0;
388                     buffer++;
389                 }
390             }
391             break;
392     }
393     return 0;
394 }
395
396 } // end of namespace Streaming
Note: See TracBrowser for help on using the browser.