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

Revision 736, 73.0 kB (checked in by ppalmers, 16 years ago)

fix some stuff that was not merged correctly

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