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

Revision 384, 16.7 kB (checked in by pieterpalmers, 16 years ago)

- temporary commit as backup measure
- rewrote synchronisation code
- receive streaming based on SYT works
- transmit streaming synced to received stream sort of works, still

have to iron out some issues.

NOTE: all devices but the bebob's are disabled in this code,

because they still have to be ported to the new sync
mechanism.

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) 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 "IsoHandlerManager.h"
30 #include "IsoHandler.h"
31 #include "IsoStream.h"
32 #include <assert.h>
33
34 namespace FreebobStreaming
35 {
36
37 IMPL_DEBUG_MODULE( IsoHandlerManager, IsoHandlerManager, DEBUG_LEVEL_NORMAL );
38
39 IsoHandlerManager::IsoHandlerManager() :
40    m_State(E_Created),
41    m_poll_timeout(1), m_poll_fds(0), m_poll_nfds(0)
42 {
43
44 }
45
46
47 IsoHandlerManager::~IsoHandlerManager()
48 {
49
50 }
51
52 bool IsoHandlerManager::Init()
53 {
54         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
55
56         return true;
57 }
58
59 /**
60  * the IsoHandlerManager thread execute function iterates the handlers.
61  *
62  * This means that once the thread is running, streams are
63  * transmitted and received (if present on the bus). Make sure
64  * that the clients are registered & ready before starting the
65  * thread!
66  *
67  * The register and unregister functions are thread unsafe, so
68  * should not be used when the thread is running.
69  *
70  * @return false if the handlers could not be iterated.
71  */
72 bool IsoHandlerManager::Execute()
73 {
74 //     updateCycleTimers();
75    
76     if(!iterate()) {
77         debugFatal("Could not iterate the isoManager\n");
78         return false;
79     }   
80    
81     return true;
82 }
83
84 /**
85  * Poll the handlers managed by this manager, and iterate them
86  * when ready
87  *
88  * @return true when successful
89  */
90 bool IsoHandlerManager::iterate()
91 {
92         int err;
93         int i=0;
94         debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "enter...\n");
95        
96         err = poll (m_poll_fds, m_poll_nfds, m_poll_timeout);
97        
98         if (err == -1) {
99                 if (errno == EINTR) {
100                         return true;
101                 }
102                 debugFatal("poll error: %s\n", strerror (errno));
103                 return false;
104         }
105
106         for (i = 0; i < m_poll_nfds; i++) {
107                 if (m_poll_fds[i].revents & POLLERR) {
108                         debugWarning("error on fd for %d\n",i);
109                 }
110
111                 if (m_poll_fds[i].revents & POLLHUP) {
112                         debugWarning("hangup on fd for %d\n",i);
113                 }
114                
115                 if(m_poll_fds[i].revents & (POLLIN)) {
116                         IsoHandler *s=m_IsoHandlers.at(i);
117                         assert(s);
118                        
119                         s->iterate();
120                 }
121         }
122
123         return true;
124
125 }
126
127 // updates the internal cycle timer caches of the handlers
128 void IsoHandlerManager::updateCycleTimers() {
129     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "enter...\n");
130    
131     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
132           it != m_IsoHandlers.end();
133           ++it )
134     {
135         int cnt=0;
136         while (!(*it)->updateCycleTimer() && (cnt++ < MAX_UPDATE_TRIES)) {
137             usleep(USLEEP_AFTER_UPDATE_FAILURE);
138         }
139     }
140    
141 }
142
143 bool IsoHandlerManager::registerHandler(IsoHandler *handler)
144 {
145     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
146     assert(handler);
147    
148     m_IsoHandlers.push_back(handler);
149    
150     handler->setVerboseLevel(getDebugLevel());
151
152     // rebuild the fd map for poll()'ing.
153     return rebuildFdMap();     
154
155 }
156
157 bool IsoHandlerManager::unregisterHandler(IsoHandler *handler)
158 {
159         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
160         assert(handler);
161
162         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
163           it != m_IsoHandlers.end();
164           ++it )
165         {
166                 if ( *it == handler ) {
167                         // erase the iso handler from the list
168                         m_IsoHandlers.erase(it);
169                         // rebuild the fd map for poll()'ing.
170                         return rebuildFdMap();
171                 }
172         }
173         debugFatal("Could not find handler (%p)\n", handler);
174        
175         return false; //not found
176
177 }
178
179 bool IsoHandlerManager::rebuildFdMap() {
180         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
181         int i=0;
182
183         m_poll_nfds=0;
184         if(m_poll_fds) free(m_poll_fds);
185
186         // count the number of handlers
187         m_poll_nfds=m_IsoHandlers.size();
188
189         // allocate the fd array
190         m_poll_fds   = (struct pollfd *) calloc (m_poll_nfds, sizeof (struct pollfd));
191         if(!m_poll_fds) {
192                 debugFatal("Could not allocate memory for poll FD array\n");
193                 return false;
194         }
195
196         // fill the fd map
197         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
198           it != m_IsoHandlers.end();
199           ++it )
200         {
201                 m_poll_fds[i].fd=(*it)->getFileDescriptor();
202                 m_poll_fds[i].events = POLLIN;
203                 i++;
204         }
205
206         return true;
207 }
208
209 void IsoHandlerManager::disablePolling(IsoStream *stream) {
210     int i=0;
211    
212     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Disable polling on stream %p\n",stream);
213
214     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
215         it != m_IsoHandlers.end();
216         ++it )
217     {
218         if ((*it)->isStreamRegistered(stream)) {
219             m_poll_fds[i].events = 0;
220             m_poll_fds[i].revents = 0;
221             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "polling disabled\n");
222         }
223        
224         i++;
225     }
226 }
227
228 void IsoHandlerManager::enablePolling(IsoStream *stream) {
229     int i=0;
230    
231     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Enable polling on stream %p\n",stream);
232    
233     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
234         it != m_IsoHandlers.end();
235         ++it )
236     {
237         if ((*it)->isStreamRegistered(stream)) {
238             m_poll_fds[i].events = POLLIN;
239             m_poll_fds[i].revents = 0;
240             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "polling enabled\n");
241         }
242        
243         i++;
244     }
245 }
246
247
248 /**
249  * Registers an IsoStream with the IsoHandlerManager.
250  *
251  * If nescessary, an IsoHandler is created to handle this stream.
252  * Once an IsoStream is registered to the handler, it will be included
253  * in the ISO streaming cycle (i.e. receive/transmit of it will occur).
254  *
255  * @param stream the stream to register
256  * @return true if registration succeeds
257  *
258  * \todo : currently there is a one-to-one mapping
259  *        between streams and handlers, this is not ok for
260  *        multichannel receive
261  */
262 bool IsoHandlerManager::registerStream(IsoStream *stream)
263 {
264         debugOutput( DEBUG_LEVEL_VERBOSE, "Registering stream %p\n",stream);
265         assert(stream);
266
267         // make sure the stream isn't already attached to a handler
268         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
269           it != m_IsoHandlers.end();
270           ++it )
271         {
272                 if((*it)->isStreamRegistered(stream)) {
273                         debugWarning( "stream already registered!\n");
274                         (*it)->unregisterStream(stream);
275                        
276                 }
277         }
278        
279         // clean up all handlers that aren't used
280         pruneHandlers();
281
282         // allocate a handler for this stream
283         if (stream->getType()==IsoStream::EST_Receive) {
284                 // setup the optimal parameters for the raw1394 ISO buffering
285                 unsigned int packets_per_period=stream->getPacketsPerPeriod();
286                
287                 // hardware interrupts occur when one DMA block is full, and the size of one DMA
288                 // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq is
289                 // occurs at a period boundary (optimal CPU use)
290                
291                 // NOTE: try and use 4 hardware interrupts per period for better latency.
292                 unsigned int max_packet_size=4 * getpagesize() / packets_per_period;
293                 if (max_packet_size < stream->getMaxPacketSize()) {
294                         max_packet_size=stream->getMaxPacketSize();
295                 }
296
297                 // Ensure we don't request a packet size bigger than the
298                 // kernel-enforced maximum which is currently 1 page.
299                 if (max_packet_size > (unsigned int)getpagesize())
300                         max_packet_size = getpagesize();
301
302                 int irq_interval=packets_per_period / 4;
303         if(irq_interval <= 0) irq_interval=1;
304
305                 /* the receive buffer size doesn't matter for the latency,
306                    but it has a minimal value in order for libraw to operate correctly (300) */
307                 int buffers=400;
308                
309                 // create the actual handler
310                 IsoRecvHandler *h = new IsoRecvHandler(stream->getPort(), buffers,
311                                                        max_packet_size, irq_interval);
312
313                 debugOutput( DEBUG_LEVEL_VERBOSE, " registering IsoRecvHandler\n");
314
315                 if(!h) {
316                         debugFatal("Could not create IsoRecvHandler\n");
317                         return false;
318                 }
319
320                 h->setVerboseLevel(getDebugLevel());
321
322                 // init the handler
323                 if(!h->init()) {
324                         debugFatal("Could not initialize receive handler\n");
325                         return false;
326                 }
327
328                 // register the stream with the handler
329                 if(!h->registerStream(stream)) {
330                         debugFatal("Could not register receive stream with handler\n");
331                         return false;
332                 }
333
334                 // register the handler with the manager
335                 if(!registerHandler(h)) {
336                         debugFatal("Could not register receive handler with manager\n");
337                         return false;
338                 }
339                 debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n",stream,h);
340         }
341        
342         if (stream->getType()==IsoStream::EST_Transmit) {
343        
344                 // setup the optimal parameters for the raw1394 ISO buffering
345                 unsigned int packets_per_period=stream->getPacketsPerPeriod();
346                 // hardware interrupts occur when one DMA block is full, and the size of one DMA
347                 // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq 
348                 // occurs at a period boundary (optimal CPU use)
349                 // NOTE: try and use 4 interrupts per period for better latency.
350                 unsigned int max_packet_size=4 * getpagesize() / packets_per_period;
351                 if (max_packet_size < stream->getMaxPacketSize()) {
352                         max_packet_size=stream->getMaxPacketSize();
353                 }
354
355                 // Ensure we don't request a packet size bigger than the
356                 // kernel-enforced maximum which is currently 1 page.
357                 if (max_packet_size > (unsigned int)getpagesize())
358                         max_packet_size = getpagesize();
359
360                 int irq_interval=packets_per_period / 4;
361                 if(irq_interval <= 0) irq_interval=1;
362        
363                 // the transmit buffer size should be as low as possible for latency.
364                 // note however that the raw1394 subsystem tries to keep this buffer
365                 // full, so we have to make sure that we have enough events in our
366                 // event buffers
367                 int buffers=packets_per_period;
368                
369                 // NOTE: this is dangerous: what if there is not enough prefill?
370 //              if (buffers<10) buffers=10;     
371                
372                 // create the actual handler
373                 IsoXmitHandler *h = new IsoXmitHandler(stream->getPort(), buffers,
374                                                        max_packet_size, irq_interval);
375
376                 debugOutput( DEBUG_LEVEL_VERBOSE, " registering IsoXmitHandler\n");
377
378                 if(!h) {
379                         debugFatal("Could not create IsoXmitHandler\n");
380                         return false;
381                 }
382
383                 h->setVerboseLevel(getDebugLevel());
384
385                 // init the handler
386                 if(!h->init()) {
387                         debugFatal("Could not initialize transmit handler\n");
388                         return false;
389                 }
390
391                 // register the stream with the handler
392                 if(!h->registerStream(stream)) {
393                         debugFatal("Could not register transmit stream with handler\n");
394                         return false;
395                 }
396
397                 // register the handler with the manager
398                 if(!registerHandler(h)) {
399                         debugFatal("Could not register transmit handler with manager\n");
400                         return false;
401                 }
402                 debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n",stream,h);
403
404         }
405
406         m_IsoStreams.push_back(stream);
407         debugOutput( DEBUG_LEVEL_VERBOSE, " %d streams, %d handlers registered\n",
408                                           m_IsoStreams.size(), m_IsoHandlers.size());
409
410         return true;
411 }
412
413 bool IsoHandlerManager::unregisterStream(IsoStream *stream)
414 {
415         debugOutput( DEBUG_LEVEL_VERBOSE, "Unregistering stream %p\n",stream);
416         assert(stream);
417
418         // make sure the stream isn't attached to a handler anymore
419         for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
420           it != m_IsoHandlers.end();
421           ++it )
422         {
423                 if((*it)->isStreamRegistered(stream)) {
424                         if(!(*it)->unregisterStream(stream)) {
425                                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not unregister stream (%p) from handler (%p)...\n",stream,*it);
426                                 return false;
427                         }
428                        
429                         debugOutput( DEBUG_LEVEL_VERBOSE, " unregistered stream (%p) from handler (%p)...\n",stream,*it);
430                 }
431         }
432
433         // clean up all handlers that aren't used
434         pruneHandlers();
435
436         // remove the stream from the registered streams list
437         for ( IsoStreamVectorIterator it = m_IsoStreams.begin();
438           it != m_IsoStreams.end();
439           ++it )
440         {
441                 if ( *it == stream ) {
442                         m_IsoStreams.erase(it);
443                        
444                         debugOutput( DEBUG_LEVEL_VERBOSE, " deleted stream (%p) from list...\n", *it);
445                         return true;
446                 }
447         }
448
449         return false; //not found
450
451 }
452
453 void IsoHandlerManager::pruneHandlers() {
454     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
455     IsoHandlerVector toUnregister;
456
457     // find all handlers that are not in use
458     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
459           it != m_IsoHandlers.end();
460           ++it )
461     {
462         if(!((*it)->inUse())) {
463             debugOutput( DEBUG_LEVEL_VERBOSE, " handler (%p) not in use\n",*it);
464             toUnregister.push_back(*it);
465         }
466     }
467     // delete them
468     for ( IsoHandlerVectorIterator it = toUnregister.begin();
469           it != toUnregister.end();
470           ++it )
471     {
472         unregisterHandler(*it);
473         debugOutput( DEBUG_LEVEL_VERBOSE, " deleting handler (%p)\n",*it);
474
475         // Now the handler's been unregistered it won't be reused
476         // again.  Therefore it really needs to be formally deleted
477         // to free up the raw1394 handle.  Otherwise things fall
478         // apart after several xrun recoveries as the system runs
479         // out of resources to support all the disused but still
480         // allocated raw1394 handles.  At least this is the current
481         // theory as to why we end up with "memory allocation"
482         // failures after several Xrun recoveries.
483         delete *it;
484     }
485
486 }
487
488
489 bool IsoHandlerManager::prepare()
490 {
491     bool retval=true;
492    
493     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
494    
495     // check state
496     if(m_State != E_Created) {
497         debugError("Incorrect state, expected E_Created, got %d\n",(int)m_State);
498         return false;
499     }
500    
501     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
502           it != m_IsoHandlers.end();
503           ++it )
504     {
505         if(!(*it)->prepare()) {
506             debugFatal("Could not prepare handlers\n");
507             retval=false;
508         }
509     }
510
511     if (retval) {
512         m_State=E_Prepared;
513     } else {
514         m_State=E_Error;
515     }
516
517     return retval;
518 }
519
520 bool IsoHandlerManager::startHandlers() {
521     return startHandlers(-1);
522 }
523
524 bool IsoHandlerManager::startHandlers(int cycle) {
525     bool retval=true;
526    
527     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
528    
529     // check state
530     if(m_State != E_Prepared) {
531         debugError("Incorrect state, expected E_Prepared, got %d\n",(int)m_State);
532         return false;
533     }
534    
535     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
536         it != m_IsoHandlers.end();
537         ++it )
538     {
539         debugOutput( DEBUG_LEVEL_VERBOSE, " starting handler (%p)\n",*it);
540         if(!(*it)->start(cycle)) {
541             debugOutput( DEBUG_LEVEL_VERBOSE, " could not start handler (%p)\n",*it);
542             retval=false;
543         }
544     }
545    
546     if (retval) {
547         m_State=E_Running;
548     } else {
549         m_State=E_Error;
550     }
551
552     return retval;
553 }
554
555 bool IsoHandlerManager::stopHandlers() {
556     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
557    
558     // check state
559     if(m_State != E_Running) {
560         debugError("Incorrect state, expected E_Running, got %d\n",(int)m_State);
561         return false;
562     }
563    
564     bool retval=true;
565    
566     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
567         it != m_IsoHandlers.end();
568         ++it )
569     {
570         debugOutput( DEBUG_LEVEL_VERBOSE, " stopping handler (%p)\n",*it);
571         if(!(*it)->stop()){
572             debugOutput( DEBUG_LEVEL_VERBOSE, " could not stop handler (%p)\n",*it);
573             retval=false;
574         }
575     }
576    
577     if (retval) {
578         m_State=E_Prepared;
579     } else {
580         m_State=E_Error;
581     }
582    
583     return retval;
584 }
585
586 bool IsoHandlerManager::reset() {
587     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
588    
589     // check state
590     if(m_State == E_Error) {
591         debugFatal("Resetting from error condition not yet supported...\n");
592         return false;
593     }
594    
595     // if not in an error condition, reset means stop the handlers
596     return stopHandlers();
597 }
598
599
600 void IsoHandlerManager::setVerboseLevel(int i) {
601     setDebugLevel(i);
602
603     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
604           it != m_IsoHandlers.end();
605           ++it )
606     {
607         (*it)->setVerboseLevel(i);
608     }
609 }
610
611 void IsoHandlerManager::dumpInfo() {
612     int i=0;
613    
614     debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping IsoHandlerManager Stream handler information...\n");
615     debugOutputShort( DEBUG_LEVEL_NORMAL, " State: %d\n",(int)m_State);
616
617     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
618           it != m_IsoHandlers.end();
619           ++it )
620     {
621         debugOutputShort( DEBUG_LEVEL_NORMAL, " IsoHandler %d (%p)\n",i++,*it);
622
623         (*it)->dumpInfo();
624     }
625
626 }
627
628 } // end of namespace FreebobStreaming
629
Note: See TracBrowser for help on using the browser.