root/branches/ppalmers-streaming/src/libstreaming/generic/StreamProcessor.cpp

Revision 705, 11.0 kB (checked in by ppalmers, 16 years ago)

restructure the streaming directory

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 "StreamProcessor.h"
25 #include "../util/cycletimer.h"
26 #include "../StreamProcessorManager.h"
27
28 #include "libutil/Atomic.h"
29
30 #include <assert.h>
31 #include <math.h>
32
33 namespace Streaming {
34
35 IMPL_DEBUG_MODULE( StreamProcessor, StreamProcessor, DEBUG_LEVEL_VERBOSE );
36 IMPL_DEBUG_MODULE( ReceiveStreamProcessor, ReceiveStreamProcessor, DEBUG_LEVEL_VERBOSE );
37 IMPL_DEBUG_MODULE( TransmitStreamProcessor, TransmitStreamProcessor, DEBUG_LEVEL_VERBOSE );
38
39 StreamProcessor::StreamProcessor(enum IsoStream::EStreamType type, int port, int framerate)
40     : IsoStream(type, port)
41     , m_nb_buffers(0)
42     , m_period(0)
43     , m_xruns(0)
44     , m_framerate(framerate)
45     , m_manager(NULL)
46     , m_running(false)
47     , m_disabled(true)
48     , m_is_disabled(true)
49     , m_cycle_to_enable_at(0)
50     , m_SyncSource(NULL)
51     , m_ticks_per_frame(0)
52     , m_last_cycle(0)
53     , m_sync_delay(0)
54 {
55     // create the timestamped buffer and register ourselves as its client
56     m_data_buffer=new Util::TimestampedBuffer(this);
57
58 }
59
60 StreamProcessor::~StreamProcessor() {
61     if (m_data_buffer) delete m_data_buffer;
62 }
63
64 void StreamProcessor::dumpInfo()
65 {
66     debugOutputShort( DEBUG_LEVEL_NORMAL, " StreamProcessor information\n");
67     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Iso stream info:\n");
68
69     IsoStream::dumpInfo();
70     debugOutputShort( DEBUG_LEVEL_NORMAL, "  StreamProcessor info:\n");
71     if (m_handler)
72         debugOutputShort( DEBUG_LEVEL_NORMAL, "  Now                   : %011u\n",m_handler->getCycleTimerTicks());
73     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Xruns                 : %d\n", m_xruns);
74     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Running               : %d\n", m_running);
75     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Enabled               : %s\n", m_disabled ? "No" : "Yes");
76     debugOutputShort( DEBUG_LEVEL_NORMAL, "   enable status        : %s\n", m_is_disabled ? "No" : "Yes");
77
78     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Nominal framerate     : %u\n", m_framerate);
79     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Device framerate      : Sync: %f, Buffer %f\n",
80         24576000.0/m_SyncSource->m_data_buffer->getRate(),
81         24576000.0/m_data_buffer->getRate()
82         );
83
84     m_data_buffer->dumpInfo();
85
86 //     m_PeriodStat.dumpInfo();
87 //     m_PacketStat.dumpInfo();
88 //     m_WakeupStat.dumpInfo();
89
90 }
91
92 bool StreamProcessor::init()
93 {
94     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "enter...\n");
95
96     m_data_buffer->init();
97
98     return IsoStream::init();
99 }
100
101 /**
102  * Resets the frame counter, the xrun counter, the ports and the iso stream.
103  * @return true if reset succeeded
104  */
105 bool StreamProcessor::reset() {
106
107     debugOutput( DEBUG_LEVEL_VERBOSE, "Resetting...\n");
108
109     // reset the event buffer, discard all content
110     if (!m_data_buffer->reset()) {
111         debugFatal("Could not reset data buffer\n");
112         return false;
113     }
114
115     resetXrunCounter();
116
117     // loop over the ports to reset them
118     if (!PortManager::resetPorts()) {
119         debugFatal("Could not reset ports\n");
120         return false;
121     }
122
123     // reset the iso stream
124     if (!IsoStream::reset()) {
125         debugFatal("Could not reset isostream\n");
126         return false;
127     }
128     return true;
129
130 }
131
132 bool StreamProcessor::prepareForEnable(uint64_t time_to_enable_at) {
133     debugOutput(DEBUG_LEVEL_VERBOSE," StreamProcessor::prepareForEnable for (%p)\n",this);
134     debugOutput(DEBUG_LEVEL_VERBOSE,"  Now                   : %011u\n",m_handler->getCycleTimerTicks());
135     debugOutput(DEBUG_LEVEL_VERBOSE,"  Enable at             : %011u\n",time_to_enable_at);
136     m_data_buffer->dumpInfo();
137     return true;
138 }
139
140 bool StreamProcessor::prepareForDisable() {
141     debugOutput(DEBUG_LEVEL_VERBOSE," StreamProcessor::prepareForDisable for (%p)\n",this);
142     debugOutput(DEBUG_LEVEL_VERBOSE,"  Now                   : %011u\n",m_handler->getCycleTimerTicks());
143     m_data_buffer->dumpInfo();
144     return true;
145 }
146
147 bool StreamProcessor::prepare() {
148
149     debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing...\n");
150
151     // init the ports
152
153     if(!m_manager) {
154         debugFatal("Not attached to a manager!\n");
155         return -1;
156     }
157
158     m_nb_buffers=m_manager->getNbBuffers();
159     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting m_nb_buffers  : %d\n", m_nb_buffers);
160
161     m_period=m_manager->getPeriodSize();
162     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting m_period      : %d\n", m_period);
163
164     // loop over the ports to reset them
165     PortManager::preparePorts();
166
167     // reset the iso stream
168     IsoStream::prepare();
169
170     return true;
171
172 }
173
174 int StreamProcessor::getBufferFill() {
175 //     return m_data_buffer->getFrameCounter();
176     return m_data_buffer->getBufferFill();
177 }
178
179 uint64_t StreamProcessor::getTimeNow() {
180     return m_handler->getCycleTimerTicks();
181 }
182
183
184 bool StreamProcessor::isRunning() {
185     return m_running;
186 }
187
188 bool StreamProcessor::enable(uint64_t time_to_enable_at)  {
189     // FIXME: time_to_enable_at will be in 'time' not cycles
190     m_cycle_to_enable_at=time_to_enable_at;
191
192     if(!m_running) {
193             debugWarning("The StreamProcessor is not running yet, enable() might not be a good idea.\n");
194     }
195
196 #ifdef DEBUG
197     uint64_t now_cycles=CYCLE_TIMER_GET_CYCLES(m_handler->getCycleTimer());
198     const int64_t max=(int64_t)(CYCLES_PER_SECOND/2);
199
200     int64_t diff=(int64_t)m_cycle_to_enable_at-(int64_t)now_cycles;
201
202     if (diff > max) {
203         diff-=TICKS_PER_SECOND;
204     } else if (diff < -max) {
205         diff+=TICKS_PER_SECOND;
206     }
207
208     if (diff<0) {
209         debugWarning("Request to enable streamprocessor %lld cycles ago (now=%llu, cy=%llu).\n",
210             diff,now_cycles,time_to_enable_at);
211     }
212 #endif
213     m_data_buffer->enable();
214
215     m_disabled=false;
216     return true;
217 }
218
219 bool StreamProcessor::disable()  {
220     m_data_buffer->disable();
221     m_disabled=true;
222     return true;
223 }
224
225 bool StreamProcessor::setSyncSource(StreamProcessor *s) {
226     m_SyncSource=s;
227     return true;
228 }
229
230 float
231 StreamProcessor::getTicksPerFrame() {
232     if (m_data_buffer) {
233         float rate=m_data_buffer->getRate();
234         if (fabsf(m_ticks_per_frame - rate)>(m_ticks_per_frame*0.1)) {
235             debugWarning("TimestampedBuffer rate (%10.5f) more that 10%% off nominal (%10.5f)\n",rate,m_ticks_per_frame);
236             return m_ticks_per_frame;
237         }
238 //         return m_ticks_per_frame;
239         if (rate<0.0) debugError("rate < 0! (%f)\n",rate);
240        
241         return rate;
242     } else {
243         return 0.0;
244     }
245 }
246
247 int64_t StreamProcessor::getTimeUntilNextPeriodSignalUsecs() {
248     uint64_t time_at_period=getTimeAtPeriod();
249
250     // we delay the period signal with the sync delay
251     // this makes that the period signals lag a little compared to reality
252     // ISO buffering causes the packets to be received at max
253     // m_handler->getWakeupInterval() later than the time they were received.
254     // hence their payload is available this amount of time later. However, the
255     // period boundary is predicted based upon earlier samples, and therefore can
256     // pass before these packets are processed. Adding this extra term makes that
257     // the period boundary is signalled later
258     time_at_period = addTicks(time_at_period, m_SyncSource->getSyncDelay());
259
260     uint64_t cycle_timer=m_handler->getCycleTimerTicks();
261
262     // calculate the time until the next period
263     int32_t until_next=diffTicks(time_at_period,cycle_timer);
264
265     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "=> TAP=%11llu, CTR=%11llu, UTN=%11ld\n",
266         time_at_period, cycle_timer, until_next
267         );
268
269     // now convert to usecs
270     // don't use the mapping function because it only works
271     // for absolute times, not the relative time we are
272     // using here (which can also be negative).
273     return (int64_t)(((float)until_next) / TICKS_PER_USEC);
274 }
275
276 uint64_t StreamProcessor::getTimeAtPeriodUsecs() {
277     return (uint64_t)((float)getTimeAtPeriod() * TICKS_PER_USEC);
278 }
279
280 bool StreamProcessor::dropFrames(unsigned int nbframes) {
281     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "StreamProcessor::dropFrames(%d)\n", nbframes);
282     return m_data_buffer->dropFrames(nbframes);
283 }
284
285 /**
286  * Resets the xrun counter, in a atomic way. This
287  * is thread safe.
288  */
289 void StreamProcessor::resetXrunCounter() {
290     ZERO_ATOMIC((SInt32 *)&m_xruns);
291 }
292
293 void StreamProcessor::setVerboseLevel(int l) {
294     setDebugLevel(l);
295     IsoStream::setVerboseLevel(l);
296     PortManager::setVerboseLevel(l);
297
298 }
299
300 ReceiveStreamProcessor::ReceiveStreamProcessor(int port, int framerate)
301     : StreamProcessor(IsoStream::EST_Receive, port, framerate) {
302
303 }
304
305 ReceiveStreamProcessor::~ReceiveStreamProcessor() {
306
307 }
308
309 void ReceiveStreamProcessor::setVerboseLevel(int l) {
310     setDebugLevel(l);
311     StreamProcessor::setVerboseLevel(l);
312
313 }
314
315 uint64_t ReceiveStreamProcessor::getTimeAtPeriod() {
316     ffado_timestamp_t next_period_boundary=m_data_buffer->getTimestampFromHead(m_period);
317
318     #ifdef DEBUG
319     ffado_timestamp_t ts;
320     signed int fc;
321    
322     m_data_buffer->getBufferTailTimestamp(&ts,&fc);
323
324     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "=> NPD="TIMESTAMP_FORMAT_SPEC", LTS="TIMESTAMP_FORMAT_SPEC", FC=%5u, TPF=%f\n",
325         next_period_boundary, ts, fc, getTicksPerFrame()
326         );
327     #endif
328
329     return (uint64_t)next_period_boundary;
330 }
331
332 bool ReceiveStreamProcessor::canClientTransferFrames(unsigned int nbframes) {
333     return m_data_buffer->getFrameCounter() >= (int) nbframes;
334 }
335
336 TransmitStreamProcessor::TransmitStreamProcessor( int port, int framerate)
337     : StreamProcessor(IsoStream::EST_Transmit, port, framerate) {
338
339 }
340
341 TransmitStreamProcessor::~TransmitStreamProcessor() {
342
343 }
344
345 void TransmitStreamProcessor::setVerboseLevel(int l) {
346     setDebugLevel(l);
347     StreamProcessor::setVerboseLevel(l);
348
349 }
350
351 uint64_t TransmitStreamProcessor::getTimeAtPeriod() {
352     ffado_timestamp_t next_period_boundary=m_data_buffer->getTimestampFromTail((m_nb_buffers-1) * m_period);
353
354     #ifdef DEBUG
355     ffado_timestamp_t ts;
356     signed int fc;
357     m_data_buffer->getBufferTailTimestamp(&ts,&fc);
358
359     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "=> NPD="TIMESTAMP_FORMAT_SPEC", LTS="TIMESTAMP_FORMAT_SPEC", FC=%5u, TPF=%f\n",
360         next_period_boundary, ts, fc, getTicksPerFrame()
361         );
362     #endif
363
364     return (uint64_t)next_period_boundary;
365 }
366
367 bool TransmitStreamProcessor::canClientTransferFrames(unsigned int nbframes) {
368     // there has to be enough space to put the frames in
369     return m_data_buffer->getBufferSize() - m_data_buffer->getFrameCounter() > nbframes;
370 }
371
372
373 }
Note: See TracBrowser for help on using the browser.