root/branches/echoaudio/src/libavc/general/avc_plug.cpp

Revision 524, 77.2 kB (checked in by ppalmers, 15 years ago)

echo discovery works, audio I/O works, still some issues with midi and channel naming

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