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

Revision 398, 19.9 kB (checked in by pieterpalmers, 16 years ago)

remove cycle timer prediction & DLL code from the IsoHandler?, as it is replaced by a raw1394 API call

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