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

Revision 733, 10.1 kB (checked in by ppalmers, 13 years ago)

adapt motu code to new SP base class (compiles, needs real testing)

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