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

Revision 554, 13.4 kB (checked in by ppalmers, 17 years ago)

Merge echoaudio branch into trunk.

This adds support for the Echo Audiofire devices to FFADO. Possibly also other devices working with the Apple Class Driver will work with this code. It is not fully complete yet, but the main rework is
done.

First of all the IAvDevice class/interface is renamed to FFADODevice, in order to separate the AV/C code from the FFADO API code. A device supported by FFADO implements a FFADODevice.

The BeBoB device has been split up into three groups:
- libavc/* : all code and commands that are specified by AV/C specs. Note that a lot of the code that used to be in BeBoB::AvDevice? now resides in AVC::Unit
- genericavc/* : a FFADODevice that uses AV/C descriptors & commands for discovery and config
- bebob/* : the bebob FFADODevice that inherits from GenericAVC::AvDevice? but that uses BridgeCo? commands for discovery

Everything has been moved as high as possible in the class hierarchy. If necessary, a subclass that uses device specific commands is introduced (e.g. BeBoB::Plug inherits from AVC::Plug and uses the
BridgeCo? extended plug info command to discover it's properties).

There are some other fixes along the way that have been done too.

Line 
1 /*
2  * Copyright (C) 2005-2007 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 library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License version 2.1, as published by the Free Software Foundation;
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  * MA 02110-1301 USA
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 "libavc/util/avc_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
54 }
55
56 AVC::Plug *
57 BeBoB::SubunitAudio::createPlug( AVC::Unit* unit,
58                      AVC::Subunit* subunit,
59                      AVC::function_block_type_t functionBlockType,
60                      AVC::function_block_type_t functionBlockId,
61                      AVC::Plug::EPlugAddressType plugAddressType,
62                      AVC::Plug::EPlugDirection plugDirection,
63                      AVC::plug_id_t plugId )
64 {
65
66     return new BeBoB::Plug( unit,
67                      subunit,
68                      functionBlockType,
69                      functionBlockId,
70                      plugAddressType,
71                      plugDirection,
72                      plugId );
73 }
74
75 bool
76 BeBoB::SubunitAudio::discover()
77 {
78     debugOutput(DEBUG_LEVEL_NORMAL, "Discovering %s...\n", getName());
79    
80     // discover the AV/C generic part
81     if ( !AVC::SubunitAudio::discover() ) {
82         return false;
83     }
84
85     // do the remaining BeBoB audio subunit discovery
86     if ( !discoverFunctionBlocks() ) {
87         debugError( "function block discovering failed\n" );
88         return false;
89     }
90
91     return true;
92 }
93
94 bool
95 BeBoB::SubunitAudio::discoverConnections()
96 {
97     debugOutput(DEBUG_LEVEL_NORMAL, "Discovering connections...\n");
98     if ( !Subunit::discoverConnections() ) {
99         return false;
100     }
101
102     for ( FunctionBlockVector::iterator it = m_functions.begin();
103           it != m_functions.end();
104           ++it )
105     {
106         FunctionBlock* function = *it;
107         if ( !function->discoverConnections() ) {
108             debugError( "functionblock connection discovering failed ('%s')\n",
109                         function->getName() );
110             return false;
111         }
112     }
113
114     return true;
115 }
116
117 const char*
118 BeBoB::SubunitAudio::getName()
119 {
120     return "BeBoB::AudioSubunit";
121 }
122
123 bool
124 BeBoB::SubunitAudio::discoverFunctionBlocks()
125 {
126     debugOutput( DEBUG_LEVEL_NORMAL,
127                  "Discovering function blocks...\n");
128
129     if ( !discoverFunctionBlocksDo(
130              ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector) )
131     {
132         debugError( "Could not discover function block selector\n" );
133         return false;
134     }
135     if ( !discoverFunctionBlocksDo(
136              ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature) )
137     {
138         debugError( "Could not discover function block feature\n" );
139         return false;
140     }
141     if ( !discoverFunctionBlocksDo(
142              ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing) )
143     {
144         debugError( "Could not discover function block processing\n" );
145         return false;
146     }
147     if ( !discoverFunctionBlocksDo(
148              ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec) )
149     {
150         debugError( "Could not discover function block codec\n" );
151         return false;
152     }
153
154     // print a function block list
155 #ifdef DEBUG
156     if ((int)getDebugLevel() >= DEBUG_LEVEL_NORMAL) {
157    
158         for ( FunctionBlockVector::iterator it = m_functions.begin();
159             it != m_functions.end();
160             ++it )
161         {
162             debugOutput(DEBUG_LEVEL_NORMAL, "%20s FB, type 0x%X, id=%d\n",
163                 (*it)->getName(),
164                 (*it)->getType(),
165                 (*it)->getId());
166         }
167     }
168 #endif
169
170     return true;
171 }
172
173 bool
174 BeBoB::SubunitAudio::discoverFunctionBlocksDo(
175     ExtendedSubunitInfoCmd::EFunctionBlockType fbType )
176 {
177     int page = 0;
178     bool cmdSuccess = false;
179     bool finished = false;
180
181     do {
182         ExtendedSubunitInfoCmd
183         extSubunitInfoCmd( m_unit->get1394Service() );
184         extSubunitInfoCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
185         extSubunitInfoCmd.setCommandType( AVCCommand::eCT_Status );
186         extSubunitInfoCmd.setSubunitId( getSubunitId() );
187         extSubunitInfoCmd.setSubunitType( getSubunitType() );
188         extSubunitInfoCmd.setVerbose( (int)getDebugLevel() );
189
190         extSubunitInfoCmd.m_fbType = fbType;
191         extSubunitInfoCmd.m_page = page;
192
193         cmdSuccess = extSubunitInfoCmd.fire();
194         if ( cmdSuccess
195              && ( extSubunitInfoCmd.getResponse()
196                   == AVCCommand::eR_Implemented ) )
197         {
198             for ( ExtendedSubunitInfoPageDataVector::iterator it =
199                       extSubunitInfoCmd.m_infoPageDatas.begin();
200                   cmdSuccess
201                       && ( it != extSubunitInfoCmd.m_infoPageDatas.end() );
202                   ++it )
203             {
204                 cmdSuccess = createFunctionBlock( fbType, **it );
205             }
206             if ( ( extSubunitInfoCmd.m_infoPageDatas.size() != 0 )
207                  && ( extSubunitInfoCmd.m_infoPageDatas.size() == 5 ) )
208             {
209                 page++;
210             } else {
211                 finished = true;
212             }
213         } else {
214             finished = true;
215         }
216     } while ( cmdSuccess && !finished );
217
218     return cmdSuccess;
219 }
220
221 bool
222 BeBoB::SubunitAudio::createFunctionBlock(
223     ExtendedSubunitInfoCmd::EFunctionBlockType fbType,
224     ExtendedSubunitInfoPageData& data )
225 {
226     FunctionBlock::ESpecialPurpose purpose
227         = convertSpecialPurpose(  data.m_functionBlockSpecialPupose );
228
229     FunctionBlock* fb = 0;
230
231     switch ( fbType ) {
232     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector:
233     {
234         fb = new FunctionBlockSelector( *this,
235                                         data.m_functionBlockId,
236                                         purpose,
237                                         data.m_noOfInputPlugs,
238                                         data.m_noOfOutputPlugs,
239                                         (int)getDebugLevel() );
240     }
241     break;
242     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature:
243     {
244         fb = new FunctionBlockFeature( *this,
245                                        data.m_functionBlockId,
246                                        purpose,
247                                        data.m_noOfInputPlugs,
248                                        data.m_noOfOutputPlugs,
249                                        (int)getDebugLevel() );
250     }
251     break;
252     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing:
253     {
254         switch ( data.m_functionBlockType ) {
255         case ExtendedSubunitInfoCmd::ePT_EnhancedMixer:
256         {
257             fb = new FunctionBlockEnhancedMixer( *this,
258                                                  data.m_functionBlockId,
259                                                  purpose,
260                                                  data.m_noOfInputPlugs,
261                                                  data.m_noOfOutputPlugs,
262                                                  (int)getDebugLevel() );
263         }
264         break;
265         case ExtendedSubunitInfoCmd::ePT_Mixer:
266         case ExtendedSubunitInfoCmd::ePT_Generic:
267         case ExtendedSubunitInfoCmd::ePT_UpDown:
268         case ExtendedSubunitInfoCmd::ePT_DolbyProLogic:
269         case ExtendedSubunitInfoCmd::ePT_3DStereoExtender:
270         case ExtendedSubunitInfoCmd::ePT_Reverberation:
271         case ExtendedSubunitInfoCmd::ePT_Chorus:
272         case ExtendedSubunitInfoCmd::ePT_DynamicRangeCompression:
273         default:
274             fb = new FunctionBlockProcessing( *this,
275                                               data.m_functionBlockId,
276                                               purpose,
277                                               data.m_noOfInputPlugs,
278                                               data.m_noOfOutputPlugs,
279                                               (int)getDebugLevel() );
280             debugWarning( "Dummy function block processing created. "
281                           "Implementation is missing\n" );
282         }
283     }
284     break;
285     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec:
286     {
287         fb = new FunctionBlockCodec( *this,
288                                      data.m_functionBlockId,
289                                      purpose,
290                                      data.m_noOfInputPlugs,
291                                      data.m_noOfOutputPlugs,
292                                      (int)getDebugLevel() );
293         debugWarning( "Dummy function block codec created. "
294                       "Implementation is missing\n" );
295     }
296     break;
297     default:
298         debugError( "Unhandled function block type found\n" );
299         return false;
300     }
301
302     if ( !fb ) {
303         debugError( "Could create function block\n" );
304         return false;
305     }
306     if ( !fb->discover() ) {
307         debugError( "Could not discover function block %s\n",
308                     fb->getName() );
309         delete fb;
310         return false;
311     }
312     m_functions.push_back( fb );
313
314     return true;
315 }
316
317 BeBoB::FunctionBlock::ESpecialPurpose
318 BeBoB::SubunitAudio::convertSpecialPurpose(
319     function_block_special_purpose_t specialPurpose )
320 {
321     FunctionBlock::ESpecialPurpose p;
322     switch ( specialPurpose ) {
323     case ExtendedSubunitInfoPageData::eSP_InputGain:
324         p  = FunctionBlock::eSP_InputGain;
325         break;
326     case ExtendedSubunitInfoPageData::eSP_OutputVolume:
327         p = FunctionBlock::eSP_OutputVolume;
328     break;
329     default:
330         p = FunctionBlock::eSP_NoSpecialPurpose;
331     }
332     return p;
333 }
334
335 bool
336 BeBoB::SubunitAudio::serializeChild( Glib::ustring basePath,
337                                              Util::IOSerialize& ser ) const
338 {
339     bool result = true;
340     int i = 0;
341
342     for ( FunctionBlockVector::const_iterator it = m_functions.begin();
343           it != m_functions.end();
344           ++it )
345     {
346         FunctionBlock* pFB = *it;
347         std::ostringstream strstrm;
348         strstrm << basePath << "FunctionBlock" << i << "/";
349
350         result &= pFB->serialize( strstrm.str() , ser );
351
352         i++;
353     }
354
355     return result;
356 }
357
358 bool
359 BeBoB::SubunitAudio::deserializeChild( Glib::ustring basePath,
360                                                Util::IODeserialize& deser,
361                                                AVC::Unit& avDevice )
362 {
363     int i = 0;
364     bool bFinished = false;
365     do {
366         std::ostringstream strstrm;
367         strstrm << basePath << "FunctionBlock" << i << "/";
368         FunctionBlock* pFB = FunctionBlock::deserialize( strstrm.str(),
369                                                          deser,
370                                                          avDevice,
371                                                          *this );
372         if ( pFB ) {
373             m_functions.push_back( pFB );
374             i++;
375         } else {
376             bFinished = true;
377         }
378     } while ( !bFinished );
379
380     return true;
381 }
382
383 ////////////////////////////////////////////
384
385 BeBoB::SubunitMusic::SubunitMusic( AVC::Unit& avDevice,
386                                    subunit_t id )
387     : AVC::SubunitMusic( avDevice, id )
388 {
389 }
390
391 BeBoB::SubunitMusic::SubunitMusic()
392     : AVC::SubunitMusic()
393 {
394 }
395
396 BeBoB::SubunitMusic::~SubunitMusic()
397 {
398 }
399
400 AVC::Plug *
401 BeBoB::SubunitMusic::createPlug( AVC::Unit* unit,
402                      AVC::Subunit* subunit,
403                      AVC::function_block_type_t functionBlockType,
404                      AVC::function_block_type_t functionBlockId,
405                      AVC::Plug::EPlugAddressType plugAddressType,
406                      AVC::Plug::EPlugDirection plugDirection,
407                      AVC::plug_id_t plugId )
408 {
409
410     return new BeBoB::Plug( unit,
411                      subunit,
412                      functionBlockType,
413                      functionBlockId,
414                      plugAddressType,
415                      plugDirection,
416                      plugId );
417 }
418
419 bool
420 BeBoB::SubunitMusic::discover()
421 {
422     debugOutput(DEBUG_LEVEL_NORMAL, "Discovering %s...\n", getName());
423    
424     // discover the AV/C generic part
425     if ( !AVC::SubunitMusic::discover() ) {
426         return false;
427     }
428
429     // do the remaining BeBoB music subunit discovery
430     // which is nothing
431
432     return true;
433 }
434
435 const char*
436 BeBoB::SubunitMusic::getName()
437 {
438     return "BeBoB::MusicSubunit";
439 }
440
441 bool
442 BeBoB::SubunitMusic::serializeChild( Glib::ustring basePath,
443                                              Util::IOSerialize& ser ) const
444 {
445     return true;
446 }
447
448 bool
449 BeBoB::SubunitMusic::deserializeChild( Glib::ustring basePath,
450                                                Util::IODeserialize& deser,
451                                                AVC::Unit& avDevice )
452 {
453     return true;
454 }
Note: See TracBrowser for help on using the browser.