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

Revision 871, 13.6 kB (checked in by wagi, 16 years ago)

use debugOutput instead of debugWarning for not supported function blocks

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( Glib::ustring 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( Glib::ustring 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 ////////////////////////////////////////////
389
390 BeBoB::SubunitMusic::SubunitMusic( AVC::Unit& avDevice,
391                                    subunit_t id )
392     : AVC::SubunitMusic( avDevice, id )
393 {
394 }
395
396 BeBoB::SubunitMusic::SubunitMusic()
397     : AVC::SubunitMusic()
398 {
399 }
400
401 BeBoB::SubunitMusic::~SubunitMusic()
402 {
403 }
404
405 AVC::Plug *
406 BeBoB::SubunitMusic::createPlug( AVC::Unit* unit,
407                      AVC::Subunit* subunit,
408                      AVC::function_block_type_t functionBlockType,
409                      AVC::function_block_type_t functionBlockId,
410                      AVC::Plug::EPlugAddressType plugAddressType,
411                      AVC::Plug::EPlugDirection plugDirection,
412                      AVC::plug_id_t plugId )
413 {
414
415     return new BeBoB::Plug( unit,
416                      subunit,
417                      functionBlockType,
418                      functionBlockId,
419                      plugAddressType,
420                      plugDirection,
421                      plugId );
422 }
423
424 bool
425 BeBoB::SubunitMusic::discover()
426 {
427     debugOutput(DEBUG_LEVEL_NORMAL, "Discovering %s...\n", getName());
428
429     // discover the AV/C generic part
430     if ( !AVC::SubunitMusic::discover() ) {
431         return false;
432     }
433
434     // do the remaining BeBoB music subunit discovery
435     // which is nothing
436
437     return true;
438 }
439
440 const char*
441 BeBoB::SubunitMusic::getName()
442 {
443     return "BeBoB::MusicSubunit";
444 }
445
446 bool
447 BeBoB::SubunitMusic::serializeChild( Glib::ustring basePath,
448                                              Util::IOSerialize& ser ) const
449 {
450     return true;
451 }
452
453 bool
454 BeBoB::SubunitMusic::deserializeChild( Glib::ustring basePath,
455                                                Util::IODeserialize& deser,
456                                                AVC::Unit& avDevice )
457 {
458     return true;
459 }
Note: See TracBrowser for help on using the browser.