root/trunk/libffado/src/bebob/bebob_avdevice_subunit.cpp

Revision 1154, 14.2 kB (checked in by ppalmers, 14 years ago)

add expat based parsing of the device cache. add compile-time selection between libxml++ and expat. will allow to get rid of the libxml++ dependency on the long run. scons SERIALIZE_USE_EXPAT=0Only compile testedscons SERIALIZE_USE_EXPAT=0

Line 
1 /*
2  * Copyright (C) 2005-2008 by Daniel Wagner
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program 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
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "bebob/bebob_functionblock.h"
25 #include "bebob/bebob_avdevice_subunit.h"
26 #include "bebob/bebob_avdevice.h"
27 #include "bebob/bebob_avplug.h"
28 #include "libieee1394/configrom.h"
29
30 #include "libavc/general/avc_plug_info.h"
31 #include "libavc/streamformat/avc_extended_stream_format.h"
32 #include "libutil/cmd_serialize.h"
33
34 #include <sstream>
35
36 using namespace AVC;
37
38 //////////////////////////
39
40 BeBoB::SubunitAudio::SubunitAudio( AVC::Unit& avDevice,
41                                    subunit_t id )
42     : AVC::SubunitAudio( avDevice, id )
43 {
44 }
45
46 BeBoB::SubunitAudio::SubunitAudio()
47     : AVC::SubunitAudio()
48 {
49 }
50
51 BeBoB::SubunitAudio::~SubunitAudio()
52 {
53     for ( FunctionBlockVector::iterator it = m_functions.begin();
54           it != m_functions.end();
55           ++it )
56     {
57         delete *it;
58     }
59 }
60
61 AVC::Plug *
62 BeBoB::SubunitAudio::createPlug( AVC::Unit* unit,
63                      AVC::Subunit* subunit,
64                      AVC::function_block_type_t functionBlockType,
65                      AVC::function_block_type_t functionBlockId,
66                      AVC::Plug::EPlugAddressType plugAddressType,
67                      AVC::Plug::EPlugDirection plugDirection,
68                      AVC::plug_id_t plugId )
69 {
70
71     return new BeBoB::Plug( unit,
72                      subunit,
73                      functionBlockType,
74                      functionBlockId,
75                      plugAddressType,
76                      plugDirection,
77                      plugId );
78 }
79
80 bool
81 BeBoB::SubunitAudio::discover()
82 {
83     debugOutput(DEBUG_LEVEL_NORMAL, "Discovering %s...\n", getName());
84
85     // discover the AV/C generic part
86     if ( !AVC::SubunitAudio::discover() ) {
87         return false;
88     }
89
90     // do the remaining BeBoB audio subunit discovery
91     if ( !discoverFunctionBlocks() ) {
92         debugError( "function block discovering failed\n" );
93         return false;
94     }
95
96     return true;
97 }
98
99 bool
100 BeBoB::SubunitAudio::discoverConnections()
101 {
102     debugOutput(DEBUG_LEVEL_NORMAL, "Discovering connections...\n");
103     if ( !Subunit::discoverConnections() ) {
104         return false;
105     }
106
107     for ( FunctionBlockVector::iterator it = m_functions.begin();
108           it != m_functions.end();
109           ++it )
110     {
111         FunctionBlock* function = *it;
112         if ( !function->discoverConnections() ) {
113             debugError( "functionblock connection discovering failed ('%s')\n",
114                         function->getName() );
115             return false;
116         }
117     }
118
119     return true;
120 }
121
122 const char*
123 BeBoB::SubunitAudio::getName()
124 {
125     return "BeBoB::AudioSubunit";
126 }
127
128 bool
129 BeBoB::SubunitAudio::discoverFunctionBlocks()
130 {
131     debugOutput( DEBUG_LEVEL_NORMAL,
132                  "Discovering function blocks...\n");
133
134     if ( !discoverFunctionBlocksDo(
135              ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector) )
136     {
137         debugError( "Could not discover function block selector\n" );
138         return false;
139     }
140     if ( !discoverFunctionBlocksDo(
141              ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature) )
142     {
143         debugError( "Could not discover function block feature\n" );
144         return false;
145     }
146     if ( !discoverFunctionBlocksDo(
147              ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing) )
148     {
149         debugError( "Could not discover function block processing\n" );
150         return false;
151     }
152     if ( !discoverFunctionBlocksDo(
153              ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec) )
154     {
155         debugError( "Could not discover function block codec\n" );
156         return false;
157     }
158
159     // print a function block list
160 #ifdef DEBUG
161     if ((int)getDebugLevel() >= DEBUG_LEVEL_NORMAL) {
162
163         for ( FunctionBlockVector::iterator it = m_functions.begin();
164             it != m_functions.end();
165             ++it )
166         {
167             debugOutput(DEBUG_LEVEL_NORMAL, "%20s FB, type 0x%X, id=%d\n",
168                 (*it)->getName(),
169                 (*it)->getType(),
170                 (*it)->getId());
171         }
172     }
173 #endif
174
175     return true;
176 }
177
178 bool
179 BeBoB::SubunitAudio::discoverFunctionBlocksDo(
180     ExtendedSubunitInfoCmd::EFunctionBlockType fbType )
181 {
182     int page = 0;
183     bool cmdSuccess = false;
184     bool finished = false;
185
186     do {
187         ExtendedSubunitInfoCmd
188         extSubunitInfoCmd( m_unit->get1394Service() );
189         extSubunitInfoCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
190         extSubunitInfoCmd.setCommandType( AVCCommand::eCT_Status );
191         extSubunitInfoCmd.setSubunitId( getSubunitId() );
192         extSubunitInfoCmd.setSubunitType( getSubunitType() );
193         extSubunitInfoCmd.setVerbose( (int)getDebugLevel() );
194
195         extSubunitInfoCmd.m_fbType = fbType;
196         extSubunitInfoCmd.m_page = page;
197
198         cmdSuccess = extSubunitInfoCmd.fire();
199         if ( cmdSuccess
200              && ( extSubunitInfoCmd.getResponse()
201                   == AVCCommand::eR_Implemented ) )
202         {
203             for ( ExtendedSubunitInfoPageDataVector::iterator it =
204                       extSubunitInfoCmd.m_infoPageDatas.begin();
205                   cmdSuccess
206                       && ( it != extSubunitInfoCmd.m_infoPageDatas.end() );
207                   ++it )
208             {
209                 cmdSuccess = createFunctionBlock( fbType, **it );
210             }
211             if ( ( extSubunitInfoCmd.m_infoPageDatas.size() != 0 )
212                  && ( extSubunitInfoCmd.m_infoPageDatas.size() == 5 ) )
213             {
214                 page++;
215             } else {
216                 finished = true;
217             }
218         } else {
219             finished = true;
220         }
221     } while ( cmdSuccess && !finished );
222
223     return cmdSuccess;
224 }
225
226 bool
227 BeBoB::SubunitAudio::createFunctionBlock(
228     ExtendedSubunitInfoCmd::EFunctionBlockType fbType,
229     ExtendedSubunitInfoPageData& data )
230 {
231     FunctionBlock::ESpecialPurpose purpose
232         = convertSpecialPurpose(  data.m_functionBlockSpecialPupose );
233
234     FunctionBlock* fb = 0;
235
236     switch ( fbType ) {
237     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector:
238     {
239         fb = new FunctionBlockSelector( *this,
240                                         data.m_functionBlockId,
241                                         purpose,
242                                         data.m_noOfInputPlugs,
243                                         data.m_noOfOutputPlugs,
244                                         (int)getDebugLevel() );
245     }
246     break;
247     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature:
248     {
249         fb = new FunctionBlockFeature( *this,
250                                        data.m_functionBlockId,
251                                        purpose,
252                                        data.m_noOfInputPlugs,
253                                        data.m_noOfOutputPlugs,
254                                        (int)getDebugLevel() );
255     }
256     break;
257     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing:
258     {
259         switch ( data.m_functionBlockType ) {
260         case ExtendedSubunitInfoCmd::ePT_EnhancedMixer:
261         {
262             fb = new FunctionBlockEnhancedMixer( *this,
263                                                  data.m_functionBlockId,
264                                                  purpose,
265                                                  data.m_noOfInputPlugs,
266                                                  data.m_noOfOutputPlugs,
267                                                  (int)getDebugLevel() );
268         }
269         break;
270         case ExtendedSubunitInfoCmd::ePT_Mixer:
271         case ExtendedSubunitInfoCmd::ePT_Generic:
272         case ExtendedSubunitInfoCmd::ePT_UpDown:
273         case ExtendedSubunitInfoCmd::ePT_DolbyProLogic:
274         case ExtendedSubunitInfoCmd::ePT_3DStereoExtender:
275         case ExtendedSubunitInfoCmd::ePT_Reverberation:
276         case ExtendedSubunitInfoCmd::ePT_Chorus:
277         case ExtendedSubunitInfoCmd::ePT_DynamicRangeCompression:
278         default:
279             /* It is no use to add a dummy FunctionBlockProcessing because
280                then the function type is not set in FunctionBlockProcessing.
281                When we try to discover the plugs attached to this function block
282                it will fail. It's better just to skip them. */
283             debugOutput( DEBUG_LEVEL_NORMAL, "Found a processing subfunction (type %d) which is not supported. "
284                          "It will be ignored.\n",
285                          data.m_functionBlockType);
286             return true;
287         }
288     }
289     break;
290     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec:
291     {
292             /* It is no use to add a dummy FunctionBlockProcessing because
293                then the function type is not set in FunctionBlockProcessing.
294                When we try to discover the plugs attached to this function block
295                it will fail. It's better just to skip them. */
296             debugOutput( DEBUG_LEVEL_NORMAL, "Found a codec subfunction (type %d) which is not supported. "
297                          "It will be ignored.\n",
298                          data.m_functionBlockType);
299             return true;
300     }
301     break;
302     default:
303         debugError( "Unhandled function block type found\n" );
304         return false;
305     }
306
307     if ( !fb ) {
308         debugError( "Could create function block\n" );
309         return false;
310     }
311     if ( !fb->discover() ) {
312         debugError( "Could not discover function block %s\n",
313                     fb->getName() );
314         delete fb;
315         return false;
316     }
317     m_functions.push_back( fb );
318
319     return true;
320 }
321
322 BeBoB::FunctionBlock::ESpecialPurpose
323 BeBoB::SubunitAudio::convertSpecialPurpose(
324     function_block_special_purpose_t specialPurpose )
325 {
326     FunctionBlock::ESpecialPurpose p;
327     switch ( specialPurpose ) {
328     case ExtendedSubunitInfoPageData::eSP_InputGain:
329         p  = FunctionBlock::eSP_InputGain;
330         break;
331     case ExtendedSubunitInfoPageData::eSP_OutputVolume:
332         p = FunctionBlock::eSP_OutputVolume;
333     break;
334     default:
335         p = FunctionBlock::eSP_NoSpecialPurpose;
336     }
337     return p;
338 }
339
340 bool
341 BeBoB::SubunitAudio::serializeChild( std::string basePath,
342                                      Util::IOSerialize& ser ) const
343 {
344     bool result = true;
345     int i = 0;
346
347     for ( FunctionBlockVector::const_iterator it = m_functions.begin();
348           it != m_functions.end();
349           ++it )
350     {
351         FunctionBlock* pFB = *it;
352         std::ostringstream strstrm;
353         strstrm << basePath << "FunctionBlock" << i << "/";
354
355         result &= pFB->serialize( strstrm.str() , ser );
356
357         i++;
358     }
359
360     return result;
361 }
362
363 bool
364 BeBoB::SubunitAudio::deserializeChild( std::string basePath,
365                                        Util::IODeserialize& deser,
366                                        AVC::Unit& avDevice )
367 {
368     int i = 0;
369     bool bFinished = false;
370     do {
371         std::ostringstream strstrm;
372         strstrm << basePath << "FunctionBlock" << i << "/";
373         FunctionBlock* pFB = FunctionBlock::deserialize( strstrm.str(),
374                                                          deser,
375                                                          avDevice,
376                                                          *this );
377         if ( pFB ) {
378             m_functions.push_back( pFB );
379             i++;
380         } else {
381             bFinished = true;
382         }
383     } while ( !bFinished );
384
385     return true;
386 }
387
388 bool
389 BeBoB::SubunitAudio::deserializeUpdateChild( std::string basePath,
390                                              Util::IODeserialize& deser )
391 {
392     bool result = true;
393     int i = 0;
394
395     for ( FunctionBlockVector::iterator it = m_functions.begin();
396           it != m_functions.end();
397           ++it )
398     {
399         std::ostringstream strstrm;
400         strstrm << basePath << "FunctionBlock" << i << "/";
401
402         result &= (*it)->deserializeUpdate( basePath, deser );
403        
404         i++;
405     }
406
407     return result;
408 }
409
410 ////////////////////////////////////////////
411
412 BeBoB::SubunitMusic::SubunitMusic( AVC::Unit& avDevice,
413                                    subunit_t id )
414     : AVC::SubunitMusic( avDevice, id )
415 {
416 }
417
418 BeBoB::SubunitMusic::SubunitMusic()
419     : AVC::SubunitMusic()
420 {
421 }
422
423 BeBoB::SubunitMusic::~SubunitMusic()
424 {
425 }
426
427 AVC::Plug *
428 BeBoB::SubunitMusic::createPlug( AVC::Unit* unit,
429                      AVC::Subunit* subunit,
430                      AVC::function_block_type_t functionBlockType,
431                      AVC::function_block_type_t functionBlockId,
432                      AVC::Plug::EPlugAddressType plugAddressType,
433                      AVC::Plug::EPlugDirection plugDirection,
434                      AVC::plug_id_t plugId )
435 {
436
437     return new BeBoB::Plug( unit,
438                      subunit,
439                      functionBlockType,
440                      functionBlockId,
441                      plugAddressType,
442                      plugDirection,
443                      plugId );
444 }
445
446 bool
447 BeBoB::SubunitMusic::discover()
448 {
449     debugOutput(DEBUG_LEVEL_NORMAL, "Discovering %s...\n", getName());
450
451     // discover the AV/C generic part
452     if ( !AVC::SubunitMusic::discover() ) {
453         return false;
454     }
455
456     // do the remaining BeBoB music subunit discovery
457     // which is nothing
458
459     return true;
460 }
461
462 const char*
463 BeBoB::SubunitMusic::getName()
464 {
465     return "BeBoB::MusicSubunit";
466 }
467
468 bool
469 BeBoB::SubunitMusic::serializeChild( std::string basePath,
470                                              Util::IOSerialize& ser ) const
471 {
472     return true;
473 }
474
475 bool
476 BeBoB::SubunitMusic::deserializeChild( std::string basePath,
477                                                Util::IODeserialize& deser,
478                                                AVC::Unit& avDevice )
479 {
480     return true;
481 }
482
483 bool
484 BeBoB::SubunitMusic::deserializeUpdateChild( std::string basePath,
485                                              Util::IODeserialize& deser )
486 {
487     return true;
488 }
Note: See TracBrowser for help on using the browser.