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

Revision 722, 12.6 kB (checked in by ppalmers, 13 years ago)

more rewrite of streaming

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