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

Revision 637, 72.6 kB (checked in by wagi, 17 years ago)

- some code cleanup (whitespace, unnecessary ';' removed, code indention, ...)
- loadFromCache: problem identified why it doesn't work. The PCPLugs and ExternaPlugs? in
AVC::Unit are not deserialized.

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