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

Revision 741, 74.2 kB (checked in by ppalmers, 13 years ago)

Fixes #54

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     setDebugLevel(l);
120     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Setting verbose level to %d...\n", 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     debugOutput( DEBUG_LEVEL_VERBOSE, "\tChannel info:\n");
1249     for ( Plug::ClusterInfoVector::const_iterator it = m_clusterInfos.begin();
1250           it != m_clusterInfos.end();
1251           ++it )
1252     {
1253         const Plug::ClusterInfo* clusterInfo = &( *it );
1254
1255         debugOutput(DEBUG_LEVEL_VERBOSE, "         Cluster %s (idx=%2d, type=0x%02X, ch=%2d, format=0x%02X)\n",
1256             clusterInfo->m_name.c_str(), clusterInfo->m_portType, clusterInfo->m_nrOfChannels, clusterInfo->m_streamFormat);
1257         Plug::ChannelInfoVector channelInfos = clusterInfo->m_channelInfos;
1258         for ( Plug::ChannelInfoVector::const_iterator it = channelInfos.begin();
1259               it != channelInfos.end();
1260               ++it )
1261         {
1262             const Plug::ChannelInfo* channelInfo = &( *it );
1263             debugOutput(DEBUG_LEVEL_VERBOSE, "           Channel %s (pos=0x%02X, loc=0x%02X)\n",
1264                 channelInfo->m_name.c_str(), channelInfo->m_streamPosition, channelInfo->m_location);
1265         }
1266     }
1267
1268     flushDebugOutput();
1269 }
1270
1271
1272 Plug*
1273 Plug::getPlugDefinedBySpecificData(
1274     UnitPlugSpecificDataPlugAddress* pUnitPlugAddress,
1275     SubunitPlugSpecificDataPlugAddress* pSubunitPlugAddress,
1276     FunctionBlockPlugSpecificDataPlugAddress* pFunctionBlockPlugAddress )
1277 {
1278     subunit_type_t        subunitType       = 0xff;
1279     subunit_id_t          subunitId         = 0xff;
1280     function_block_type_t functionBlockType = 0xff;
1281     function_block_id_t   functionBlockId   = 0xff;
1282     EPlugAddressType      addressType       = eAPA_Undefined;
1283     EPlugDirection        direction         = eAPD_Unknown;
1284     plug_id_t             plugId            = 0xff;
1285
1286     if ( !pUnitPlugAddress
1287          && !pSubunitPlugAddress
1288          && !pFunctionBlockPlugAddress )
1289     {
1290         debugError( "No correct specific data found\n" );
1291         return 0;
1292     }
1293
1294     if ( pUnitPlugAddress ) {
1295         subunitType = eST_Unit;
1296         switch ( pUnitPlugAddress->m_plugType ) {
1297         case UnitPlugSpecificDataPlugAddress::ePT_PCR:
1298             addressType = eAPA_PCR;
1299             break;
1300         case UnitPlugSpecificDataPlugAddress::ePT_ExternalPlug:
1301             addressType = eAPA_ExternalPlug;
1302             break;
1303         case UnitPlugSpecificDataPlugAddress::ePT_AsynchronousPlug:
1304             addressType = eAPA_AsynchronousPlug;
1305             break;
1306         }
1307         // unit plug have only connections to subunits
1308         if ( getPlugAddressType() == eAPA_SubunitPlug ) {
1309             direction = getDirection();
1310         } else {
1311             debugError( "Function block has connection from/to unknown "
1312                         "plug type\n" );
1313             direction = eAPD_Unknown;
1314         }
1315         plugId = pUnitPlugAddress->m_plugId;
1316
1317         debugOutput( DEBUG_LEVEL_VERBOSE,
1318                      "'(%d) %s': Remote plug is a unit plug "
1319                      "(%s, %s, %d)\n",
1320                      getGlobalId(),
1321                      getName(),
1322                      avPlugAddressTypeToString( addressType ),
1323                      avPlugDirectionToString( direction ),
1324                      plugId );
1325     }
1326
1327     if ( pSubunitPlugAddress ) {
1328         subunitType = pSubunitPlugAddress->m_subunitType;
1329         subunitId = pSubunitPlugAddress->m_subunitId;
1330         addressType = eAPA_SubunitPlug;
1331
1332         if ( getPlugAddressType() == eAPA_FunctionBlockPlug ) {
1333             direction = getDirection();
1334         } else if ( getPlugAddressType() == eAPA_SubunitPlug ) {
1335             direction = toggleDirection( getDirection() );
1336         } else {
1337             // unit
1338             direction = getDirection();
1339         }
1340
1341         plugId = pSubunitPlugAddress->m_plugId;
1342         debugOutput( DEBUG_LEVEL_VERBOSE,
1343                      "'(%d) %s': Remote plug is a subunit plug "
1344                      "(%d, %d, %s, %d)\n",
1345                      getGlobalId(),
1346                      getName(),
1347                      subunitType,
1348                      subunitId,
1349                      avPlugDirectionToString( direction ),
1350                      plugId );
1351     }
1352
1353     if ( pFunctionBlockPlugAddress ) {
1354         subunitType = pFunctionBlockPlugAddress->m_subunitType;
1355         subunitId = pFunctionBlockPlugAddress->m_subunitId;
1356         functionBlockType = pFunctionBlockPlugAddress->m_functionBlockType;
1357         functionBlockId = pFunctionBlockPlugAddress->m_functionBlockId;
1358         addressType = eAPA_FunctionBlockPlug;
1359
1360         if ( getPlugAddressType() == eAPA_FunctionBlockPlug ) {
1361             direction = toggleDirection( getDirection() );
1362         } else if ( getPlugAddressType() == eAPA_SubunitPlug ){
1363             direction = getDirection();
1364         } else {
1365             debugError( "Function block has connection from/to unknown "
1366                         "plug type\n" );
1367             direction = eAPD_Unknown;
1368         }
1369
1370         plugId = pFunctionBlockPlugAddress->m_plugId;
1371
1372         debugOutput( DEBUG_LEVEL_VERBOSE,
1373                      "'(%d) %s': Remote plug is a functionblock plug "
1374                      "(%d, %d, %d, %d, %s, %d)\n",
1375                      getGlobalId(),
1376                      getName(),
1377                      subunitType,
1378                      subunitId,
1379                      functionBlockType,
1380                      functionBlockId,
1381                      avPlugDirectionToString( direction ),
1382                      plugId );
1383     }
1384
1385     ESubunitType enumSubunitType =
1386         static_cast<ESubunitType>( subunitType );
1387
1388     return m_unit->getPlugManager().getPlug(
1389         enumSubunitType,
1390         subunitId,
1391         functionBlockType,
1392         functionBlockId,
1393         addressType,
1394         direction,
1395         plugId );
1396 }
1397
1398 Plug::EPlugDirection
1399 Plug::toggleDirection( EPlugDirection direction ) const
1400 {
1401     EPlugDirection newDirection;
1402     switch ( direction ) {
1403     case eAPD_Output:
1404         newDirection = eAPD_Input;
1405         break;
1406     case eAPD_Input:
1407         newDirection = eAPD_Output;
1408         break;
1409     default:
1410         newDirection = direction;
1411     }
1412
1413     return newDirection;
1414 }
1415
1416 bool
1417 Plug::serializeChannelInfos( Glib::ustring basePath,
1418                              Util::IOSerialize& ser,
1419                              const ClusterInfo& clusterInfo ) const
1420 {
1421     bool result = true;
1422     int i = 0;
1423     for ( ChannelInfoVector::const_iterator it = clusterInfo.m_channelInfos.begin();
1424           it != clusterInfo.m_channelInfos.end();
1425           ++it )
1426     {
1427         const ChannelInfo& info = *it;
1428         std::ostringstream strstrm;
1429         strstrm << basePath << i;
1430
1431         result &= ser.write( strstrm.str() + "/m_streamPosition", info.m_streamPosition );
1432         result &= ser.write( strstrm.str() + "/m_location", info.m_location );
1433         result &= ser.write( strstrm.str() + "/m_name", info.m_name );
1434         i++;
1435     }
1436
1437     return result;
1438 }
1439
1440 bool
1441 Plug::deserializeChannelInfos( Glib::ustring basePath,
1442                                Util::IODeserialize& deser,
1443                                ClusterInfo& clusterInfo )
1444 {
1445     int i = 0;
1446     bool bFinished = false;
1447     bool result = true;
1448     do {
1449         std::ostringstream strstrm;
1450         strstrm << basePath << i;
1451
1452         // check for one element to exist. when one exist the other elements
1453         // must also be there. otherwise just return (last) result.
1454         if ( deser.isExisting( strstrm.str() + "/m_streamPosition" ) ) {
1455             ChannelInfo info;
1456
1457             result &= deser.read( strstrm.str() + "/m_streamPosition", info.m_streamPosition );
1458             result &= deser.read( strstrm.str() + "/m_location", info.m_location );
1459             result &= deser.read( strstrm.str() + "/m_name", info.m_name );
1460
1461             if ( result ) {
1462                 clusterInfo.m_channelInfos.push_back( info );
1463                 i++;
1464             } else {
1465                 bFinished = true;
1466             }
1467         } else {
1468             bFinished = true;
1469         }
1470     } while ( !bFinished );
1471
1472     return result;
1473 }
1474
1475
1476 bool
1477 Plug::serializeClusterInfos( Glib::ustring basePath,
1478                              Util::IOSerialize& ser ) const
1479 {
1480     bool result = true;
1481     int i = 0;
1482     for ( ClusterInfoVector::const_iterator it = m_clusterInfos.begin();
1483           it != m_clusterInfos.end();
1484           ++it )
1485     {
1486         const ClusterInfo& info = *it;
1487         std::ostringstream strstrm;
1488         strstrm << basePath << i;
1489
1490         result &= ser.write( strstrm.str() + "/m_index", info.m_index );
1491         result &= ser.write( strstrm.str() + "/m_portType", info.m_portType );
1492         result &= ser.write( strstrm.str() + "/m_name", info.m_name );
1493         result &= ser.write( strstrm.str() + "/m_nrOfChannels", info.m_nrOfChannels );
1494         result &= serializeChannelInfos( strstrm.str() + "/m_channelInfo", ser, info );
1495         result &= ser.write( strstrm.str() + "/m_streamFormat", info.m_streamFormat );
1496         i++;
1497     }
1498
1499     return result;
1500 }
1501
1502 bool
1503 Plug::deserializeClusterInfos( Glib::ustring basePath,
1504                                Util::IODeserialize& deser )
1505 {
1506     int i = 0;
1507     bool bFinished = false;
1508     bool result = true;
1509     do {
1510         std::ostringstream strstrm;
1511         strstrm << basePath << i;
1512
1513         // check for one element to exist. when one exist the other elements
1514         // must also be there. otherwise just return (last) result.
1515         if ( deser.isExisting( strstrm.str() + "/m_index" ) ) {
1516             ClusterInfo info;
1517
1518             result &= deser.read( strstrm.str() + "/m_index", info.m_index );
1519             result &= deser.read( strstrm.str() + "/m_portType", info.m_portType );
1520             result &= deser.read( strstrm.str() + "/m_name", info.m_name );
1521             result &= deser.read( strstrm.str() + "/m_nrOfChannels", info.m_nrOfChannels );
1522             result &= deserializeChannelInfos( strstrm.str() + "/m_channelInfo", deser, info );
1523             result &= deser.read( strstrm.str() + "/m_streamFormat", info.m_streamFormat );
1524
1525             if ( result ) {
1526                 m_clusterInfos.push_back( info );
1527                 i++;
1528             } else {
1529                 bFinished = true;
1530             }
1531         } else {
1532             bFinished = true;
1533         }
1534     } while ( !bFinished );
1535
1536     return result;
1537 }
1538
1539
1540 bool
1541 Plug::serializeFormatInfos( Glib::ustring basePath,
1542                             Util::IOSerialize& ser ) const
1543 {
1544     bool result = true;
1545     int i = 0;
1546     for ( FormatInfoVector::const_iterator it = m_formatInfos.begin();
1547           it != m_formatInfos.end();
1548           ++it )
1549     {
1550         const FormatInfo& info = *it;
1551         std::ostringstream strstrm;
1552         strstrm << basePath << i;
1553
1554         result &= ser.write( strstrm.str() + "/m_samplingFrequency", info.m_samplingFrequency );
1555         result &= ser.write( strstrm.str() + "/m_isSyncStream", info.m_isSyncStream );
1556         result &= ser.write( strstrm.str() + "/m_audioChannels", info.m_audioChannels );
1557         result &= ser.write( strstrm.str() + "/m_midiChannels", info.m_midiChannels );
1558         result &= ser.write( strstrm.str() + "/m_index", info.m_index );
1559         i++;
1560     }
1561     return result;
1562 }
1563
1564 bool
1565 Plug::deserializeFormatInfos( Glib::ustring basePath,
1566                               Util::IODeserialize& deser )
1567 {
1568     int i = 0;
1569     bool bFinished = false;
1570     bool result = true;
1571     do {
1572         std::ostringstream strstrm;
1573         strstrm << basePath << i;
1574
1575         // check for one element to exist. when one exist the other elements
1576         // must also be there. otherwise just return (last) result.
1577         if ( deser.isExisting( strstrm.str() + "/m_samplingFrequency" ) ) {
1578             FormatInfo info;
1579
1580             result &= deser.read( strstrm.str() + "/m_samplingFrequency", info.m_samplingFrequency );
1581             result &= deser.read( strstrm.str() + "/m_isSyncStream", info.m_isSyncStream );
1582             result &= deser.read( strstrm.str() + "/m_audioChannels", info.m_audioChannels );
1583             result &= deser.read( strstrm.str() + "/m_midiChannels", info.m_midiChannels );
1584             result &= deser.read( strstrm.str() + "/m_index", info.m_index );
1585
1586             if ( result ) {
1587                 m_formatInfos.push_back( info );
1588                 i++;
1589             } else {
1590                 bFinished = true;
1591             }
1592         } else {
1593             bFinished = true;
1594         }
1595     } while ( !bFinished );
1596
1597     return result;
1598 }
1599
1600 bool
1601 Plug::serialize( Glib::ustring basePath, Util::IOSerialize& ser ) const
1602 {
1603     bool result=true;
1604     result &= ser.write( basePath + "m_subunitType", getSubunitType());
1605     result &= ser.write( basePath + "m_subunitId", getSubunitId());
1606     result &= ser.write( basePath + "m_functionBlockType", m_functionBlockType);
1607     result &= ser.write( basePath + "m_functionBlockId", m_functionBlockId);
1608     result &= ser.write( basePath + "m_addressType", m_addressType );
1609     result &= ser.write( basePath + "m_direction", m_direction);
1610     result &= ser.write( basePath + "m_id", m_id);
1611     result &= ser.write( basePath + "m_infoPlugType", m_infoPlugType);
1612     result &= ser.write( basePath + "m_nrOfChannels", m_nrOfChannels);
1613     result &= ser.write( basePath + "m_name", m_name);
1614     result &= serializeClusterInfos( basePath + "m_clusterInfos", ser );
1615     result &= ser.write( basePath + "m_samplingFrequency", m_samplingFrequency);
1616     result &= serializeFormatInfos( basePath + "m_formatInfo", ser );
1617     result &= serializePlugVector( basePath + "m_inputConnections", ser, m_inputConnections );
1618     result &= serializePlugVector( basePath + "m_outputConnections", ser, m_outputConnections );
1619     result &= ser.write( basePath + "m_globalId", m_globalId);
1620     result &= ser.write( basePath + "m_globalIdCounter", m_globalIdCounter );
1621
1622     return result;
1623 }
1624
1625 Plug*
1626 Plug::deserialize( Glib::ustring basePath,
1627                    Util::IODeserialize& deser,
1628                    Unit& unit,
1629                    PlugManager& plugManager )
1630 {
1631     #warning FIXME: The derived class should be creating these
1632     // FIXME: The derived class should be creating these, such that discover() can become pure virtual
1633
1634     if ( !deser.isExisting( basePath + "m_subunitType" ) ) {
1635         return 0;
1636     }
1637     Plug* pPlug = new Plug;
1638     if ( !pPlug ) {
1639         return 0;
1640     }
1641
1642     pPlug->m_unit = &unit;
1643
1644     bool result=true;
1645
1646     result  = deser.read( basePath + "m_subunitType", pPlug->m_subunitType );
1647     result &= deser.read( basePath + "m_subunitId", pPlug->m_subunitId );
1648     result &= deser.read( basePath + "m_functionBlockType", pPlug->m_functionBlockType );
1649     result &= deser.read( basePath + "m_functionBlockId", pPlug->m_functionBlockId );
1650     result &= deser.read( basePath + "m_addressType", pPlug->m_addressType );
1651     result &= deser.read( basePath + "m_direction", pPlug->m_direction );
1652     result &= deser.read( basePath + "m_id", pPlug->m_id );
1653     result &= deser.read( basePath + "m_infoPlugType", pPlug->m_infoPlugType );
1654     result &= deser.read( basePath + "m_nrOfChannels", pPlug->m_nrOfChannels );
1655     result &= deser.read( basePath + "m_name", pPlug->m_name );
1656     result &= pPlug->deserializeClusterInfos( basePath + "m_clusterInfos", deser );
1657     result &= deser.read( basePath + "m_samplingFrequency", pPlug->m_samplingFrequency );
1658     result &= pPlug->deserializeFormatInfos( basePath + "m_formatInfos", deser );
1659     // input and output connections can't be processed here because not all plugs might
1660     // deserialized at this point. so we do that in deserializeUpdate.
1661     result &= deser.read( basePath + "m_globalId", pPlug->m_globalId );
1662     result &= deser.read( basePath + "m_globalIdCounter", pPlug->m_globalIdCounter );
1663
1664     if ( !result ) {
1665         delete pPlug;
1666         return 0;
1667     }
1668
1669     return pPlug;
1670 }
1671
1672 bool
1673 Plug::deserializeUpdate( Glib::ustring basePath,
1674                          Util::IODeserialize& deser )
1675 {
1676     bool result;
1677
1678     result  = deserializePlugVector( basePath + "m_inputConnections", deser,
1679                                      m_unit->getPlugManager(), m_inputConnections );
1680     result &= deserializePlugVector( basePath + "m_outputConnections", deser,
1681                                      m_unit->getPlugManager(), m_outputConnections );
1682
1683     return result;
1684 }
1685
1686 bool
1687 Plug::deserializeUpdateSubunit()
1688 {
1689     m_subunit = m_unit->getSubunit( m_subunitType, m_subunitId );
1690     return true;
1691 }
1692
1693 /////////////////////////////////////////
1694 /////////////////////////////////////////
1695
1696 const char* avPlugAddressTypeStrings[] =
1697 {
1698     "PCR",
1699     "external",
1700     "asynchronous",
1701     "subunit",
1702     "functionblock",
1703     "undefined",
1704 };
1705
1706 const char* avPlugAddressTypeToString( Plug::EPlugAddressType type )
1707 {
1708     if ( type > ( int )( sizeof( avPlugAddressTypeStrings )
1709                          / sizeof( avPlugAddressTypeStrings[0] ) ) )
1710     {
1711         type = Plug::eAPA_Undefined;
1712     }
1713     return avPlugAddressTypeStrings[type];
1714 }
1715
1716 const char* avPlugTypeStrings[] =
1717 {
1718     "IsoStream",
1719     "AsyncStream",
1720     "MIDI",
1721     "Sync",
1722     "Analog",
1723     "Digital",
1724     "Unknown",
1725 };
1726
1727 const char* avPlugTypeToString( Plug::EPlugType type )
1728 {
1729     if ( type > ( int )( sizeof( avPlugTypeStrings )
1730                          / sizeof( avPlugTypeStrings[0] ) ) )
1731     {
1732         type = Plug::eAPT_Unknown;
1733     }
1734     return avPlugTypeStrings[type];
1735 }
1736
1737 const char* avPlugDirectionStrings[] =
1738 {
1739     "Input",
1740     "Output",
1741     "Unknown",
1742 };
1743
1744 const char* avPlugDirectionToString( Plug::EPlugDirection type )
1745 {
1746     if ( type > ( int )( sizeof( avPlugDirectionStrings )
1747                          / sizeof( avPlugDirectionStrings[0] ) ) )
1748     {
1749         type = Plug::eAPD_Unknown;
1750     }
1751     return avPlugDirectionStrings[type];
1752 }
1753
1754 /////////////////////////////////////
1755
1756
1757 PlugManager::PlugManager(  )
1758 {
1759
1760 }
1761
1762 PlugManager::PlugManager( const PlugManager& rhs )
1763 {
1764     setDebugLevel( rhs.getDebugLevel() );
1765 }
1766
1767 PlugManager::~PlugManager()
1768 {
1769 }
1770
1771 void
1772 PlugManager::setVerboseLevel( int l )
1773 {
1774     setDebugLevel(l);
1775     for ( PlugVector::iterator it = m_plugs.begin();
1776           it !=  m_plugs.end();
1777           ++it )
1778     {
1779         (*it)->setVerboseLevel(l);
1780     }
1781     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
1782 }
1783
1784 bool
1785 PlugManager::addPlug( Plug& plug )
1786 {
1787     m_plugs.push_back( &plug );
1788     // inherit debug level
1789     plug.setVerboseLevel(getDebugLevel());
1790     return true;
1791 }
1792
1793 bool
1794 PlugManager::remPlug( Plug& plug )
1795 {
1796     for ( PlugVector::iterator it = m_plugs.begin();
1797           it !=  m_plugs.end();
1798           ++it )
1799     {
1800         Plug* plugIt = *it;
1801         if ( plugIt == &plug ) {
1802             m_plugs.erase( it );
1803             return true;
1804         }
1805     }
1806     return false;
1807 }
1808
1809 // helper function
1810 static void addConnection( PlugConnectionVector& connections,
1811                            Plug& srcPlug,
1812                            Plug& destPlug )
1813 {
1814     for ( PlugConnectionVector::iterator it = connections.begin();
1815           it != connections.end();
1816           ++it )
1817     {
1818         PlugConnection* con = *it;
1819         if ( ( &( con->getSrcPlug() ) == &srcPlug )
1820              && ( &( con->getDestPlug() ) == &destPlug ) )
1821         {
1822             return;
1823         }
1824     }
1825     connections.push_back( new PlugConnection( srcPlug, destPlug ) );
1826 }
1827
1828 bool
1829 PlugManager::tidyPlugConnections(PlugConnectionVector& connections)
1830 {
1831     for ( PlugVector::const_iterator it = m_plugs.begin();
1832           it !=  m_plugs.end();
1833           ++it )
1834     {
1835         Plug* plug = *it;
1836         for ( PlugVector::const_iterator it =
1837                   plug->getInputConnections().begin();
1838             it != plug->getInputConnections().end();
1839             ++it )
1840         {
1841             addConnection( connections, *( *it ), *plug );
1842         }
1843         plug->getInputConnections().clear();
1844
1845         for ( PlugVector::const_iterator it =
1846                   plug->getOutputConnections().begin();
1847             it != plug->getOutputConnections().end();
1848             ++it )
1849         {
1850             addConnection( connections, *plug, *( *it ) );
1851         }
1852         plug->getOutputConnections().clear();
1853     }
1854
1855     for ( PlugConnectionVector::iterator it = connections.begin();
1856           it != connections.end();
1857           ++it )
1858     {
1859         PlugConnection * con = *it;
1860         con->getSrcPlug().getOutputConnections().push_back(&( con->getDestPlug() ));
1861         con->getDestPlug().getInputConnections().push_back(&( con->getSrcPlug() ));
1862
1863     }
1864
1865     return true;
1866 }
1867
1868 static void addConnectionOwner( PlugConnectionOwnerVector& connections,
1869                            Plug& srcPlug,
1870                            Plug& destPlug )
1871 {
1872
1873     for ( PlugConnectionOwnerVector::iterator it = connections.begin();
1874           it != connections.end();
1875           ++it )
1876     {
1877         PlugConnection& con = *it;
1878         if ( ( &( con.getSrcPlug() ) == &srcPlug )
1879              && ( &( con.getDestPlug() ) == &destPlug ) )
1880         {
1881             return;
1882         }
1883     }
1884     connections.push_back( PlugConnection( srcPlug, destPlug ) );
1885 }
1886
1887
1888 void
1889 PlugManager::showPlugs() const
1890 {
1891     if(getDebugLevel() < DEBUG_LEVEL_INFO) return;
1892
1893     // \todo The information provided here could be better arranged. For a start it is ok, but
1894     // there is room for improvement. Something for a lazy sunday afternoon (tip: maybe drink some
1895     // beer to get into the mood)
1896
1897     printf( "\nSummary\n" );
1898     printf( "-------\n\n" );
1899     printf( "Nr | AddressType     | Direction | SubUnitType | SubUnitId | FunctionBlockType | FunctionBlockId | Id   | Type         |Name\n" );
1900     printf( "---+-----------------+-----------+-------------+-----------+-------------------+-----------------+------+--------------+------\n" );
1901
1902     for ( PlugVector::const_iterator it = m_plugs.begin();
1903           it !=  m_plugs.end();
1904           ++it )
1905     {
1906         Plug* plug = *it;
1907
1908         printf( "%2d | %15s | %9s | %11s |      0x%02x |              0x%02x |            0x%02x | 0x%02x | %12s | %s\n",
1909                 plug->getGlobalId(),
1910                 avPlugAddressTypeToString( plug->getPlugAddressType() ),
1911                 avPlugDirectionToString( plug->getDirection() ),
1912                 subunitTypeToString( plug->getSubunitType() ),
1913                 plug->getSubunitId(),
1914                 plug->getFunctionBlockType(),
1915                 plug->getFunctionBlockId(),
1916                 plug->getPlugId(),
1917                 avPlugTypeToString( plug->getPlugType() ),
1918                 plug->getName() );
1919     }
1920
1921     printf( "\nConnections\n" );
1922     printf( "-----------\n" );
1923
1924     PlugConnectionOwnerVector connections;
1925
1926     for ( PlugVector::const_iterator it = m_plugs.begin();
1927           it !=  m_plugs.end();
1928           ++it )
1929     {
1930         Plug* plug = *it;
1931         for ( PlugVector::const_iterator it =
1932                   plug->getInputConnections().begin();
1933             it != plug->getInputConnections().end();
1934             ++it )
1935         {
1936             addConnectionOwner( connections, *( *it ), *plug );
1937         }
1938         for ( PlugVector::const_iterator it =
1939                   plug->getOutputConnections().begin();
1940             it != plug->getOutputConnections().end();
1941             ++it )
1942         {
1943             addConnectionOwner( connections, *plug, *( *it ) );
1944         }
1945     }
1946
1947     printf( "digraph avcconnections {\n" );
1948     for ( PlugConnectionOwnerVector::iterator it = connections.begin();
1949           it != connections.end();
1950           ++it )
1951     {
1952         PlugConnection& con = *it;
1953         printf( "\t\"(%d) %s\" -> \"(%d) %s\"\n",
1954                 con.getSrcPlug().getGlobalId(),
1955                 con.getSrcPlug().getName(),
1956                 con.getDestPlug().getGlobalId(),
1957                 con.getDestPlug().getName() );
1958     }
1959     for ( PlugVector::const_iterator it = m_plugs.begin();
1960           it != m_plugs.end();
1961           ++it )
1962     {
1963         Plug* plug = *it;
1964         if ( plug->getFunctionBlockType() != 0xff ) {
1965             std::ostringstream strstrm;
1966             switch(plug->getFunctionBlockType()) {
1967                 case 0x80:
1968                     strstrm << "Selector FB";
1969                     break;
1970                 case 0x81:
1971                     strstrm << "Feature FB";
1972                     break;
1973                 case 0x82:
1974                     strstrm << "Processing FB";
1975                     break;
1976                 case 0x83:
1977                     strstrm << "CODEC FB";
1978                     break;
1979                 default:
1980                     strstrm << plug->getFunctionBlockType();
1981             }
1982
1983             if ( plug->getPlugDirection() == Plug::eAPD_Input ) {
1984                 printf( "\t\"(%d) %s\" -> \"(%s, ID %d)\"\n",
1985                         plug->getGlobalId(),
1986                         plug->getName(),
1987                         strstrm.str().c_str(),
1988                         plug->getFunctionBlockId() );
1989             } else {
1990                 printf( "\t\"(%s, ID %d)\" -> \t\"(%d) %s\"\n",
1991                         strstrm.str().c_str(),
1992                         plug->getFunctionBlockId(),
1993                         plug->getGlobalId(),
1994                         plug->getName() );
1995             }
1996         }
1997     }
1998
1999     const char* colorStrings[] = {
2000         "coral",
2001         "slateblue",
2002         "white",
2003         "green",
2004         "yellow",
2005         "grey",
2006     };
2007
2008     for ( PlugVector::const_iterator it = m_plugs.begin();
2009           it !=  m_plugs.end();
2010           ++it )
2011     {
2012         Plug* plug = *it;
2013         printf( "\t\"(%d) %s\" [color=%s,style=filled];\n",
2014                 plug->getGlobalId(), plug->getName(),
2015                 colorStrings[plug->getPlugAddressType() ] );
2016     }
2017
2018     printf("}\n" );
2019     printf( "Use \"dot -Tps FILENAME.dot -o FILENAME.ps\" "
2020             "to generate graph\n");
2021
2022     debugOutput( DEBUG_LEVEL_VERBOSE, "Plug details\n" );
2023     debugOutput( DEBUG_LEVEL_VERBOSE, "------------\n" );
2024     for ( PlugVector::const_iterator it = m_plugs.begin();
2025           it !=  m_plugs.end();
2026           ++it )
2027     {
2028         Plug* plug = *it;
2029         debugOutput( DEBUG_LEVEL_VERBOSE, "Plug %d:\n", plug->getGlobalId() );
2030         plug->showPlug();
2031
2032     }
2033 }
2034
2035 Plug*
2036 PlugManager::getPlug( ESubunitType subunitType,
2037                       subunit_id_t subunitId,
2038                       function_block_type_t functionBlockType,
2039                       function_block_id_t functionBlockId,
2040                       Plug::EPlugAddressType plugAddressType,
2041                       Plug::EPlugDirection plugDirection,
2042                       plug_id_t plugId ) const
2043 {
2044     debugOutput( DEBUG_LEVEL_VERBOSE, "SBT, SBID, FBT, FBID, AT, PD, ID = "
2045                  "(0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x)\n",
2046                  subunitType,
2047                  subunitId,
2048                  functionBlockType,
2049                  functionBlockId,
2050                  plugAddressType,
2051                  plugDirection,
2052                  plugId );
2053
2054     for ( PlugVector::const_iterator it = m_plugs.begin();
2055           it !=  m_plugs.end();
2056           ++it )
2057     {
2058         Plug* plug = *it;
2059
2060         if (    ( subunitType == plug->getSubunitType() )
2061              && ( subunitId == plug->getSubunitId() )
2062              && ( functionBlockType == plug->getFunctionBlockType() )
2063              && ( functionBlockId == plug->getFunctionBlockId() )
2064              && ( plugAddressType == plug->getPlugAddressType() )
2065              && ( plugDirection == plug->getPlugDirection() )
2066              && ( plugId == plug->getPlugId() ) )
2067         {
2068             return plug;
2069         }
2070     }
2071
2072     return 0;
2073 }
2074
2075 Plug*
2076 PlugManager::getPlug( int iGlobalId ) const
2077 {
2078     for ( PlugVector::const_iterator it = m_plugs.begin();
2079           it !=  m_plugs.end();
2080           ++it )
2081     {
2082         Plug* pPlug = *it;
2083         if ( pPlug->getGlobalId() == iGlobalId ) {
2084             return pPlug;
2085         }
2086     }
2087
2088     return 0;
2089 }
2090
2091 PlugVector
2092 PlugManager::getPlugsByType( ESubunitType subunitType,
2093                              subunit_id_t subunitId,
2094                              function_block_type_t functionBlockType,
2095                              function_block_id_t functionBlockId,
2096                              Plug::EPlugAddressType plugAddressType,
2097                              Plug::EPlugDirection plugDirection,
2098                              Plug::EPlugType type) const
2099 {
2100     debugOutput( DEBUG_LEVEL_VERBOSE, "SBT, SBID, FBT, FBID, AT, PD, T = "
2101                  "(0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x)\n",
2102                  subunitType,
2103                  subunitId,
2104                  functionBlockType,
2105                  functionBlockId,
2106                  plugAddressType,
2107                  plugDirection,
2108                  type );
2109
2110     PlugVector plugVector;
2111     for ( PlugVector::const_iterator it = m_plugs.begin();
2112           it !=  m_plugs.end();
2113           ++it )
2114     {
2115         Plug* pPlug = *it;
2116
2117         if (    ( subunitType == pPlug->getSubunitType() )
2118              && ( subunitId == pPlug->getSubunitId() )
2119              && ( functionBlockType == pPlug->getFunctionBlockType() )
2120              && ( functionBlockId == pPlug->getFunctionBlockId() )
2121              && ( plugAddressType == pPlug->getPlugAddressType() )
2122              && ( plugDirection == pPlug->getPlugDirection() )
2123              && ( type == pPlug->getPlugType() ) )
2124         {
2125             plugVector.push_back( pPlug );
2126         }
2127     }
2128
2129     return plugVector;
2130 }
2131
2132 bool
2133 PlugManager::serialize( Glib::ustring basePath, Util::IOSerialize& ser ) const
2134 {
2135     bool result = true;
2136     int i = 0;
2137     for ( PlugVector::const_iterator it = m_plugs.begin();
2138           it !=  m_plugs.end();
2139           ++it )
2140     {
2141         Plug* pPlug = *it;
2142         std::ostringstream strstrm;
2143         strstrm << basePath << i;
2144         result &= pPlug->serialize( strstrm.str() + "/", ser );
2145         i++;
2146     }
2147
2148     return result;
2149 }
2150
2151 PlugManager*
2152 PlugManager::deserialize( Glib::ustring basePath,
2153                           Util::IODeserialize& deser,
2154                           Unit& unit )
2155
2156 {
2157     PlugManager* pMgr = new PlugManager;
2158
2159     if ( !pMgr ) {
2160         return 0;
2161     }
2162
2163     int i = 0;
2164     bool bFinished = false;
2165     do {
2166         std::ostringstream strstrm;
2167         strstrm << basePath << i;
2168         // unit still holds a null pointer for the plug manager
2169         // therefore we have to *this as additional argument
2170         Plug* pPlug = Plug::deserialize( strstrm.str() + "/",
2171                                          deser,
2172                                          unit,
2173                                          *pMgr );
2174         if ( pPlug ) {
2175             pMgr->m_plugs.push_back( pPlug );
2176             i++;
2177         } else {
2178             bFinished = true;
2179         }
2180     } while ( !bFinished );
2181
2182     return pMgr;
2183 }
2184
2185 bool
2186 PlugManager::deserializeUpdate()
2187 {
2188     bool result = true;
2189
2190     for ( PlugVector::const_iterator it = m_plugs.begin();
2191           it !=  m_plugs.end();
2192           ++it )
2193     {
2194         Plug* pPlug = *it;
2195
2196         result &= pPlug->deserializeUpdateSubunit();
2197     }
2198
2199     return result;
2200 }
2201
2202 ////////////////////////////////////
2203
2204 PlugConnection::PlugConnection( Plug& srcPlug, Plug& destPlug )
2205     : m_srcPlug( &srcPlug )
2206     , m_destPlug( &destPlug )
2207 {
2208 }
2209
2210 PlugConnection::PlugConnection()
2211     : m_srcPlug( 0 )
2212     , m_destPlug( 0 )
2213 {
2214 }
2215
2216 bool
2217 PlugConnection::serialize( Glib::ustring basePath, Util::IOSerialize& ser ) const
2218 {
2219     bool result;
2220     result  = ser.write( basePath + "m_srcPlug", m_srcPlug->getGlobalId() );
2221     result &= ser.write( basePath + "m_destPlug", m_destPlug->getGlobalId() );
2222     return result;
2223 }
2224
2225 PlugConnection*
2226 PlugConnection::deserialize( Glib::ustring basePath,
2227                                Util::IODeserialize& deser,
2228                                Unit& unit )
2229 {
2230     if ( !deser.isExisting( basePath + "m_srcPlug" ) ) {
2231         return 0;
2232     }
2233     PlugConnection* pConnection = new PlugConnection;
2234     if ( !pConnection ) {
2235         return 0;
2236     }
2237
2238     bool result;
2239     int iSrcPlugId;
2240     int iDestPlugId;
2241     result  = deser.read( basePath + "m_srcPlug", iSrcPlugId );
2242     result &= deser.read( basePath + "m_destPlug",  iDestPlugId );
2243
2244     if ( !result ) {
2245         delete pConnection;
2246         return 0;
2247     }
2248
2249     pConnection->m_srcPlug  = unit.getPlugManager().getPlug( iSrcPlugId );
2250     pConnection->m_destPlug = unit.getPlugManager().getPlug( iDestPlugId );
2251
2252     if ( !pConnection->m_srcPlug || !pConnection->m_destPlug ) {
2253         delete pConnection;
2254         return 0;
2255     }
2256
2257     return pConnection;
2258 }
2259
2260 ExtendedStreamFormatCmd
2261 Plug::setPlugAddrToStreamFormatCmd(
2262     ExtendedStreamFormatCmd::ESubFunction subFunction)
2263 {
2264     ExtendedStreamFormatCmd extStreamFormatInfoCmd(
2265         m_unit->get1394Service(),
2266         subFunction );
2267     switch( getSubunitType() ) {
2268     case eST_Unit:
2269     {
2270             UnitPlugAddress::EPlugType ePlugType =
2271                 UnitPlugAddress::ePT_Unknown;
2272             switch ( m_addressType ) {
2273                 case eAPA_PCR:
2274                     ePlugType = UnitPlugAddress::ePT_PCR;
2275                     break;
2276                 case eAPA_ExternalPlug:
2277                     ePlugType = UnitPlugAddress::ePT_ExternalPlug;
2278                     break;
2279                 case eAPA_AsynchronousPlug:
2280                     ePlugType = UnitPlugAddress::ePT_AsynchronousPlug;
2281                     break;
2282                 default:
2283                     ePlugType = UnitPlugAddress::ePT_Unknown;
2284             }
2285         UnitPlugAddress unitPlugAddress( ePlugType,
2286                                          m_id );
2287         extStreamFormatInfoCmd.setPlugAddress(
2288             PlugAddress( convertPlugDirection( getPlugDirection() ),
2289                          PlugAddress::ePAM_Unit,
2290                          unitPlugAddress ) );
2291         }
2292         break;
2293     case eST_Music:
2294     case eST_Audio:
2295     {
2296         switch( m_addressType ) {
2297         case eAPA_SubunitPlug:
2298         {
2299             SubunitPlugAddress subunitPlugAddress( m_id );
2300             extStreamFormatInfoCmd.setPlugAddress(
2301                 PlugAddress( convertPlugDirection( getPlugDirection() ),
2302                              PlugAddress::ePAM_Subunit,
2303                              subunitPlugAddress ) );
2304         }
2305         break;
2306         case eAPA_FunctionBlockPlug:
2307         {
2308             FunctionBlockPlugAddress functionBlockPlugAddress(
2309                 m_functionBlockType,
2310                 m_functionBlockId,
2311                 m_id );
2312             extStreamFormatInfoCmd.setPlugAddress(
2313                 PlugAddress( convertPlugDirection( getPlugDirection() ),
2314                              PlugAddress::ePAM_FunctionBlock,
2315                              functionBlockPlugAddress ) );
2316         }
2317         break;
2318         default:
2319             extStreamFormatInfoCmd.setPlugAddress(PlugAddress());
2320         }
2321     }
2322     break;
2323     default:
2324         debugError( "Unknown subunit type\n" );
2325     }
2326
2327     extStreamFormatInfoCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
2328     extStreamFormatInfoCmd.setCommandType( AVCCommand::eCT_Status );
2329     extStreamFormatInfoCmd.setSubunitId( getSubunitId() );
2330     extStreamFormatInfoCmd.setSubunitType( getSubunitType() );
2331
2332     return extStreamFormatInfoCmd;
2333 }
2334
2335 bool
2336 serializePlugVector( Glib::ustring basePath,
2337                      Util::IOSerialize& ser,
2338                      const PlugVector& vec)
2339 {
2340     bool result = true;
2341     int i = 0;
2342     for ( PlugVector::const_iterator it = vec.begin();
2343           it != vec.end();
2344           ++it )
2345     {
2346         const Plug* pPlug = *it;
2347         std::ostringstream strstrm;
2348         strstrm << basePath << i;
2349
2350         result &= ser.write( strstrm.str() + "/global_id", pPlug->getGlobalId() );
2351         i++;
2352     }
2353     return result;
2354 }
2355
2356 bool
2357 deserializePlugVector( Glib::ustring basePath,
2358                        Util::IODeserialize& deser,
2359                        const PlugManager& plugManager,
2360                        PlugVector& vec )
2361 {
2362     int i = 0;
2363     bool bFinished = false;
2364     bool result = true;
2365     do {
2366         std::ostringstream strstrm;
2367         strstrm << basePath << i;
2368
2369         // check for one element to exist. when one exist the other elements
2370         // must also be there. otherwise just return (last) result.
2371         if ( deser.isExisting( strstrm.str() + "/global_id" ) ) {
2372             unsigned int iPlugId;
2373             result &= deser.read( strstrm.str() + "/global_id", iPlugId );
2374
2375             if ( result ) {
2376                 Plug* pPlug = plugManager.getPlug( iPlugId );
2377                 if ( pPlug ) {
2378                     vec.push_back( pPlug );
2379                 } else {
2380                     result = false;
2381                     bFinished = true;
2382                 }
2383                 i++;
2384             } else {
2385                 bFinished = true;
2386             }
2387         } else {
2388             bFinished = true;
2389         }
2390     } while ( !bFinished );
2391
2392     return result;
2393 }
2394
2395 }
Note: See TracBrowser for help on using the browser.