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

Revision 864, 74.5 kB (checked in by ppalmers, 15 years ago)

update license to GPLv2 or GPLv3 instead of GPLv2 or any later version. Update copyrights to reflect the new year

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