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

Revision 419, 10.0 kB (checked in by pieterpalmers, 15 years ago)

namespace simplification

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 Streaming {
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 Util::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.