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

Revision 554, 72.8 kB (checked in by ppalmers, 16 years ago)

Merge echoaudio branch into trunk.

This adds support for the Echo Audiofire devices to FFADO. Possibly also other devices working with the Apple Class Driver will work with this code. It is not fully complete yet, but the main rework is
done.

First of all the IAvDevice class/interface is renamed to FFADODevice, in order to separate the AV/C code from the FFADO API code. A device supported by FFADO implements a FFADODevice.

The BeBoB device has been split up into three groups:
- libavc/* : all code and commands that are specified by AV/C specs. Note that a lot of the code that used to be in BeBoB::AvDevice? now resides in AVC::Unit
- genericavc/* : a FFADODevice that uses AV/C descriptors & commands for discovery and config
- bebob/* : the bebob FFADODevice that inherits from GenericAVC::AvDevice? but that uses BridgeCo? commands for discovery

Everything has been moved as high as possible in the class hierarchy. If necessary, a subclass that uses device specific commands is introduced (e.g. BeBoB::Plug inherits from AVC::Plug and uses the
BridgeCo? extended plug info command to discover it's properties).

There are some other fixes along the way that have been done too.

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