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

Revision 428, 10.0 kB (checked in by jwoithe, 17 years ago)

MOTU: more work trying to get MOTU working with the new streaming framework.

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