root/branches/api-cleanup/src/libstreaming/motu/MotuReceiveStreamProcessor.cpp

Revision 809, 10.8 kB (checked in by ppalmers, 14 years ago)

First round of cleanup:
- make Ports auto-register to a PortManager?
- remove the different 'signal' types, everything is now period-signaled.
- removed obsolete streaming test programs

Line 
1 /*
2  * Copyright (C) 2005-2007 by Jonathan Woithe
3  * Copyright (C) 2005-2007 by Pieter Palmers
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB.
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include "MotuReceiveStreamProcessor.h"
26 #include "MotuPort.h"
27 #include "../StreamProcessorManager.h"
28 #include "devicemanager.h"
29
30 #include "libieee1394/ieee1394service.h"
31 #include "libieee1394/IsoHandlerManager.h"
32 #include "libieee1394/cycletimer.h"
33
34 #include <math.h>
35 #include <netinet/in.h>
36 #include <assert.h>
37
38 namespace Streaming {
39
40 // A macro to extract specific bits from a native endian quadlet
41 #define get_bits(_d,_start,_len) (((_d)>>((_start)-(_len)+1)) & ((1<<(_len))-1))
42
43 // Convert an SPH timestamp as received from the MOTU to a full timestamp in ticks.
44 static inline uint32_t sphRecvToFullTicks(uint32_t sph, uint32_t ct_now) {
45
46 uint32_t timestamp = CYCLE_TIMER_TO_TICKS(sph & 0x1ffffff);
47 uint32_t now_cycles = CYCLE_TIMER_GET_CYCLES(ct_now);
48
49 uint32_t ts_sec = CYCLE_TIMER_GET_SECS(ct_now);
50     // If the cycles have wrapped, correct ts_sec so it represents when timestamp
51     // was received.  The timestamps sent by the MOTU are always 1 or two cycles
52     // in advance of the cycle timer (reasons unknown at this stage).  In addition,
53     // iso buffering can delay the arrival of packets for quite a number of cycles
54     // (have seen a delay >12 cycles).
55     // Every so often we also see sph wrapping ahead of ct_now, so deal with that
56     // too.
57     if (CYCLE_TIMER_GET_CYCLES(sph) > now_cycles + 1000) {
58         if (ts_sec)
59             ts_sec--;
60         else
61             ts_sec = 127;
62     } else
63     if (now_cycles > CYCLE_TIMER_GET_CYCLES(sph) + 1000) {
64         if (ts_sec == 127)
65             ts_sec = 0;
66         else
67             ts_sec++;
68     }
69     return timestamp + ts_sec*TICKS_PER_SECOND;
70 }
71
72 MotuReceiveStreamProcessor::MotuReceiveStreamProcessor(FFADODevice &parent, unsigned int event_size)
73     : StreamProcessor(parent, ePT_Receive)
74     , m_event_size( event_size )
75 {}
76
77 unsigned int
78 MotuReceiveStreamProcessor::getMaxPacketSize() {
79     int framerate = m_Parent.getDeviceManager().getStreamProcessorManager().getNominalRate();
80     return framerate<=48000?616:(framerate<=96000?1032:1160);
81 }
82
83 unsigned int
84 MotuReceiveStreamProcessor::getNominalFramesPerPacket() {
85     int framerate = m_Parent.getDeviceManager().getStreamProcessorManager().getNominalRate();
86     return framerate<=48000?8:(framerate<=96000?16:32);
87 }
88
89 bool
90 MotuReceiveStreamProcessor::prepareChild() {
91     debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this);
92
93     // prepare the framerate estimate
94     // FIXME: not needed anymore?
95     //m_ticks_per_frame = (TICKS_PER_SECOND*1.0) / ((float)m_Parent.getDeviceManager().getStreamProcessorManager().getNominalRate());
96
97     return true;
98 }
99
100
101 /**
102  * Processes packet header to extract timestamps and check if the packet is valid
103  * @param data
104  * @param length
105  * @param channel
106  * @param tag
107  * @param sy
108  * @param cycle
109  * @param dropped
110  * @return
111  */
112 enum StreamProcessor::eChildReturnValue
113 MotuReceiveStreamProcessor::processPacketHeader(unsigned char *data, unsigned int length,
114                   unsigned char channel, unsigned char tag, unsigned char sy,
115                   unsigned int cycle, unsigned int dropped)
116 {
117     if (length > 8) {
118         // The iso data blocks from the MOTUs comprise a CIP-like
119         // header followed by a number of events (8 for 1x rates, 16
120         // for 2x rates, 32 for 4x rates).
121         quadlet_t *quadlet = (quadlet_t *)data;
122         unsigned int dbs = get_bits(ntohl(quadlet[0]), 23, 8);  // Size of one event in terms of fdf_size
123         unsigned int fdf_size = get_bits(ntohl(quadlet[1]), 23, 8) == 0x22 ? 32:0; // Event unit size in bits
124
125         // Don't even attempt to process a packet if it isn't what
126         // we expect from a MOTU.  Yes, an FDF value of 32 bears
127         // little relationship to the actual data (24 bit integer)
128         // sent by the MOTU - it's one of those areas where MOTU
129         // have taken a curious detour around the standards.
130         if (tag!=1 || fdf_size!=32) {
131             return eCRV_Invalid;
132         }
133
134         // put this after the check because event_length can become 0 on invalid packets
135         unsigned int event_length = (fdf_size * dbs) / 8;       // Event size in bytes
136         unsigned int n_events = (length-8) / event_length;
137
138         // Acquire the timestamp of the last frame in the packet just
139         // received.  Since every frame from the MOTU has its own timestamp
140         // we can just pick it straight from the packet.
141         uint32_t last_sph = ntohl(*(quadlet_t *)(data+8+(n_events-1)*event_length));
142         m_last_timestamp = sphRecvToFullTicks(last_sph, m_Parent.get1394Service().getCycleTimer());
143         return eCRV_OK;
144     } else {
145         return eCRV_Invalid;
146     }
147 }
148
149 /**
150  * extract the data from the packet
151  * @pre the IEC61883 packet is valid according to isValidPacket
152  * @param data
153  * @param length
154  * @param channel
155  * @param tag
156  * @param sy
157  * @param cycle
158  * @param dropped
159  * @return
160  */
161 enum StreamProcessor::eChildReturnValue
162 MotuReceiveStreamProcessor::processPacketData(unsigned char *data, unsigned int length,
163                   unsigned char channel, unsigned char tag, unsigned char sy,
164                   unsigned int cycle, unsigned int dropped_cycles) {
165     quadlet_t* quadlet = (quadlet_t*) data;
166
167     unsigned int dbs = get_bits(ntohl(quadlet[0]), 23, 8);  // Size of one event in terms of fdf_size
168     unsigned int fdf_size = get_bits(ntohl(quadlet[1]), 23, 8) == 0x22 ? 32:0; // Event unit size in bits
169     // this is only called for packets that return eCRV_OK on processPacketHeader
170     // so event_length won't become 0
171     unsigned int event_length = (fdf_size * dbs) / 8;       // Event size in bytes
172     unsigned int n_events = (length-8) / event_length;
173
174     // we have to keep in mind that there are also
175     // some packets buffered by the ISO layer,
176     // at most x=m_handler->getWakeupInterval()
177     // these contain at most x*syt_interval
178     // frames, meaning that we might receive
179     // this packet x*syt_interval*ticks_per_frame
180     // later than expected (the real receive time)
181     #ifdef DEBUG
182     if(isRunning()) {
183         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"STMP: %lluticks | tpf=%f\n",
184             m_last_timestamp, getTicksPerFrame());
185     }
186     #endif
187
188     if(m_data_buffer->writeFrames(n_events, (char *)(data+8), m_last_timestamp)) {
189         return eCRV_OK;
190     } else {
191         return eCRV_XRun;
192     }
193 }
194
195 /***********************************************
196  * Encoding/Decoding API                       *
197  ***********************************************/
198 /**
199  * \brief write received events to the port ringbuffers.
200  */
201 bool MotuReceiveStreamProcessor::processReadBlock(char *data,
202                        unsigned int nevents, unsigned int offset)
203 {
204     bool no_problem=true;
205     for ( PortVectorIterator it = m_Ports.begin();
206           it != m_Ports.end();
207           ++it ) {
208         if((*it)->isDisabled()) {continue;};
209
210         Port *port=(*it);
211
212         switch(port->getPortType()) {
213
214         case Port::E_Audio:
215             if(decodeMotuEventsToPort(static_cast<MotuAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) {
216                 debugWarning("Could not decode packet data to port %s",(*it)->getName().c_str());
217                 no_problem=false;
218             }
219             break;
220         case Port::E_Midi:
221 //             if(decodeMotuMidiEventsToPort(static_cast<MotuMidiPort *>(*it), (quadlet_t *)data, offset, nevents)) {
222 //                 debugWarning("Could not decode packet midi data to port %s",(*it)->getName().c_str());
223 //                 no_problem=false;
224 //             }
225             break;
226
227         default: // ignore
228             break;
229         }
230     }
231     return no_problem;
232 }
233
234 signed int MotuReceiveStreamProcessor::decodeMotuEventsToPort(MotuAudioPort *p,
235         quadlet_t *data, unsigned int offset, unsigned int nevents)
236 {
237     unsigned int j=0;
238
239     // Use char here since a port's source address won't necessarily be
240     // aligned; use of an unaligned quadlet_t may cause issues on
241     // certain architectures.  Besides, the source (data coming directly
242     // from the MOTU) isn't structured in quadlets anyway; it mainly
243     // consists of packed 24-bit integers.
244
245     unsigned char *src_data;
246     src_data = (unsigned char *)data + p->getPosition();
247
248     switch(p->getDataType()) {
249         default:
250         case Port::E_Int24:
251             {
252                 quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());
253
254                 assert(nevents + offset <= p->getBufferSize());
255
256                 // Offset is in frames, but each port is only a single
257                 // channel, so the number of frames is the same as the
258                 // number of quadlets to offset (assuming the port buffer
259                 // uses one quadlet per sample, which is the case currently).
260                 buffer+=offset;
261
262                 for(j = 0; j < nevents; j += 1) { // Decode nsamples
263                     *buffer = (*src_data<<16)+(*(src_data+1)<<8)+*(src_data+2);
264                     // Sign-extend highest bit of 24-bit int.
265                     // FIXME: this isn't strictly needed since E_Int24 is a 24-bit,
266                     // but doing so shouldn't break anything and makes the data
267                     // easier to deal with during debugging.
268                     if (*src_data & 0x80)
269                         *buffer |= 0xff000000;
270
271                     buffer++;
272                     src_data+=m_event_size;
273                 }
274             }
275             break;
276         case Port::E_Float:
277             {
278                 const float multiplier = 1.0f / (float)(0x7FFFFF);
279                 float *buffer=(float *)(p->getBufferAddress());
280
281                 assert(nevents + offset <= p->getBufferSize());
282
283                 buffer+=offset;
284
285                 for(j = 0; j < nevents; j += 1) { // decode max nsamples
286
287                     unsigned int v = (*src_data<<16)+(*(src_data+1)<<8)+*(src_data+2);
288
289                     // sign-extend highest bit of 24-bit int
290                     int tmp = (int)(v << 8) / 256;
291
292                     *buffer = tmp * multiplier;
293
294                     buffer++;
295                     src_data+=m_event_size;
296                 }
297             }
298             break;
299     }
300
301     return 0;
302 }
303
304 } // end of namespace Streaming
Note: See TracBrowser for help on using the browser.