root/branches/libffado-2.0/src/libavc/general/avc_plug.cpp

Revision 1408, 79.9 kB (checked in by ppalmers, 15 years ago)

fix up sync source selection through sync plugs

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