root/branches/streaming-rework/src/libstreaming/StreamProcessor.cpp

Revision 411, 10.0 kB (checked in by pieterpalmers, 16 years ago)

cycletimer.h:
- some extra operations on Ticks (diffTicks & substractTicks)

StreamProcessor?.cpp
AmdtpStreamProcessor?.cpp
MotuStreamProcessor?.cpp:
- Moved the syncDelay to StreamProcessor::getTimeUntilNextPeriodSignalUsecs(). This delay should be the delay between the actual period boundary and the time it is reported to the SPManager. Therefore it's place is not as a buffer offset, but in the calculation of the signalling time.
This makes that the buffer timestamps correspond to 'real' timestamps. These might have to be manipulated by the transmit or receive handles to account for e.g. iso buffering etc..., but at least the timestamps themselves have a well-defined meaning now.

StreamProcessorManager?.cpp:
- The only stream that needs to be running is the sync source stream. It is assumed that the other streams start running in time. 'In time' is currently about 2000 cycles afterwards.

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