root/trunk/libffado/src/libavc/general/avc_plug.cpp

Revision 560, 72.9 kB (checked in by ppalmers, 16 years ago)

- Sort the FFADODevice vector on GUID before assigning device id's

This results in the same device id for identical device setups,
independent of the way they are connected or the node numbers they
have been assigned.

- Sanitized debug message reporting a bit
- Cosmetic changes

Line 
1 /*
2  * Copyright (C)      2007 by Pieter Palmers
3  * Copyright (C) 2005-2007 by Daniel Wagner
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License version 2.1, as published by the Free Software Foundation;
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  * MA 02110-1301 USA
23  */
24
25 #include "avc_plug.h"
26 #include "avc_unit.h"
27 #include "avc_signal_format.h"
28
29 #include "libieee1394/configrom.h"
30
31 #include "libieee1394/ieee1394service.h"
32 #include "../util/avc_serialize.h"
33
34 #include <sstream>
35
36 namespace AVC {
37
38 int Plug::m_globalIdCounter = 0;
39
40 IMPL_DEBUG_MODULE( Plug, Plug, DEBUG_LEVEL_NORMAL );
41 IMPL_DEBUG_MODULE( PlugManager, PlugManager, DEBUG_LEVEL_NORMAL );
42
43 Plug::Plug( Unit* unit,
44             Subunit* subunit,
45             function_block_type_t functionBlockType,
46             function_block_id_t functionBlockId,
47             EPlugAddressType plugAddressType,
48             EPlugDirection plugDirection,
49             plug_id_t plugId )
50     : m_unit(unit)
51     , m_subunit(subunit)
52     , m_functionBlockType( functionBlockType )
53     , m_functionBlockId( functionBlockId )
54     , m_addressType( plugAddressType )
55     , m_direction( plugDirection )
56     , m_id( plugId )
57     , m_infoPlugType( eAPT_Unknown )
58     , m_nrOfChannels( 0 )
59     , m_globalId( m_globalIdCounter++ )
60 {
61     debugOutput( DEBUG_LEVEL_VERBOSE,
62                  "nodeId = %d, subunitType = %d, "
63                  "subunitId = %d, functionBlockType = %d, "
64                  "functionBlockId = %d, addressType = %d, "
65                  "direction = %d, id = %d\n",
66                  m_unit->getConfigRom().getNodeId(),
67                  getSubunitType(),
68                  getSubunitId(),
69                  m_functionBlockType,
70                  m_functionBlockId,
71                  m_addressType,
72                  m_direction,
73                  m_id );
74 }
75
76 Plug::Plug( const Plug& rhs )
77     : m_unit ( rhs.m_unit )
78     , m_subunit ( rhs.m_subunit )
79     , m_functionBlockType( rhs.m_functionBlockType )
80     , m_functionBlockId( rhs.m_functionBlockId )
81     , m_addressType( rhs.m_addressType )
82     , m_direction( rhs.m_direction )
83     , m_id( rhs.m_id )
84     , m_infoPlugType( rhs.m_infoPlugType )
85     , m_nrOfChannels( rhs.m_nrOfChannels )
86     , m_name( rhs.m_name )
87     , m_clusterInfos( rhs.m_clusterInfos )
88     , m_formatInfos( rhs.m_formatInfos )
89 {
90     if ( getDebugLevel() ) {
91         setDebugLevel( DEBUG_LEVEL_VERBOSE );
92      }
93 }
94
95 Plug::Plug()
96     : m_unit( NULL )
97     , m_subunit( NULL )
98     , m_functionBlockType( 0 )
99     , m_functionBlockId( 0 )
100     , m_addressType( eAPA_Undefined )
101     , m_direction( eAPD_Unknown )
102     , m_id( 0 )
103     , m_infoPlugType( eAPT_Unknown )
104     , m_nrOfChannels( 0 )
105     , m_globalId( 0 )
106 {
107 }
108
109 Plug::~Plug()
110 {
111     m_unit->getPlugManager().remPlug( *this );
112 }
113
114 void
115 Plug::setVerboseLevel(int l)
116 {
117     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
118     setDebugLevel(l);
119 }
120
121 ESubunitType
122 Plug::getSubunitType() const
123 {
124     return (m_subunit==NULL?eST_Unit:m_subunit->getSubunitType());
125 }
126
127 subunit_id_t
128 Plug::getSubunitId() const
129 {
130     return (m_subunit==NULL?0xFF:m_subunit->getSubunitId());
131 }
132
133 bool
134 Plug::discover()
135 {
136
137     if ( !initFromDescriptor() ) {
138         debugError( "discover: Could not init plug from descriptor (%d,%d,%d,%d,%d)\n",
139                     m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
140 //         return false;
141     }
142
143     if ( !discoverPlugType() ) {
144         debugError( "discover: Could not discover plug type (%d,%d,%d,%d,%d)\n",
145                     m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
146         return false;
147     }
148
149     if ( !discoverName() ) {
150         debugError( "Could not discover name (%d,%d,%d,%d,%d)\n",
151                     m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
152         return false;
153     }
154
155     if ( !discoverNoOfChannels() ) {
156         debugError( "Could not discover number of channels "
157                     "(%d,%d,%d,%d,%d)\n",
158                     m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
159         return false;
160     }
161
162     if ( !discoverChannelPosition() ) {
163         debugError( "Could not discover channel positions "
164                     "(%d,%d,%d,%d,%d)\n",
165                     m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
166         return false;
167     }
168
169     if ( !discoverChannelName() ) {
170         debugError( "Could not discover channel name "
171                     "(%d,%d,%d,%d,%d)\n",
172                     m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
173         return false;
174     }
175
176     if ( !discoverClusterInfo() ) {
177         debugError( "Could not discover channel name "
178                     "(%d,%d,%d,%d,%d)\n",
179                     m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
180         return false;
181     }
182
183     if ( !discoverStreamFormat() ) {
184         debugError( "Could not discover stream format "
185                     "(%d,%d,%d,%d,%d)\n",
186                     m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
187 //         return false;
188     }
189
190     if ( !discoverSupportedStreamFormats() ) {
191         debugError( "Could not discover supported stream formats "
192                     "(%d,%d,%d,%d,%d)\n",
193                     m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
194 //         return false;
195     }
196
197     return m_unit->getPlugManager().addPlug( *this );
198 }
199
200 bool
201 Plug::initFromDescriptor()
202 {
203     if(getSubunitType()==eST_Unit) {
204         debugOutput(DEBUG_LEVEL_VERBOSE, "Not loading unit plug from descriptor.\n");
205         return true;
206     } else {
207         return m_subunit->initPlugFromDescriptor(*this);
208     }
209 }
210
211 bool
212 Plug::discoverConnections()
213 {
214     return discoverConnectionsInput() && discoverConnectionsOutput();
215 }
216
217 bool
218 Plug::discoverPlugType()
219 {
220
221     return true;
222 }
223
224 bool
225 Plug::discoverName()
226 {
227     // name already set
228     if (m_name != "") return true;
229    
230     m_name = plugAddressTypeToString(getPlugAddressType());
231     m_name += " ";
232     m_name += plugTypeToString(getPlugType());
233     m_name += " ";
234     m_name += plugDirectionToString(getPlugDirection());
235
236     return true;
237 }
238
239 bool
240 Plug::discoverNoOfChannels()
241 {
242
243     return true;
244 }
245
246 bool
247 Plug::discoverChannelPosition()
248 {
249
250     return true;
251 }
252
253 bool
254 Plug::discoverChannelName()
255 {
256    
257     return true;
258 }
259
260 bool
261 Plug::discoverClusterInfo()
262 {
263
264     return true;
265 }
266
267 bool
268 Plug::discoverStreamFormat()
269 {
270     ExtendedStreamFormatCmd extStreamFormatCmd =
271         setPlugAddrToStreamFormatCmd( ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommand );
272     extStreamFormatCmd.setVerbose( getDebugLevel() );
273
274     if ( !extStreamFormatCmd.fire() ) {
275         debugError( "stream format command failed\n" );
276         return false;
277     }
278
279     if ( ( extStreamFormatCmd.getStatus() ==  ExtendedStreamFormatCmd::eS_NoStreamFormat )
280          || ( extStreamFormatCmd.getStatus() ==  ExtendedStreamFormatCmd::eS_NotUsed ) )
281     {
282         debugOutput( DEBUG_LEVEL_VERBOSE,
283                      "No stream format information available\n" );
284         return true;
285     }
286
287     if ( !extStreamFormatCmd.getFormatInformation() ) {
288         debugWarning( "No stream format information for plug found -> skip\n" );
289         return true;
290     }
291
292     if ( extStreamFormatCmd.getFormatInformation()->m_root
293            != FormatInformation::eFHR_AudioMusic  )
294     {
295         debugWarning( "Format hierarchy root is not Audio&Music -> skip\n" );
296         return true;
297     }
298
299     FormatInformation* formatInfo =
300         extStreamFormatCmd.getFormatInformation();
301     FormatInformationStreamsCompound* compoundStream
302         = dynamic_cast< FormatInformationStreamsCompound* > (
303             formatInfo->m_streams );
304     if ( compoundStream ) {
305         m_samplingFrequency =
306             compoundStream->m_samplingFrequency;
307         debugOutput( DEBUG_LEVEL_VERBOSE,
308                      "%s plug %d uses "
309                      "sampling frequency %d, nr of stream infos = %d\n",
310                      getName(),
311                      m_id,
312                      m_samplingFrequency,
313                      compoundStream->m_numberOfStreamFormatInfos );
314
315         for ( int i = 1;
316               i <= compoundStream->m_numberOfStreamFormatInfos;
317               ++i )
318         {
319             ClusterInfo* clusterInfo =
320                 const_cast<ClusterInfo*>( getClusterInfoByIndex( i ) );
321
322             if ( !clusterInfo ) {
323                 debugError( "No matching cluster "
324                             "info found for index %d\n",  i );
325                     return false;
326             }
327             StreamFormatInfo* streamFormatInfo =
328                 compoundStream->m_streamFormatInfos[ i - 1 ];
329
330             debugOutput( DEBUG_LEVEL_VERBOSE,
331                          "number of channels = %d, stream format = %d\n",
332                          streamFormatInfo->m_numberOfChannels,
333                          streamFormatInfo->m_streamFormat );
334
335             int nrOfChannels = clusterInfo->m_nrOfChannels;
336             if ( streamFormatInfo->m_streamFormat ==
337                  FormatInformation::eFHL2_AM824_MIDI_CONFORMANT )
338             {
339                 // 8 logical midi channels fit into 1 channel
340                 nrOfChannels = ( ( nrOfChannels + 7 ) / 8 );
341             }
342             // sanity check
343             if ( nrOfChannels != streamFormatInfo->m_numberOfChannels )
344             {
345                 debugWarning( "Number of channels "
346                               "mismatch: '%s' plug discovering reported "
347                               "%d channels for cluster '%s', while stream "
348                               "format reported %d\n",
349                               getName(),
350                               nrOfChannels,
351                               clusterInfo->m_name.c_str(),
352                               streamFormatInfo->m_numberOfChannels);
353             }
354             clusterInfo->m_streamFormat = streamFormatInfo->m_streamFormat;
355
356             debugOutput( DEBUG_LEVEL_VERBOSE,
357                          "%s plug %d cluster info %d ('%s'): "
358                          "stream format %d\n",
359                          getName(),
360                          m_id,
361                          i,
362                          clusterInfo->m_name.c_str(),
363                          clusterInfo->m_streamFormat );
364         }
365     }
366
367     FormatInformationStreamsSync* syncStream
368         = dynamic_cast< FormatInformationStreamsSync* > (
369             formatInfo->m_streams );
370     if ( syncStream ) {
371         m_samplingFrequency =
372             syncStream->m_samplingFrequency;
373         debugOutput( DEBUG_LEVEL_VERBOSE,
374                      "%s plug %d is sync stream with sampling frequency %d\n",
375                      getName(),
376                      m_id,
377                      m_samplingFrequency );
378     }
379
380
381     if ( !compoundStream && !syncStream )
382     {
383         debugError( "Unsupported stream format\n" );
384         return false;
385     }
386
387     return true;
388 }
389
390 bool
391 Plug::discoverSupportedStreamFormats()
392 {
393     ExtendedStreamFormatCmd extStreamFormatCmd =
394         setPlugAddrToStreamFormatCmd(
395             ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommandList);
396     extStreamFormatCmd.setVerbose( getDebugLevel() );
397
398     int i = 0;
399     bool cmdSuccess = false;
400
401     do {
402         extStreamFormatCmd.setIndexInStreamFormat( i );
403         extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
404         cmdSuccess = extStreamFormatCmd.fire();
405         if ( cmdSuccess
406              && ( extStreamFormatCmd.getResponse()
407                   == AVCCommand::eR_Implemented ) )
408         {
409             FormatInfo formatInfo;
410             formatInfo.m_index = i;
411             bool formatInfoIsValid = true;
412
413             FormatInformationStreamsSync* syncStream
414                 = dynamic_cast< FormatInformationStreamsSync* >
415                 ( extStreamFormatCmd.getFormatInformation()->m_streams );
416             if ( syncStream ) {
417                 formatInfo.m_samplingFrequency =
418                     syncStream->m_samplingFrequency;
419                 formatInfo.m_isSyncStream = true ;
420             }
421
422             FormatInformationStreamsCompound* compoundStream
423                 = dynamic_cast< FormatInformationStreamsCompound* >
424                 ( extStreamFormatCmd.getFormatInformation()->m_streams );
425             if ( compoundStream ) {
426                 formatInfo.m_samplingFrequency =
427                     compoundStream->m_samplingFrequency;
428                 formatInfo.m_isSyncStream = false;
429                 for ( int j = 0;
430                       j < compoundStream->m_numberOfStreamFormatInfos;
431                       ++j )
432                 {
433                     switch ( compoundStream->m_streamFormatInfos[j]->m_streamFormat ) {
434                     case AVC1394_STREAM_FORMAT_AM824_IEC60968_3:
435                         formatInfo.m_audioChannels +=
436                             compoundStream->m_streamFormatInfos[j]->m_numberOfChannels;
437                         break;
438                     case AVC1394_STREAM_FORMAT_AM824_MULTI_BIT_LINEAR_AUDIO_RAW:
439                         formatInfo.m_audioChannels +=
440                             compoundStream->m_streamFormatInfos[j]->m_numberOfChannels;
441                         break;
442                     case AVC1394_STREAM_FORMAT_AM824_MIDI_CONFORMANT:
443                         formatInfo.m_midiChannels +=
444                             compoundStream->m_streamFormatInfos[j]->m_numberOfChannels;
445                         break;
446                     default:
447                         formatInfoIsValid = false;
448                         debugWarning("unknown stream format (0x%02x) for channel "
449                                       "(%d)\n",
450                                      compoundStream->m_streamFormatInfos[j]->m_streamFormat,
451                                      j );
452                     }
453                 }
454             }
455
456             if ( formatInfoIsValid ) {
457                 flushDebugOutput();
458                 debugOutput( DEBUG_LEVEL_VERBOSE,
459                              "[%s:%d] formatInfo[%d].m_samplingFrequency "
460                              "= %d\n",
461                              getName(), m_id,
462                              i, formatInfo.m_samplingFrequency );
463                 debugOutput( DEBUG_LEVEL_VERBOSE,
464                              "[%s:%d] formatInfo[%d].m_isSyncStream = %d\n",
465                              getName(), m_id,
466                              i, formatInfo.m_isSyncStream );
467                 debugOutput( DEBUG_LEVEL_VERBOSE,
468                              "[%s:%d] formatInfo[%d].m_audioChannels = %d\n",
469                              getName(), m_id,
470                              i, formatInfo.m_audioChannels );
471                 debugOutput( DEBUG_LEVEL_VERBOSE,
472                              "[%s:%d] formatInfo[%d].m_midiChannels = %d\n",
473                              getName(), m_id,
474                              i, formatInfo.m_midiChannels );
475                 m_formatInfos.push_back( formatInfo );
476                 flushDebugOutput();
477             }
478         }
479
480         ++i;
481     } while ( cmdSuccess && ( extStreamFormatCmd.getResponse()
482                               == ExtendedStreamFormatCmd::eR_Implemented ) );
483
484     return true;
485 }
486
487 bool
488 Plug::discoverConnectionsInput()
489 {
490     debugOutput( DEBUG_LEVEL_VERBOSE, "Discovering incoming connections...\n");
491
492     int sourcePlugGlobalId=getSignalSource();
493    
494     if(sourcePlugGlobalId >= 0) {
495         Plug *p=m_unit->getPlugManager().getPlug(sourcePlugGlobalId);
496         if (p==NULL) {
497             debugError( "Plug with global id %d not found\n",sourcePlugGlobalId );
498             return false;
499         }
500         // connected to another plug
501         debugOutput( DEBUG_LEVEL_VERBOSE, "Plug '%s' gets signal from '%s'...\n",
502             getName(), p->getName() );
503
504
505
506         if ( p ) {
507             debugOutput( DEBUG_LEVEL_VERBOSE,
508                         "'(%d) %s' has a connection to '(%d) %s'\n",
509                         getGlobalId(),
510                         getName(),
511                         p->getGlobalId(),
512                         p->getName() );
513             addPlugConnection( m_inputConnections, *p );
514         } else {
515             debugError( "no corresponding plug found for '(%d) %s'\n",
516                         getGlobalId(),
517                         getName() );
518             return false;
519         }
520            
521     }
522
523     return true;
524 }
525
526 bool
527 Plug::discoverConnectionsOutput()
528 {
529     return true;
530 }
531
532 bool
533 Plug::inquireConnnection( Plug& plug )
534 {
535     SignalSourceCmd signalSourceCmd = setSrcPlugAddrToSignalCmd();
536     setDestPlugAddrToSignalCmd( signalSourceCmd, plug );
537     signalSourceCmd.setCommandType( AVCCommand::eCT_SpecificInquiry );
538     signalSourceCmd.setVerbose( getDebugLevel() );
539
540     if ( !signalSourceCmd.fire() ) {
541         debugError( "Could not inquire connection between '%s' and '%s'\n",
542                     getName(), plug.getName() );
543         return false;
544     }
545
546     if ( signalSourceCmd.getResponse() == AVCCommand::eR_Implemented ) {
547         debugOutput( DEBUG_LEVEL_VERBOSE,
548                      "Connection possible between '%s' and '%s'\n",
549                      getName(),  plug.getName() );
550         return true;
551     }
552     debugOutput( DEBUG_LEVEL_VERBOSE,
553                  "Connection not possible between '%s' and '%s'\n",
554                  getName(),  plug.getName() );
555     return false;
556 }
557
558 int
559 Plug::getSignalSource()
560 {
561     if((getPlugAddressType() == eAPA_PCR) ||
562        (getPlugAddressType() == eAPA_ExternalPlug)) {
563         if (getPlugDirection() != eAPD_Output) {
564             debugWarning("Signal Source command not valid for non-output unit plugs...\n");
565             return -1;
566         }
567     }
568    
569     if(getPlugAddressType() == eAPA_SubunitPlug) {
570         if (getPlugDirection() != eAPD_Input) {
571             debugWarning("Signal Source command not valid for non-input subunit plugs...\n");
572             return -1;
573         }
574     }
575    
576     SignalSourceCmd signalSourceCmd( m_unit->get1394Service() );
577    
578     signalSourceCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
579     signalSourceCmd.setSubunitType( eST_Unit  );
580     signalSourceCmd.setSubunitId( 0xff );
581
582     SignalSubunitAddress signalSubunitAddr;
583     signalSubunitAddr.m_subunitType = 0xFF;
584     signalSubunitAddr.m_subunitId = 0xFF;
585     signalSubunitAddr.m_plugId = 0xFE;
586     signalSourceCmd.setSignalSource( signalSubunitAddr );
587    
588     setDestPlugAddrToSignalCmd( signalSourceCmd, *this );
589
590     signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
591     signalSourceCmd.setVerbose( getDebugLevel() );
592
593     if ( !signalSourceCmd.fire() ) {
594         debugError( "Could not get signal source for '%s'\n",
595                     getName() );
596         return -1;
597     }
598
599     if ( signalSourceCmd.getResponse() == AVCCommand::eR_Implemented ) {
600         SignalAddress* src=signalSourceCmd.getSignalSource();
601         Plug* p=NULL;
602         if(dynamic_cast<SignalUnitAddress *>(src)) {
603             SignalUnitAddress *usrc=dynamic_cast<SignalUnitAddress *>(src);
604             if (usrc->m_plugId & 0x80) {
605                 p=m_unit->getPlugManager().getPlug( eST_Unit, 0xFF,
606                         0xFF, 0xFF, eAPA_ExternalPlug, eAPD_Input,
607                         usrc->m_plugId & 0x7F );
608             } else {
609                 p=m_unit->getPlugManager().getPlug( eST_Unit, 0xFF,
610                         0xFF, 0xFF, eAPA_PCR, eAPD_Input,
611                         usrc->m_plugId & 0x7F );
612             }
613         } else if (dynamic_cast<SignalSubunitAddress *>(src)) {
614             SignalSubunitAddress *susrc=dynamic_cast<SignalSubunitAddress *>(src);
615             p=m_unit->getPlugManager().getPlug( byteToSubunitType(susrc->m_subunitType),
616                     susrc->m_subunitId, 0xFF, 0xFF, eAPA_SubunitPlug,
617                     eAPD_Output, susrc->m_plugId);
618         } else return -1;
619        
620         if (p==NULL) {
621             debugError("reported signal source plug not found\n");
622             return -1;
623         }
624        
625         return p->getGlobalId();
626     }
627
628     return -1;
629 }
630
631 bool
632 Plug::setConnection( Plug& plug )
633 {
634     SignalSourceCmd signalSourceCmd = setSrcPlugAddrToSignalCmd();
635     setDestPlugAddrToSignalCmd( signalSourceCmd, plug );
636     signalSourceCmd.setCommandType( AVCCommand::eCT_Control );
637     signalSourceCmd.setVerbose( getDebugLevel() );
638
639     if ( !signalSourceCmd.fire() ) {
640         debugError( "Could not set connection between '%s' and '%s'\n",
641                     getName(), plug.getName() );
642         return false;
643     }
644
645     if ( signalSourceCmd.getResponse() == AVCCommand::eR_Accepted ) {
646         debugOutput( DEBUG_LEVEL_VERBOSE,
647                      "Could set connection between '%s' and '%s'\n",
648                      getName(), plug.getName() );
649         return true;
650     }
651     debugOutput( DEBUG_LEVEL_VERBOSE,
652                  "Could not set connection between '%s' and '%s'\n",
653                  getName(),  plug.getName() );
654     return false;
655 }
656
657 bool
658 Plug::propagateFromConnectedPlug( ) {
659
660     if (getDirection() == eAPD_Output) {
661         if (getInputConnections().size()==0) {
662             debugWarning("No input connections to propagate from, skipping.\n");
663             return true;
664         }
665         if (getInputConnections().size()>1) {
666             debugWarning("Too many input connections to propagate from, using first one.\n");
667         }
668        
669         Plug* p = *(getInputConnections().begin());
670         return propagateFromPlug( p );
671        
672     } else if (getDirection() == eAPD_Input) {
673         if (getOutputConnections().size()==0) {
674             debugWarning("No output connections to propagate from, skipping.\n");
675             return true;
676         }
677         if (getOutputConnections().size()>1) {
678             debugWarning("Too many output connections to propagate from, using first one.\n");
679         }
680        
681         Plug* p = *(getOutputConnections().begin());
682         return propagateFromPlug( p );
683        
684     } else {
685         debugWarning("plug with undefined direction\n");
686         return false;
687     }
688 }
689
690 bool
691 Plug::propagateFromPlug( Plug *p ) {
692     debugOutput( DEBUG_LEVEL_VERBOSE,
693                  "Propagating info from plug '%s' to plug '%s'\n",
694                  p->getName(), getName() );
695    
696     if (m_clusterInfos.size()==0) {
697         m_clusterInfos=p->m_clusterInfos;
698     }
699    
700     m_nrOfChannels=p->m_nrOfChannels;
701    
702     return true;
703 }
704
705 int
706 Plug::getNrOfStreams() const
707 {
708     int nrOfChannels = 0;
709     for ( ClusterInfoVector::const_iterator it = m_clusterInfos.begin();
710           it != m_clusterInfos.end();
711           ++it )
712     {
713         const ClusterInfo* clusterInfo = &( *it );
714         nrOfChannels += clusterInfo->m_nrOfChannels;
715     }
716     return nrOfChannels;
717 }
718
719 int
720 Plug::getNrOfChannels() const
721 {
722     return m_nrOfChannels;
723 }
724
725 bool
726 Plug::setNrOfChannels(int i)
727 {
728     m_nrOfChannels=i;
729     return true;
730 }
731
732 int
733 Plug::getSampleRate() const
734 {
735     if(getPlugAddressType()==eAPA_PCR) {
736         if(getPlugDirection()==eAPD_Input) {
737             InputPlugSignalFormatCmd cmd( m_unit->get1394Service() );
738             cmd.m_form=0xFF;
739             cmd.m_eoh=0xFF;
740             cmd.m_fmt=0xFF;
741             cmd.m_plug=getPlugId();
742            
743             cmd.setNodeId( m_unit->getConfigRom().getNodeId() );
744             cmd.setSubunitType( eST_Unit  );
745             cmd.setSubunitId( 0xff );
746            
747             cmd.setCommandType( AVCCommand::eCT_Status );
748
749             if ( !cmd.fire() ) {
750                 debugError( "input plug signal format command failed\n" );
751                 return 0;
752             }
753            
754             if (cmd.m_fmt != 0x10 ) {
755                 debugWarning("Incorrect FMT response received: 0x%02X\n",cmd.m_fmt);
756             }
757            
758             return fdfSfcToSampleRate(cmd.m_fdf[0]);
759            
760         } else if (getPlugDirection()==eAPD_Output) {
761             OutputPlugSignalFormatCmd cmd( m_unit->get1394Service() );
762             cmd.m_form=0xFF;
763             cmd.m_eoh=0xFF;
764             cmd.m_fmt=0xFF;
765             cmd.m_plug=getPlugId();
766            
767             cmd.setNodeId( m_unit->getConfigRom().getNodeId() );
768             cmd.setSubunitType( eST_Unit  );
769             cmd.setSubunitId( 0xff );
770    
771             cmd.setCommandType( AVCCommand::eCT_Status );
772            
773             if ( !cmd.fire() ) {
774                 debugError( "output plug signal format command failed\n" );
775                 return 0;
776             }
777            
778             if (cmd.m_fmt != 0x10 ) {
779                 debugWarning("Incorrect FMT response received: 0x%02X\n",cmd.m_fmt);
780             }
781            
782             return fdfSfcToSampleRate(cmd.m_fdf[0]);
783        
784         } else {
785             debugError("PCR plug with undefined direction.\n");
786             return 0;
787         }
788     }
789    
790     // fallback
791     return convertESamplingFrequency( static_cast<ESamplingFrequency>( m_samplingFrequency ) );
792 }
793
794 bool
795 Plug::setSampleRate( int rate )
796 {
797     // apple style
798     if(getPlugAddressType()==eAPA_PCR) {
799         if(getPlugDirection()==eAPD_Input) {
800             InputPlugSignalFormatCmd cmd( m_unit->get1394Service() );
801             cmd.m_eoh=1;
802             cmd.m_form=0;
803             cmd.m_fmt=0x10;
804             cmd.m_plug=getPlugId();
805             cmd.m_fdf[0]=sampleRateToFdfSfc(rate);
806             cmd.m_fdf[1]=0xFF;
807             cmd.m_fdf[2]=0xFF;
808
809             cmd.setNodeId( m_unit->getConfigRom().getNodeId() );
810             cmd.setSubunitType( eST_Unit  );
811             cmd.setSubunitId( 0xff );
812            
813             cmd.setCommandType( AVCCommand::eCT_Control );
814
815             if ( !cmd.fire() ) {
816                 debugError( "input plug signal format command failed\n" );
817                 return false;
818             }
819
820             if ( cmd.getResponse() == AVCCommand::eR_Accepted )
821             {
822                 return true;
823             }
824             debugWarning( "output plug signal format command not accepted\n" );
825
826         } else if (getPlugDirection()==eAPD_Output) {
827             OutputPlugSignalFormatCmd cmd( m_unit->get1394Service() );
828             cmd.m_eoh=1;
829             cmd.m_form=0;
830             cmd.m_fmt=0x10;
831             cmd.m_plug=getPlugId();
832             cmd.m_fdf[0]=sampleRateToFdfSfc(rate);
833             cmd.m_fdf[1]=0xFF;
834             cmd.m_fdf[2]=0xFF;
835            
836             cmd.setNodeId( m_unit->getConfigRom().getNodeId() );
837             cmd.setSubunitType( eST_Unit  );
838             cmd.setSubunitId( 0xff );
839    
840             cmd.setCommandType( AVCCommand::eCT_Control );
841            
842             if ( !cmd.fire() ) {
843                 debugError( "output plug signal format command failed\n" );
844                 return false;
845             }
846
847             if ( cmd.getResponse() == AVCCommand::eR_Accepted )
848             {
849                 return true;
850             }
851             debugWarning( "output plug signal format command not accepted\n" );
852         } else {
853             debugError("PCR plug with undefined direction.\n");
854             return false;
855         }
856     }
857
858     // fallback: BeBoB style
859     ESamplingFrequency samplingFrequency = parseSampleRate(rate);
860    
861     ExtendedStreamFormatCmd extStreamFormatCmd(
862         m_unit->get1394Service(),
863         ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommandList );
864     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
865                                      getPlugId() );
866
867     extStreamFormatCmd.setPlugAddress(
868         PlugAddress(
869             Plug::convertPlugDirection(getPlugDirection() ),
870             PlugAddress::ePAM_Unit,
871             unitPlugAddress ) );
872
873     extStreamFormatCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
874     extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
875
876     int i = 0;
877     bool cmdSuccess = false;
878     bool correctFormatFound = false;
879
880     do {
881         extStreamFormatCmd.setIndexInStreamFormat( i );
882         extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
883         extStreamFormatCmd.setVerbose( getDebugLevel() );
884
885         cmdSuccess = extStreamFormatCmd.fire();
886
887         if ( cmdSuccess
888              && ( extStreamFormatCmd.getResponse() ==
889                   AVCCommand::eR_Implemented ) )
890         {
891             ESamplingFrequency foundFreq = eSF_DontCare;
892
893             FormatInformation* formatInfo =
894                 extStreamFormatCmd.getFormatInformation();
895             FormatInformationStreamsCompound* compoundStream
896                 = dynamic_cast< FormatInformationStreamsCompound* > (
897                     formatInfo->m_streams );
898             if ( compoundStream ) {
899                 foundFreq =
900                     static_cast< ESamplingFrequency >(
901                         compoundStream->m_samplingFrequency );
902             }
903
904             FormatInformationStreamsSync* syncStream
905                 = dynamic_cast< FormatInformationStreamsSync* > (
906                     formatInfo->m_streams );
907             if ( syncStream ) {
908                 foundFreq =
909                     static_cast< ESamplingFrequency >(
910                         syncStream->m_samplingFrequency );
911             }
912
913             if ( foundFreq == samplingFrequency )
914             {
915                 correctFormatFound = true;
916                 break;
917             }
918         }
919
920         ++i;
921     } while ( cmdSuccess
922               && ( extStreamFormatCmd.getResponse() ==
923                    ExtendedStreamFormatCmd::eR_Implemented ) );
924
925     if ( !cmdSuccess ) {
926         debugError( "setSampleRatePlug: Failed to retrieve format info\n" );
927         return false;
928     }
929
930     if ( !correctFormatFound ) {
931         debugError( "setSampleRatePlug: %s plug %d does not support "
932                     "sample rate %d\n",
933                     getName(),
934                     getPlugId(),
935                     convertESamplingFrequency( samplingFrequency ) );
936         return false;
937     }
938
939     extStreamFormatCmd.setSubFunction(
940         ExtendedStreamFormatCmd::eSF_ExtendedStreamFormatInformationCommand );
941     extStreamFormatCmd.setCommandType( AVCCommand::eCT_Control );
942     extStreamFormatCmd.setVerbose( getDebugLevel() );
943
944     if ( !extStreamFormatCmd.fire() ) {
945         debugError( "setSampleRate: Could not set sample rate %d "
946                     "to %s plug %d\n",
947                     convertESamplingFrequency( samplingFrequency ),
948                     getName(),
949                     getPlugId() );
950         return false;
951     }
952
953     return true;
954 }
955
956 bool
957 Plug::discoverConnectionsFromSpecificData(
958     EPlugDirection discoverDirection,
959     PlugAddressSpecificData* plugAddress,
960     PlugVector& connections )
961 {
962     UnitPlugSpecificDataPlugAddress* pUnitPlugAddress =
963         dynamic_cast<UnitPlugSpecificDataPlugAddress*>
964         ( plugAddress->m_plugAddressData );
965
966     SubunitPlugSpecificDataPlugAddress* pSubunitPlugAddress =
967         dynamic_cast<SubunitPlugSpecificDataPlugAddress*>
968         ( plugAddress->m_plugAddressData );
969
970     FunctionBlockPlugSpecificDataPlugAddress*
971         pFunctionBlockPlugAddress =
972         dynamic_cast<FunctionBlockPlugSpecificDataPlugAddress*>
973         ( plugAddress->m_plugAddressData );
974
975     Plug* plug = getPlugDefinedBySpecificData(
976         pUnitPlugAddress,
977         pSubunitPlugAddress,
978         pFunctionBlockPlugAddress );
979
980     if ( plug ) {
981         debugOutput( DEBUG_LEVEL_VERBOSE,
982                      "'(%d) %s' has a connection to '(%d) %s'\n",
983                      getGlobalId(),
984                      getName(),
985                      plug->getGlobalId(),
986                      plug->getName() );
987         addPlugConnection( connections, *plug );
988     } else {
989         debugError( "no corresponding plug found for '(%d) %s'\n",
990                     getGlobalId(),
991                     getName() );
992         return false;
993     }
994
995     return true;
996 }
997
998 bool
999 Plug::addPlugConnection( PlugVector& connections,
1000                            Plug& plug )
1001
1002 {
1003     for ( PlugVector::iterator it = connections.begin();
1004           it != connections.end();
1005           ++it )
1006     {
1007         Plug* cPlug = *it;
1008         if ( cPlug == &plug ) {
1009             debugOutput( DEBUG_LEVEL_VERBOSE,
1010                          "plug '%s' already in connection list\n",
1011                          plug.getName() );
1012             return true;
1013         }
1014     }
1015
1016     connections.push_back( &plug );
1017     return true;
1018 }
1019
1020 SignalSourceCmd
1021 Plug::setSrcPlugAddrToSignalCmd()
1022 {
1023     SignalSourceCmd signalSourceCmd( m_unit->get1394Service() );
1024
1025     switch( getSubunitType() ) {
1026     case eST_Unit:
1027     {
1028         SignalUnitAddress signalUnitAddr;
1029         if ( getPlugAddressType() == eAPA_ExternalPlug ) {
1030             signalUnitAddr.m_plugId = m_id + 0x80;
1031         } else {
1032             signalUnitAddr.m_plugId = m_id;
1033         }
1034         signalSourceCmd.setSignalSource( signalUnitAddr );
1035     }
1036     break;
1037     case eST_Music:
1038     case eST_Audio:
1039     {
1040         SignalSubunitAddress signalSubunitAddr;
1041         signalSubunitAddr.m_subunitType = getSubunitType();
1042         signalSubunitAddr.m_subunitId = getSubunitId();
1043         signalSubunitAddr.m_plugId = m_id;
1044         signalSourceCmd.setSignalSource( signalSubunitAddr );
1045     }
1046     break;
1047     default:
1048         debugError( "Unknown subunit type\n" );
1049     }
1050
1051     signalSourceCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
1052     signalSourceCmd.setSubunitType( eST_Unit  );
1053     signalSourceCmd.setSubunitId( 0xff );
1054
1055     return signalSourceCmd;
1056 }
1057
1058 void
1059 Plug::setDestPlugAddrToSignalCmd(SignalSourceCmd& signalSourceCmd,
1060                                    Plug& plug)
1061 {
1062     switch( plug.getSubunitType() ) {
1063     case eST_Unit:
1064     {
1065         SignalUnitAddress signalUnitAddr;
1066         if ( plug.getPlugAddressType() == eAPA_ExternalPlug ) {
1067             signalUnitAddr.m_plugId = plug.m_id + 0x80;
1068         } else {
1069             signalUnitAddr.m_plugId = plug.m_id;
1070         }
1071         signalSourceCmd.setSignalDestination( signalUnitAddr );
1072     }
1073     break;
1074     case eST_Music:
1075     case eST_Audio:
1076     {
1077         SignalSubunitAddress signalSubunitAddr;
1078         signalSubunitAddr.m_subunitType = plug.getSubunitType();
1079         signalSubunitAddr.m_subunitId = plug.getSubunitId();
1080         signalSubunitAddr.m_plugId = plug.m_id;
1081         signalSourceCmd.setSignalDestination( signalSubunitAddr );
1082     }
1083     break;
1084     default:
1085         debugError( "Unknown subunit type\n" );
1086     }
1087 }
1088
1089 void
1090 Plug::debugOutputClusterInfos( int debugLevel )
1091 {
1092     for ( ClusterInfoVector::const_iterator it = m_clusterInfos.begin();
1093           it != m_clusterInfos.end();
1094           ++it )
1095     {
1096         const ClusterInfo* clusterInfo = &( *it );
1097
1098         debugOutput( debugLevel, "number of channels: %d\n",
1099                      clusterInfo->m_nrOfChannels );
1100
1101         for ( ChannelInfoVector::const_iterator cit
1102                   = clusterInfo->m_channelInfos.begin();
1103               cit != clusterInfo->m_channelInfos.end();
1104               ++cit )
1105         {
1106             const ChannelInfo* channelInfo = &( *cit );
1107             channelInfo = channelInfo;
1108             debugOutput( debugLevel,
1109                          "stream position: %d\n",
1110                          channelInfo->m_streamPosition );
1111             debugOutput( debugLevel,
1112                          "location: %d\n",
1113                          channelInfo->m_location );
1114         }
1115     }
1116 }
1117
1118 const Plug::ClusterInfo*
1119 Plug::getClusterInfoByIndex(int index) const
1120 {
1121     for ( Plug::ClusterInfoVector::const_iterator clit =
1122               m_clusterInfos.begin();
1123           clit != m_clusterInfos.end();
1124           ++clit )
1125     {
1126         const ClusterInfo* info = &*clit;
1127         if ( info->m_index == index ) {
1128             return info;
1129         }
1130     }
1131     return 0;
1132 }
1133
1134 PlugAddress::EPlugDirection
1135 Plug::convertPlugDirection( EPlugDirection direction )
1136 {
1137     PlugAddress::EPlugDirection dir;
1138     switch ( direction ) {
1139     case Plug::eAPD_Input:
1140         dir = PlugAddress::ePD_Input;
1141         break;
1142     case Plug::eAPD_Output:
1143         dir = PlugAddress::ePD_Output;
1144         break;
1145     default:
1146         dir = PlugAddress::ePD_Undefined;
1147     }
1148     return dir;
1149 }
1150
1151 std::string
1152 Plug::plugAddressTypeToString(enum EPlugAddressType t) {
1153     switch (t) {
1154         case eAPA_PCR:
1155             return string("PCR");
1156         case eAPA_ExternalPlug:
1157             return string("External");
1158         case eAPA_AsynchronousPlug:
1159             return string("Async");
1160         case eAPA_SubunitPlug:
1161             return string("Subunit");
1162         case eAPA_FunctionBlockPlug:
1163             return string("Function Block");
1164         default:
1165         case eAPA_Undefined:
1166             return string("Undefined");
1167     }
1168 }
1169
1170 std::string
1171 Plug::plugTypeToString(enum EPlugType t) {
1172     switch (t) {
1173         case eAPT_IsoStream:
1174             return string("IsoStream");
1175         case eAPT_AsyncStream:
1176             return string("AsyncStream");
1177         case eAPT_Midi:
1178             return string("MIDI");
1179         case eAPT_Sync:
1180             return string("Sync");
1181         case eAPT_Analog:
1182             return string("Analog");
1183         case eAPT_Digital:
1184             return string("Digital");
1185         default:
1186         case eAPT_Unknown:
1187             return string("Unknown");
1188     }
1189 }
1190
1191 std::string
1192 Plug::plugDirectionToString(enum EPlugDirection t) {
1193     switch (t) {
1194         case eAPD_Input:
1195             return string("Input");
1196         case eAPD_Output:
1197             return string("Output");
1198         default:
1199         case eAPT_Unknown:
1200             return string("Unknown");
1201     }
1202 }
1203
1204 void
1205 Plug::showPlug() const
1206 {
1207     debugOutput( DEBUG_LEVEL_VERBOSE, "\tName               = %s\n",
1208                  getName() );
1209     debugOutput( DEBUG_LEVEL_VERBOSE, "\tType               = %s\n",
1210                  extendedPlugInfoPlugTypeToString( getPlugType() ) );
1211     debugOutput( DEBUG_LEVEL_VERBOSE, "\tAddress Type       = %s\n",
1212                  avPlugAddressTypeToString( getPlugAddressType() ) );
1213     debugOutput( DEBUG_LEVEL_VERBOSE, "\tId                 = %d\n",
1214                  getPlugId() );
1215     debugOutput( DEBUG_LEVEL_VERBOSE, "\tSubunitType        = %d\n",
1216                  getSubunitType() );
1217     debugOutput( DEBUG_LEVEL_VERBOSE, "\tSubunitId          = %d\n",
1218                  getSubunitId() );
1219     debugOutput( DEBUG_LEVEL_VERBOSE, "\tDirection          = %s\n",
1220                  avPlugDirectionToString( getPlugDirection() ) );
1221     debugOutput( DEBUG_LEVEL_VERBOSE, "\tSampling Rate      = %d\n",
1222                  getSampleRate() );
1223     debugOutput( DEBUG_LEVEL_VERBOSE, "\tNumber of Channels = %d\n",
1224                  getNrOfChannels() );
1225     debugOutput( DEBUG_LEVEL_VERBOSE, "\tNumber of Streams  = %d\n",
1226                  getNrOfStreams() );
1227     debugOutput( DEBUG_LEVEL_VERBOSE, "\tIncoming connections from: ");
1228    
1229     for ( PlugVector::const_iterator it = m_inputConnections.begin();
1230           it != m_inputConnections.end();
1231           ++it )
1232     {
1233         debugOutputShort(DEBUG_LEVEL_VERBOSE, "%s, ", (*it)->getName());
1234     }
1235     debugOutputShort(DEBUG_LEVEL_VERBOSE, "\n");
1236
1237     debugOutput( DEBUG_LEVEL_VERBOSE, "\tOutgoing connections to: ");
1238     for ( PlugVector::const_iterator it = m_outputConnections.begin();
1239           it != m_outputConnections.end();
1240           ++it )
1241     {
1242         debugOutputShort(DEBUG_LEVEL_VERBOSE, "%s, ", (*it)->getName());
1243     }
1244     debugOutputShort(DEBUG_LEVEL_VERBOSE, "\n");
1245
1246     flushDebugOutput();
1247 }
1248
1249
1250 Plug*
1251 Plug::getPlugDefinedBySpecificData(
1252     UnitPlugSpecificDataPlugAddress* pUnitPlugAddress,
1253     SubunitPlugSpecificDataPlugAddress* pSubunitPlugAddress,
1254     FunctionBlockPlugSpecificDataPlugAddress* pFunctionBlockPlugAddress )
1255 {
1256     subunit_type_t        subunitType       = 0xff;
1257     subunit_id_t          subunitId         = 0xff;
1258     function_block_type_t functionBlockType = 0xff;
1259     function_block_id_t   functionBlockId   = 0xff;
1260     EPlugAddressType    addressType       = eAPA_Undefined;
1261     EPlugDirection      direction         = eAPD_Unknown;
1262     plug_id_t             plugId            = 0xff;
1263
1264     if ( !pUnitPlugAddress
1265          && !pSubunitPlugAddress
1266          && !pFunctionBlockPlugAddress )
1267     {
1268         debugError( "No correct specific data found\n" );
1269         return 0;
1270     }
1271
1272     if ( pUnitPlugAddress ) {
1273         subunitType = eST_Unit;
1274         switch ( pUnitPlugAddress->m_plugType ) {
1275         case UnitPlugSpecificDataPlugAddress::ePT_PCR:
1276             addressType = eAPA_PCR;
1277             break;
1278         case UnitPlugSpecificDataPlugAddress::ePT_ExternalPlug:
1279             addressType = eAPA_ExternalPlug;
1280             break;
1281         case UnitPlugSpecificDataPlugAddress::ePT_AsynchronousPlug:
1282             addressType = eAPA_AsynchronousPlug;
1283             break;
1284         }
1285         // unit plug have only connections to subunits
1286         if ( getPlugAddressType() == eAPA_SubunitPlug ) {
1287             direction = getDirection();
1288         } else {
1289             debugError( "Function block has connection from/to unknown "
1290                         "plug type\n" );
1291             direction = eAPD_Unknown;
1292         }
1293         plugId = pUnitPlugAddress->m_plugId;
1294
1295         debugOutput( DEBUG_LEVEL_VERBOSE,
1296                      "'(%d) %s': Remote plug is a unit plug "
1297                      "(%s, %s, %d)\n",
1298                      getGlobalId(),
1299                      getName(),
1300                      avPlugAddressTypeToString( addressType ),
1301                      avPlugDirectionToString( direction ),
1302                      plugId );
1303     }
1304
1305     if ( pSubunitPlugAddress ) {
1306         subunitType = pSubunitPlugAddress->m_subunitType;
1307         subunitId = pSubunitPlugAddress->m_subunitId;
1308         addressType = eAPA_SubunitPlug;
1309
1310         if ( getPlugAddressType() == eAPA_FunctionBlockPlug ) {
1311             direction = getDirection();
1312         } else if ( getPlugAddressType() == eAPA_SubunitPlug ) {
1313             direction = toggleDirection( getDirection() );
1314         } else {
1315             // unit
1316             direction = getDirection();
1317         }
1318
1319         plugId = pSubunitPlugAddress->m_plugId;
1320         debugOutput( DEBUG_LEVEL_VERBOSE,
1321                      "'(%d) %s': Remote plug is a subunit plug "
1322                      "(%d, %d, %s, %d)\n",
1323                      getGlobalId(),
1324                      getName(),
1325                      subunitType,
1326                      subunitId,
1327                      avPlugDirectionToString( direction ),
1328                      plugId );
1329     }
1330
1331     if ( pFunctionBlockPlugAddress ) {
1332         subunitType = pFunctionBlockPlugAddress->m_subunitType;
1333         subunitId = pFunctionBlockPlugAddress->m_subunitId;
1334         functionBlockType = pFunctionBlockPlugAddress->m_functionBlockType;
1335         functionBlockId = pFunctionBlockPlugAddress->m_functionBlockId;
1336         addressType = eAPA_FunctionBlockPlug;
1337
1338         if ( getPlugAddressType() == eAPA_FunctionBlockPlug ) {
1339             direction = toggleDirection( getDirection() );
1340         } else if ( getPlugAddressType() == eAPA_SubunitPlug ){
1341             direction = getDirection();
1342         } else {
1343             debugError( "Function block has connection from/to unknown "
1344                         "plug type\n" );
1345             direction = eAPD_Unknown;
1346         }
1347
1348         plugId = pFunctionBlockPlugAddress->m_plugId;
1349
1350         debugOutput( DEBUG_LEVEL_VERBOSE,
1351                      "'(%d) %s': Remote plug is a functionblock plug "
1352                      "(%d, %d, %d, %d, %s, %d)\n",
1353                      getGlobalId(),
1354                      getName(),
1355                      subunitType,
1356                      subunitId,
1357                      functionBlockType,
1358                      functionBlockId,
1359                      avPlugDirectionToString( direction ),
1360                      plugId );
1361     }
1362
1363     ESubunitType enumSubunitType =
1364         static_cast<ESubunitType>( subunitType );
1365
1366     return m_unit->getPlugManager().getPlug(
1367         enumSubunitType,
1368         subunitId,
1369         functionBlockType,
1370         functionBlockId,
1371         addressType,
1372         direction,
1373         plugId );
1374 }
1375
1376 Plug::EPlugDirection
1377 Plug::toggleDirection( EPlugDirection direction ) const
1378 {
1379     EPlugDirection newDirection;
1380     switch ( direction ) {
1381     case eAPD_Output:
1382         newDirection = eAPD_Input;
1383         break;
1384     case eAPD_Input:
1385         newDirection = eAPD_Output;
1386         break;
1387     default:
1388         newDirection = direction;
1389     }
1390
1391     return newDirection;
1392 }
1393
1394 bool
1395 Plug::serializeChannelInfos( Glib::ustring basePath,
1396                                Util::IOSerialize& ser,
1397                                const ClusterInfo& clusterInfo ) const
1398 {
1399     bool result = true;
1400     int i = 0;
1401     for ( ChannelInfoVector::const_iterator it = clusterInfo.m_channelInfos.begin();
1402           it != clusterInfo.m_channelInfos.end();
1403           ++it )
1404     {
1405         const ChannelInfo& info = *it;
1406         std::ostringstream strstrm;
1407         strstrm << basePath << i;
1408
1409         result &= ser.write( strstrm.str() + "/m_streamPosition", info.m_streamPosition );
1410         result &= ser.write( strstrm.str() + "/m_location", info.m_location );
1411         result &= ser.write( strstrm.str() + "/m_name", info.m_name );
1412     }
1413
1414     return result;
1415 }
1416
1417 bool
1418 Plug::deserializeChannelInfos( Glib::ustring basePath,
1419                                  Util::IODeserialize& deser,
1420                                  ClusterInfo& clusterInfo )
1421 {
1422     int i = 0;
1423     bool bFinished = false;
1424     bool result = true;
1425     do {
1426         std::ostringstream strstrm;
1427         strstrm << basePath << i;
1428
1429         // check for one element to exist. when one exist the other elements
1430         // must also be there. otherwise just return (last) result.
1431         if ( deser.isExisting( strstrm.str() + "/m_streamPosition" ) ) {
1432             ChannelInfo info;
1433
1434             result &= deser.read( strstrm.str() + "/m_streamPosition", info.m_streamPosition );
1435             result &= deser.read( strstrm.str() + "/m_location", info.m_location );
1436             result &= deser.read( strstrm.str() + "/m_name", info.m_name );
1437
1438             if ( result ) {
1439                 clusterInfo.m_channelInfos.push_back( info );
1440                 i++;
1441             } else {
1442                 bFinished = true;
1443             }
1444         } else {
1445             bFinished = true;
1446         }
1447     } while ( !bFinished );
1448
1449     return result;
1450 }
1451
1452
1453 bool
1454 Plug::serializeClusterInfos( Glib::ustring basePath,
1455                                Util::IOSerialize& ser ) const
1456 {
1457     bool result = true;
1458     int i = 0;
1459     for ( ClusterInfoVector::const_iterator it = m_clusterInfos.begin();
1460           it != m_clusterInfos.end();
1461           ++it )
1462     {
1463         const ClusterInfo& info = *it;
1464         std::ostringstream strstrm;
1465         strstrm << basePath << i;
1466
1467         result &= ser.write( strstrm.str() + "/m_index", info.m_index );
1468         result &= ser.write( strstrm.str() + "/m_portType", info.m_portType );
1469         result &= ser.write( strstrm.str() + "/m_name", info.m_name );
1470         result &= ser.write( strstrm.str() + "/m_nrOfChannels", info.m_nrOfChannels );
1471         result &= serializeChannelInfos( strstrm.str() + "/m_channelInfo", ser, info );
1472         result &= ser.write( strstrm.str() + "/m_streamFormat", info.m_streamFormat );
1473
1474     }
1475
1476     return result;
1477 }
1478
1479 bool
1480 Plug::deserializeClusterInfos( Glib::ustring basePath,
1481                                  Util::IODeserialize& deser )
1482 {
1483     int i = 0;
1484     bool bFinished = false;
1485     bool result = true;
1486     do {
1487         std::ostringstream strstrm;
1488         strstrm << basePath << i;
1489
1490         // check for one element to exist. when one exist the other elements
1491         // must also be there. otherwise just return (last) result.
1492         if ( deser.isExisting( strstrm.str() + "/m_index" ) ) {
1493             ClusterInfo info;
1494
1495             result &= deser.read( strstrm.str() + "/m_index", info.m_index );
1496             result &= deser.read( strstrm.str() + "/m_portType", info.m_portType );
1497             result &= deser.read( strstrm.str() + "/m_name", info.m_name );
1498             result &= deser.read( strstrm.str() + "/m_nrOfChannels", info.m_nrOfChannels );
1499             result &= deserializeChannelInfos( strstrm.str() + "/m_channelInfo", deser, info );
1500             result &= deser.read( strstrm.str() + "/m_streamFormat", info.m_streamFormat );
1501
1502             if ( result ) {
1503                 m_clusterInfos.push_back( info );
1504                 i++;
1505             } else {
1506                 bFinished = true;
1507             }
1508         } else {
1509             bFinished = true;
1510         }
1511     } while ( !bFinished );
1512
1513     return result;
1514 }
1515
1516
1517 bool
1518 Plug::serializeFormatInfos( Glib::ustring basePath,
1519                               Util::IOSerialize& ser ) const
1520 {
1521     bool result = true;
1522     int i = 0;
1523     for ( FormatInfoVector::const_iterator it = m_formatInfos.begin();
1524           it != m_formatInfos.end();
1525           ++it )
1526     {
1527         const FormatInfo& info = *it;
1528         std::ostringstream strstrm;
1529         strstrm << basePath << i;
1530
1531         result &= ser.write( strstrm.str() + "/m_samplingFrequency", info.m_samplingFrequency );
1532         result &= ser.write( strstrm.str() + "/m_isSyncStream", info.m_isSyncStream );
1533         result &= ser.write( strstrm.str() + "/m_audioChannels", info.m_audioChannels );
1534         result &= ser.write( strstrm.str() + "/m_midiChannels", info.m_midiChannels );
1535         result &= ser.write( strstrm.str() + "/m_index", info.m_index );
1536     }
1537     return result;
1538 }
1539
1540 bool
1541 Plug::deserializeFormatInfos( Glib::ustring basePath,
1542                                 Util::IODeserialize& deser )
1543 {
1544     int i = 0;
1545     bool bFinished = false;
1546     bool result = true;
1547     do {
1548         std::ostringstream strstrm;
1549         strstrm << basePath << i;
1550
1551         // check for one element to exist. when one exist the other elements
1552         // must also be there. otherwise just return (last) result.
1553         if ( deser.isExisting( strstrm.str() + "/m_samplingFrequency" ) ) {
1554             FormatInfo info;
1555
1556             result &= deser.read( strstrm.str() + "/m_samplingFrequency", info.m_samplingFrequency );
1557             result &= deser.read( strstrm.str() + "/m_isSyncStream", info.m_isSyncStream );
1558             result &= deser.read( strstrm.str() + "/m_audioChannels", info.m_audioChannels );
1559             result &= deser.read( strstrm.str() + "/m_midiChannels", info.m_midiChannels );
1560             result &= deser.read( strstrm.str() + "/m_index", info.m_index );
1561
1562             if ( result ) {
1563                 m_formatInfos.push_back( info );
1564                 i++;
1565             } else {
1566                 bFinished = true;
1567             }
1568         } else {
1569             bFinished = true;
1570         }
1571     } while ( !bFinished );
1572
1573     return result;
1574 }
1575
1576
1577 bool
1578 Plug::serializePlugVector( Glib::ustring basePath,
1579                                Util::IOSerialize& ser,
1580                                const PlugVector& vec) const
1581 {
1582     bool result = true;
1583     int i = 0;
1584     for ( PlugVector::const_iterator it = vec.begin();
1585           it != vec.end();
1586           ++it )
1587     {
1588         const Plug* pPlug = *it;
1589         std::ostringstream strstrm;
1590         strstrm << basePath << i;
1591
1592         result &= ser.write( strstrm.str() + "/global_id", pPlug->getGlobalId() );
1593         i++;
1594     }
1595     return result;
1596 }
1597
1598 bool
1599 Plug::deserializePlugVector( Glib::ustring basePath,
1600                                  Util::IODeserialize& deser,
1601                                  PlugVector& vec )
1602 {
1603     int i = 0;
1604     bool bFinished = false;
1605     bool result = true;
1606     do {
1607         std::ostringstream strstrm;
1608         strstrm << basePath << i;
1609
1610         // check for one element to exist. when one exist the other elements
1611         // must also be there. otherwise just return (last) result.
1612         if ( deser.isExisting( strstrm.str() + "/global_id" ) ) {
1613             unsigned int iPlugId;
1614             result &= deser.read( strstrm.str() + "/global_id", iPlugId );
1615
1616             if ( result ) {
1617                 Plug* pPlug = m_unit->getPlugManager().getPlug( iPlugId );
1618                 if ( pPlug ) {
1619                     vec.push_back( pPlug );
1620                 } else {
1621                     result = false;
1622                     bFinished = true;
1623                 }
1624                 i++;
1625             } else {
1626                 bFinished = true;
1627             }
1628         } else {
1629             bFinished = true;
1630         }
1631     } while ( !bFinished );
1632
1633     return result;
1634 }
1635
1636 bool
1637 Plug::serialize( Glib::ustring basePath, Util::IOSerialize& ser ) const
1638 {
1639     bool result=true;
1640     result &= ser.write( basePath + "m_subunitType", getSubunitType());
1641     result &= ser.write( basePath + "m_subunitId", getSubunitId());
1642     result &= ser.write( basePath + "m_functionBlockType", m_functionBlockType);
1643     result &= ser.write( basePath + "m_functionBlockId", m_functionBlockId);
1644     result &= ser.write( basePath + "m_addressType", m_addressType );
1645     result &= ser.write( basePath + "m_direction", m_direction);
1646     result &= ser.write( basePath + "m_id", m_id);
1647     result &= ser.write( basePath + "m_infoPlugType", m_infoPlugType);
1648     result &= ser.write( basePath + "m_nrOfChannels", m_nrOfChannels);
1649     result &= ser.write( basePath + "m_name", m_name);
1650     result &= serializeClusterInfos( basePath + "m_clusterInfos", ser );
1651     result &= ser.write( basePath + "m_samplingFrequency", m_samplingFrequency);
1652     result &= serializeFormatInfos( basePath + "m_formatInfo", ser );
1653     result &= serializePlugVector( basePath + "m_inputConnections", ser, m_inputConnections );
1654     result &= serializePlugVector( basePath + "m_outputConnections", ser, m_outputConnections );
1655     result &= ser.write( basePath + "m_verbose_level", getDebugLevel());
1656     result &= ser.write( basePath + "m_globalId", m_globalId);
1657     result &= ser.write( basePath + "m_globalIdCounter", m_globalIdCounter );
1658
1659     return result;
1660 }
1661
1662 Plug*
1663 Plug::deserialize( Glib::ustring basePath,
1664                      Util::IODeserialize& deser,
1665                      Unit& unit,
1666                      PlugManager& plugManager )
1667 {
1668     #warning FIXME: The derived class should be creating these
1669     // FIXME: The derived class should be creating these, such that discover() can become pure virtual
1670
1671     if ( !deser.isExisting( basePath + "m_subunitType" ) ) {
1672         return 0;
1673     }
1674     Plug* pPlug = new Plug;
1675     if ( !pPlug ) {
1676         return 0;
1677     }
1678
1679     pPlug->m_unit = &unit;
1680    
1681     bool result=true;
1682    
1683     ESubunitType subunitType;
1684     result  = deser.read( basePath + "m_subunitType", subunitType );
1685     subunit_t subunitId;
1686     result &= deser.read( basePath + "m_subunitId", subunitId );
1687     pPlug->m_subunit = unit.getSubunit( subunitType, subunitType );
1688    
1689     result &= deser.read( basePath + "m_functionBlockType", pPlug->m_functionBlockType );
1690     result &= deser.read( basePath + "m_functionBlockId", pPlug->m_functionBlockId );
1691     result &= deser.read( basePath + "m_addressType", pPlug->m_addressType );
1692     result &= deser.read( basePath + "m_direction", pPlug->m_direction );
1693     result &= deser.read( basePath + "m_id", pPlug->m_id );
1694     result &= deser.read( basePath + "m_infoPlugType", pPlug->m_infoPlugType );
1695     result &= deser.read( basePath + "m_nrOfChannels", pPlug->m_nrOfChannels );
1696     result &= deser.read( basePath + "m_name", pPlug->m_name );
1697     result &= pPlug->deserializeClusterInfos( basePath + "m_clusterInfos", deser );
1698     result &= deser.read( basePath + "m_samplingFrequency", pPlug->m_samplingFrequency );
1699     result &= pPlug->deserializeFormatInfos( basePath + "m_formatInfos", deser );
1700     // input and output connections can't be processed here because not all plugs might
1701     // deserialized at this point. so we do that in deserializeUpdate.
1702     int level;
1703     result &= deser.read( basePath + "m_verbose_level", level );
1704     setDebugLevel(level);
1705     result &= deser.read( basePath + "m_globalId", pPlug->m_globalId );
1706     result &= deser.read( basePath + "m_globalIdCounter", pPlug->m_globalIdCounter );
1707
1708     if ( !result ) {
1709         delete pPlug;
1710         return 0;
1711     }
1712
1713     return pPlug;
1714 }
1715
1716 bool
1717 Plug::deserializeUpdate( Glib::ustring basePath,
1718                            Util::IODeserialize& deser )
1719 {
1720     bool result;
1721
1722     result  = deserializePlugVector( basePath + "m_inputConnections", deser, m_inputConnections );
1723     result &= deserializePlugVector( basePath + "m_outputConnections", deser, m_outputConnections );
1724
1725     return result;
1726 }
1727
1728 /////////////////////////////////////////
1729 /////////////////////////////////////////
1730
1731 const char* avPlugAddressTypeStrings[] =
1732 {
1733     "PCR",
1734     "external",
1735     "asynchronous",
1736     "subunit",
1737     "functionblock",
1738     "undefined",
1739 };
1740
1741 const char* avPlugAddressTypeToString( Plug::EPlugAddressType type )
1742 {
1743     if ( type > ( int )( sizeof( avPlugAddressTypeStrings )
1744                          / sizeof( avPlugAddressTypeStrings[0] ) ) )
1745     {
1746         type = Plug::eAPA_Undefined;
1747     }
1748     return avPlugAddressTypeStrings[type];
1749 }
1750
1751 const char* avPlugTypeStrings[] =
1752 {
1753     "IsoStream",
1754     "AsyncStream",
1755     "MIDI",
1756     "Sync",
1757     "Analog",
1758     "Digital",
1759     "Unknown",
1760 };
1761
1762 const char* avPlugTypeToString( Plug::EPlugType type )
1763 {
1764     if ( type > ( int )( sizeof( avPlugTypeStrings )
1765                          / sizeof( avPlugTypeStrings[0] ) ) )
1766     {
1767         type = Plug::eAPT_Unknown;
1768     }
1769     return avPlugTypeStrings[type];
1770 }
1771
1772 const char* avPlugDirectionStrings[] =
1773 {
1774     "Input",
1775     "Output",
1776     "Unknown",
1777 };
1778
1779 const char* avPlugDirectionToString( Plug::EPlugDirection type )
1780 {
1781     if ( type > ( int )( sizeof( avPlugDirectionStrings )
1782                          / sizeof( avPlugDirectionStrings[0] ) ) )
1783     {
1784         type = Plug::eAPD_Unknown;
1785     }
1786     return avPlugDirectionStrings[type];
1787 }
1788
1789 /////////////////////////////////////
1790
1791
1792 PlugManager::PlugManager(  )
1793 {
1794
1795 }
1796
1797 PlugManager::PlugManager( const PlugManager& rhs )
1798 {
1799     setDebugLevel( rhs.getDebugLevel() );
1800 }
1801
1802 PlugManager::~PlugManager()
1803 {
1804 }
1805
1806 bool
1807 PlugManager::addPlug( Plug& plug )
1808 {
1809     m_plugs.push_back( &plug );
1810     return true;
1811 }
1812
1813 bool
1814 PlugManager::remPlug( Plug& plug )
1815 {
1816     for ( PlugVector::iterator it = m_plugs.begin();
1817           it !=  m_plugs.end();
1818           ++it )
1819     {
1820         Plug* plugIt = *it;
1821         if ( plugIt == &plug ) {
1822             m_plugs.erase( it );
1823             return true;
1824         }
1825     }
1826     return false;
1827 }
1828
1829 // helper function
1830 static void addConnection( PlugConnectionVector& connections,
1831                            Plug& srcPlug,
1832                            Plug& destPlug )
1833 {
1834     for ( PlugConnectionVector::iterator it = connections.begin();
1835           it != connections.end();
1836           ++it )
1837     {
1838         PlugConnection* con = *it;
1839         if ( ( &( con->getSrcPlug() ) == &srcPlug )
1840              && ( &( con->getDestPlug() ) == &destPlug ) )
1841         {
1842             return;
1843         }
1844     }
1845     connections.push_back( new PlugConnection( srcPlug, destPlug ) );
1846 }
1847
1848 bool
1849 PlugManager::tidyPlugConnections(PlugConnectionVector& connections)
1850 {
1851     for ( PlugVector::const_iterator it = m_plugs.begin();
1852           it !=  m_plugs.end();
1853           ++it )
1854     {
1855         Plug* plug = *it;
1856         for ( PlugVector::const_iterator it =
1857                   plug->getInputConnections().begin();
1858             it != plug->getInputConnections().end();
1859             ++it )
1860         {
1861             addConnection( connections, *( *it ), *plug );
1862         }
1863         plug->getInputConnections().clear();
1864        
1865         for ( PlugVector::const_iterator it =
1866                   plug->getOutputConnections().begin();
1867             it != plug->getOutputConnections().end();
1868             ++it )
1869         {
1870             addConnection( connections, *plug, *( *it ) );
1871         }
1872         plug->getOutputConnections().clear();
1873     }
1874    
1875     for ( PlugConnectionVector::iterator it = connections.begin();
1876           it != connections.end();
1877           ++it )
1878     {
1879         PlugConnection * con = *it;
1880         con->getSrcPlug().getOutputConnections().push_back(&( con->getDestPlug() ));
1881         con->getDestPlug().getInputConnections().push_back(&( con->getSrcPlug() ));
1882
1883     }
1884    
1885     return true;
1886 }
1887
1888 static void addConnectionOwner( PlugConnectionOwnerVector& connections,
1889                            Plug& srcPlug,
1890                            Plug& destPlug )
1891 {
1892
1893     for ( PlugConnectionOwnerVector::iterator it = connections.begin();
1894           it != connections.end();
1895           ++it )
1896     {
1897         PlugConnection& con = *it;
1898         if ( ( &( con.getSrcPlug() ) == &srcPlug )
1899              && ( &( con.getDestPlug() ) == &destPlug ) )
1900         {
1901             return;
1902         }
1903     }
1904     connections.push_back( PlugConnection( srcPlug, destPlug ) );
1905 }
1906
1907
1908 void
1909 PlugManager::showPlugs() const
1910 {
1911     if(getDebugLevel() < DEBUG_LEVEL_INFO) return;
1912
1913     // \todo The information provided here could be better arranged. For a start it is ok, but
1914     // there is room for improvement. Something for a lazy sunday afternoon (tip: maybe drink some
1915     // beer to get into the mood)
1916
1917     printf( "\nSummary\n" );
1918     printf( "-------\n\n" );
1919     printf( "Nr | AddressType     | Direction | SubUnitType | SubUnitId | FunctionBlockType | FunctionBlockId | Id   | Type         |Name\n" );
1920     printf( "---+-----------------+-----------+-------------+-----------+-------------------+-----------------+------+--------------+------\n" );
1921
1922     for ( PlugVector::const_iterator it = m_plugs.begin();
1923           it !=  m_plugs.end();
1924           ++it )
1925     {
1926         Plug* plug = *it;
1927
1928         printf( "%2d | %15s | %9s | %11s |      0x%02x |              0x%02x |            0x%02x | 0x%02x | %12s | %s\n",
1929                 plug->getGlobalId(),
1930                 avPlugAddressTypeToString( plug->getPlugAddressType() ),
1931                 avPlugDirectionToString( plug->getDirection() ),
1932                 subunitTypeToString( plug->getSubunitType() ),
1933                 plug->getSubunitId(),
1934                 plug->getFunctionBlockType(),
1935                 plug->getFunctionBlockId(),
1936                 plug->getPlugId(),
1937                 avPlugTypeToString( plug->getPlugType() ),
1938                 plug->getName() );
1939     }
1940
1941     printf( "\nConnections\n" );
1942     printf( "-----------\n" );
1943
1944     PlugConnectionOwnerVector connections;
1945
1946     for ( PlugVector::const_iterator it = m_plugs.begin();
1947           it !=  m_plugs.end();
1948           ++it )
1949     {
1950         Plug* plug = *it;
1951         for ( PlugVector::const_iterator it =
1952                   plug->getInputConnections().begin();
1953             it != plug->getInputConnections().end();
1954             ++it )
1955         {
1956             addConnectionOwner( connections, *( *it ), *plug );
1957         }
1958         for ( PlugVector::const_iterator it =
1959                   plug->getOutputConnections().begin();
1960             it != plug->getOutputConnections().end();
1961             ++it )
1962         {
1963             addConnectionOwner( connections, *plug, *( *it ) );
1964         }
1965     }
1966
1967     printf( "digraph avcconnections {\n" );
1968     for ( PlugConnectionOwnerVector::iterator it = connections.begin();
1969           it != connections.end();
1970           ++it )
1971     {
1972         PlugConnection& con = *it;
1973         printf( "\t\"(%d) %s\" -> \"(%d) %s\"\n",
1974                 con.getSrcPlug().getGlobalId(),
1975                 con.getSrcPlug().getName(),
1976                 con.getDestPlug().getGlobalId(),
1977                 con.getDestPlug().getName() );
1978     }
1979     for ( PlugVector::const_iterator it = m_plugs.begin();
1980           it != m_plugs.end();
1981           ++it )
1982     {
1983         Plug* plug = *it;
1984         if ( plug->getFunctionBlockType() != 0xff ) {
1985             std::ostringstream strstrm;
1986             switch(plug->getFunctionBlockType()) {
1987                 case 0x80:
1988                     strstrm << "Selector FB";
1989                     break;
1990                 case 0x81:
1991                     strstrm << "Feature FB";
1992                     break;
1993                 case 0x82:
1994                     strstrm << "Processing FB";
1995                     break;
1996                 case 0x83:
1997                     strstrm << "CODEC FB";
1998                     break;
1999                 default:
2000                     strstrm << plug->getFunctionBlockType();
2001             }
2002            
2003             if ( plug->getPlugDirection() == Plug::eAPD_Input ) {
2004                 printf( "\t\"(%d) %s\" -> \"(%s, ID %d)\"\n",
2005                         plug->getGlobalId(),
2006                         plug->getName(),
2007                         strstrm.str().c_str(),
2008                         plug->getFunctionBlockId() );
2009             } else {
2010                 printf( "\t\"(%s, ID %d)\" -> \t\"(%d) %s\"\n",
2011                         strstrm.str().c_str(),
2012                         plug->getFunctionBlockId(),
2013                         plug->getGlobalId(),
2014                         plug->getName() );
2015             }
2016         }
2017     }
2018
2019     const char* colorStrings[] = {
2020         "coral",
2021         "slateblue",
2022         "white",
2023         "green",
2024         "yellow",
2025         "grey",
2026     };
2027
2028     for ( PlugVector::const_iterator it = m_plugs.begin();
2029           it !=  m_plugs.end();
2030           ++it )
2031     {
2032         Plug* plug = *it;
2033         printf( "\t\"(%d) %s\" [color=%s,style=filled];\n",
2034                 plug->getGlobalId(), plug->getName(),
2035                 colorStrings[plug->getPlugAddressType() ] );
2036     }
2037
2038     printf("}\n" );
2039     printf( "Use \"dot -Tps FILENAME.dot -o FILENAME.ps\" "
2040             "to generate graph\n");
2041
2042     debugOutput( DEBUG_LEVEL_VERBOSE, "Plug details\n" );
2043     debugOutput( DEBUG_LEVEL_VERBOSE, "------------\n" );
2044     for ( PlugVector::const_iterator it = m_plugs.begin();
2045           it !=  m_plugs.end();
2046           ++it )
2047     {
2048         Plug* plug = *it;
2049         debugOutput( DEBUG_LEVEL_VERBOSE, "Plug %d:\n", plug->getGlobalId() );
2050         plug->showPlug();
2051
2052     }
2053 }
2054
2055 Plug*
2056 PlugManager::getPlug( ESubunitType subunitType,
2057                         subunit_id_t subunitId,
2058                         function_block_type_t functionBlockType,
2059                         function_block_id_t functionBlockId,
2060                         Plug::EPlugAddressType plugAddressType,
2061                         Plug::EPlugDirection plugDirection,
2062                         plug_id_t plugId ) const
2063 {
2064     debugOutput( DEBUG_LEVEL_VERBOSE, "SBT, SBID, FBT, FBID, AT, PD, ID = "
2065                  "(0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x)\n",
2066                  subunitType,
2067                  subunitId,
2068                  functionBlockType,
2069                  functionBlockId,
2070                  plugAddressType,
2071                  plugDirection,
2072                  plugId );
2073
2074     for ( PlugVector::const_iterator it = m_plugs.begin();
2075           it !=  m_plugs.end();
2076           ++it )
2077     {
2078         Plug* plug = *it;
2079
2080         if (    ( subunitType == plug->getSubunitType() )
2081              && ( subunitId == plug->getSubunitId() )
2082              && ( functionBlockType == plug->getFunctionBlockType() )
2083              && ( functionBlockId == plug->getFunctionBlockId() )
2084              && ( plugAddressType == plug->getPlugAddressType() )
2085              && ( plugDirection == plug->getPlugDirection() )
2086              && ( plugId == plug->getPlugId() ) )
2087         {
2088             return plug;
2089         }
2090     }
2091
2092     return 0;
2093 }
2094
2095 Plug*
2096 PlugManager::getPlug( int iGlobalId ) const
2097 {
2098     for ( PlugVector::const_iterator it = m_plugs.begin();
2099           it !=  m_plugs.end();
2100           ++it )
2101     {
2102         Plug* pPlug = *it;
2103         if ( pPlug->getGlobalId() == iGlobalId ) {
2104             return pPlug;
2105         }
2106     }
2107
2108     return 0;
2109 }
2110
2111 PlugVector
2112 PlugManager::getPlugsByType( ESubunitType subunitType,
2113                                subunit_id_t subunitId,
2114                                function_block_type_t functionBlockType,
2115                                function_block_id_t functionBlockId,
2116                                Plug::EPlugAddressType plugAddressType,
2117                                Plug::EPlugDirection plugDirection,
2118                                Plug::EPlugType type) const
2119 {
2120     debugOutput( DEBUG_LEVEL_VERBOSE, "SBT, SBID, FBT, FBID, AT, PD, T = "
2121                  "(0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x)\n",
2122                  subunitType,
2123                  subunitId,
2124                  functionBlockType,
2125                  functionBlockId,
2126                  plugAddressType,
2127                  plugDirection,
2128                  type );
2129
2130     PlugVector plugVector;
2131     for ( PlugVector::const_iterator it = m_plugs.begin();
2132           it !=  m_plugs.end();
2133           ++it )
2134     {
2135         Plug* pPlug = *it;
2136
2137         if (    ( subunitType == pPlug->getSubunitType() )
2138              && ( subunitId == pPlug->getSubunitId() )
2139              && ( functionBlockType == pPlug->getFunctionBlockType() )
2140              && ( functionBlockId == pPlug->getFunctionBlockId() )
2141              && ( plugAddressType == pPlug->getPlugAddressType() )
2142              && ( plugDirection == pPlug->getPlugDirection() )
2143              && ( type == pPlug->getPlugType() ) )
2144         {
2145             plugVector.push_back( pPlug );
2146         }
2147     }
2148
2149     return plugVector;
2150 }
2151
2152 bool
2153 PlugManager::serialize( Glib::ustring basePath, Util::IOSerialize& ser ) const
2154 {
2155     bool result = true;
2156     int i = 0;
2157     for ( PlugVector::const_iterator it = m_plugs.begin();
2158           it !=  m_plugs.end();
2159           ++it )
2160     {
2161         Plug* pPlug = *it;
2162         std::ostringstream strstrm;
2163         strstrm << basePath << i;
2164         result &= pPlug->serialize( strstrm.str() + "/", ser );
2165         i++;
2166     }
2167
2168     return result;
2169 }
2170
2171 PlugManager*
2172 PlugManager::deserialize( Glib::ustring basePath,
2173                             Util::IODeserialize& deser,
2174                             Unit& unit )
2175
2176 {
2177     PlugManager* pMgr = new PlugManager;
2178
2179     if ( !pMgr ) {
2180         return 0;
2181     }
2182
2183     int i = 0;
2184     bool bFinished = false;
2185     do {
2186         std::ostringstream strstrm;
2187         strstrm << basePath << i;
2188         // unit still holds a null pointer for the plug manager
2189         // therefore we have to *this as additional argument
2190         Plug* pPlug = Plug::deserialize( strstrm.str() + "/",
2191                                              deser,
2192                                              unit,
2193                                              *pMgr );
2194         if ( pPlug ) {
2195             pMgr->m_plugs.push_back( pPlug );
2196             i++;
2197         } else {
2198             bFinished = true;
2199         }
2200     } while ( !bFinished );
2201
2202     return pMgr;
2203 }
2204
2205
2206 ////////////////////////////////////
2207
2208 PlugConnection::PlugConnection( Plug& srcPlug, Plug& destPlug )
2209     : m_srcPlug( &srcPlug )
2210     , m_destPlug( &destPlug )
2211 {
2212 }
2213
2214 PlugConnection::PlugConnection()
2215     : m_srcPlug( 0 )
2216     , m_destPlug( 0 )
2217 {
2218 }
2219
2220 bool
2221 PlugConnection::serialize( Glib::ustring basePath, Util::IOSerialize& ser ) const
2222 {
2223     bool result;
2224     result  = ser.write( basePath + "m_srcPlug", m_srcPlug->getGlobalId() );
2225     result &= ser.write( basePath + "m_destPlug", m_destPlug->getGlobalId() );
2226     return result;
2227 }
2228
2229 PlugConnection*
2230 PlugConnection::deserialize( Glib::ustring basePath,
2231                                Util::IODeserialize& deser,
2232                                Unit& unit )
2233 {
2234     if ( !deser.isExisting( basePath + "m_srcPlug" ) ) {
2235         return 0;
2236     }
2237     PlugConnection* pConnection = new PlugConnection;
2238     if ( !pConnection ) {
2239         return 0;
2240     }
2241
2242     bool result;
2243     int iSrcPlugId;
2244     int iDestPlugId;
2245     result  = deser.read( basePath + "m_srcPlug", iSrcPlugId );
2246     result &= deser.read( basePath + "m_destPlug",  iDestPlugId );
2247
2248     if ( !result ) {
2249         delete pConnection;
2250         return 0;
2251     }
2252
2253     pConnection->m_srcPlug  = unit.getPlugManager().getPlug( iSrcPlugId );
2254     pConnection->m_destPlug = unit.getPlugManager().getPlug( iDestPlugId );
2255
2256     if ( !pConnection->m_srcPlug || !pConnection->m_destPlug ) {
2257         delete pConnection;
2258         return 0;
2259     }
2260
2261     return pConnection;
2262 }
2263
2264 ExtendedStreamFormatCmd
2265 Plug::setPlugAddrToStreamFormatCmd(
2266     ExtendedStreamFormatCmd::ESubFunction subFunction)
2267 {
2268     ExtendedStreamFormatCmd extStreamFormatInfoCmd(
2269         m_unit->get1394Service(),
2270         subFunction );
2271     switch( getSubunitType() ) {
2272     case eST_Unit:
2273     {
2274             UnitPlugAddress::EPlugType ePlugType =
2275                 UnitPlugAddress::ePT_Unknown;
2276             switch ( m_addressType ) {
2277                 case eAPA_PCR:
2278                     ePlugType = UnitPlugAddress::ePT_PCR;
2279                     break;
2280                 case eAPA_ExternalPlug:
2281                     ePlugType = UnitPlugAddress::ePT_ExternalPlug;
2282                     break;
2283                 case eAPA_AsynchronousPlug:
2284                     ePlugType = UnitPlugAddress::ePT_AsynchronousPlug;
2285                     break;
2286                 default:
2287                     ePlugType = UnitPlugAddress::ePT_Unknown;
2288             }
2289         UnitPlugAddress unitPlugAddress( ePlugType,
2290                                          m_id );
2291         extStreamFormatInfoCmd.setPlugAddress(
2292             PlugAddress( convertPlugDirection( getPlugDirection() ),
2293                          PlugAddress::ePAM_Unit,
2294                          unitPlugAddress ) );
2295         }
2296         break;
2297     case eST_Music:
2298     case eST_Audio:
2299     {
2300         switch( m_addressType ) {
2301         case eAPA_SubunitPlug:
2302         {
2303             SubunitPlugAddress subunitPlugAddress( m_id );
2304             extStreamFormatInfoCmd.setPlugAddress(
2305                 PlugAddress( convertPlugDirection( getPlugDirection() ),
2306                              PlugAddress::ePAM_Subunit,
2307                              subunitPlugAddress ) );
2308         }
2309         break;
2310         case eAPA_FunctionBlockPlug:
2311         {
2312             FunctionBlockPlugAddress functionBlockPlugAddress(
2313                 m_functionBlockType,
2314                 m_functionBlockId,
2315                 m_id );
2316             extStreamFormatInfoCmd.setPlugAddress(
2317                 PlugAddress( convertPlugDirection( getPlugDirection() ),
2318                              PlugAddress::ePAM_FunctionBlock,
2319                              functionBlockPlugAddress ) );
2320         }
2321         break;
2322         default:
2323             extStreamFormatInfoCmd.setPlugAddress(PlugAddress());
2324         }
2325     }
2326     break;
2327     default:
2328         debugError( "Unknown subunit type\n" );
2329     }
2330
2331     extStreamFormatInfoCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
2332     extStreamFormatInfoCmd.setCommandType( AVCCommand::eCT_Status );
2333     extStreamFormatInfoCmd.setSubunitId( getSubunitId() );
2334     extStreamFormatInfoCmd.setSubunitType( getSubunitType() );
2335
2336     return extStreamFormatInfoCmd;
2337 }
2338
2339 }
Note: See TracBrowser for help on using the browser.