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

Revision 451, 17.8 kB (checked in by ppalmers, 15 years ago)

- First attempt at a OSC controlled mixer. The level of

abstraction is very low, meaning that you have to know
how the function blocks work. It however allows control
applications to be written and to experiment with them.

- This version only does Selector function blocks.

The following message switches the phase88 input to the

  • front (or is is back?)
    /devicemanager/dev0/GenericMixer set selector 10 0
  • back (or is it front?)
    /devicemanager/dev0/GenericMixer set selector 10 1

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/avc_plug_info.h"
31 #include "libavc/avc_extended_stream_format.h"
32 #include "libavc/avc_serialize.h"
33
34 #include <sstream>
35
36 IMPL_DEBUG_MODULE( BeBoB::AvDeviceSubunit, BeBoB::AvDeviceSubunit, DEBUG_LEVEL_VERBOSE );
37
38 ////////////////////////////////////////////
39
40 BeBoB::AvDeviceSubunit::AvDeviceSubunit( AvDevice& avDevice,
41                                          AVCCommand::ESubunitType type,
42                                          subunit_t id,
43                                          int verboseLevel )
44     : m_avDevice( &avDevice )
45     , m_sbType( type )
46     , m_sbId( id )
47     , m_verboseLevel( verboseLevel )
48 {
49     setDebugLevel( m_verboseLevel );
50 }
51
52 BeBoB::AvDeviceSubunit::AvDeviceSubunit()
53 {
54 }
55
56 BeBoB::AvDeviceSubunit::~AvDeviceSubunit()
57 {
58     for ( AvPlugVector::iterator it = m_plugs.begin();
59           it != m_plugs.end();
60           ++it )
61     {
62         delete *it;
63     }
64 }
65
66 bool
67 BeBoB::AvDeviceSubunit::discover()
68 {
69     if ( !discoverPlugs() ) {
70         debugError( "plug discovering failed\n" );
71         return false;
72     }
73
74     return true;
75 }
76
77 bool
78 BeBoB::AvDeviceSubunit::discoverPlugs()
79 {
80     PlugInfoCmd plugInfoCmd( m_avDevice->get1394Service(),
81                              PlugInfoCmd::eSF_SerialBusIsochronousAndExternalPlug );
82     plugInfoCmd.setNodeId( m_avDevice->getConfigRom().getNodeId() );
83     plugInfoCmd.setCommandType( AVCCommand::eCT_Status );
84     plugInfoCmd.setSubunitType( m_sbType );
85     plugInfoCmd.setSubunitId( m_sbId );
86     plugInfoCmd.setVerbose( m_verboseLevel );
87
88     if ( !plugInfoCmd.fire() ) {
89         debugError( "plug info command failed\n" );
90         return false;
91     }
92
93     debugOutput( DEBUG_LEVEL_NORMAL, "number of source plugs = %d\n",
94                  plugInfoCmd.m_sourcePlugs );
95     debugOutput( DEBUG_LEVEL_NORMAL, "number of destination output "
96                  "plugs = %d\n", plugInfoCmd.m_destinationPlugs );
97
98     if ( !discoverPlugs( AvPlug::eAPD_Input,
99                          plugInfoCmd.m_destinationPlugs ) )
100     {
101         debugError( "destination plug discovering failed\n" );
102         return false;
103     }
104
105     if ( !discoverPlugs(  AvPlug::eAPD_Output,
106                           plugInfoCmd.m_sourcePlugs ) )
107     {
108         debugError( "source plug discovering failed\n" );
109         return false;
110     }
111
112     return true;
113 }
114
115 bool
116 BeBoB::AvDeviceSubunit::discoverConnections()
117 {
118     for ( AvPlugVector::iterator it = m_plugs.begin();
119           it != m_plugs.end();
120           ++it )
121     {
122         AvPlug* plug = *it;
123         if ( !plug->discoverConnections() ) {
124             debugError( "plug connection discovering failed ('%s')\n",
125                         plug->getName() );
126             return false;
127         }
128     }
129
130     return true;
131 }
132
133 bool
134 BeBoB::AvDeviceSubunit::discoverPlugs(AvPlug::EAvPlugDirection plugDirection,
135                                       plug_id_t plugMaxId )
136 {
137     for ( int plugIdx = 0;
138           plugIdx < plugMaxId;
139           ++plugIdx )
140     {
141         AVCCommand::ESubunitType subunitType =
142             static_cast<AVCCommand::ESubunitType>( getSubunitType() );
143         AvPlug* plug = new AvPlug( m_avDevice->get1394Service(),
144                                    m_avDevice->getConfigRom(),
145                                    m_avDevice->getPlugManager(),
146                                    subunitType,
147                                    getSubunitId(),
148                                    0xff,
149                                    0xff,
150                                    AvPlug::eAPA_SubunitPlug,
151                                    plugDirection,
152                                    plugIdx,
153                                    m_verboseLevel );
154         if ( !plug || !plug->discover() ) {
155             debugError( "plug discover failed\n" );
156             return false;
157         }
158
159         debugOutput( DEBUG_LEVEL_NORMAL, "plug '%s' found\n",
160                      plug->getName() );
161         m_plugs.push_back( plug );
162     }
163     return true;
164 }
165
166 bool
167 BeBoB::AvDeviceSubunit::addPlug( AvPlug& plug )
168 {
169     m_plugs.push_back( &plug );
170     return true;
171 }
172
173
174 BeBoB::AvPlug*
175 BeBoB::AvDeviceSubunit::getPlug(AvPlug::EAvPlugDirection direction, plug_id_t plugId)
176 {
177     for ( AvPlugVector::iterator it = m_plugs.begin();
178           it != m_plugs.end();
179           ++it )
180     {
181         AvPlug* plug = *it;
182         if ( ( plug->getPlugId() == plugId )
183             && ( plug->getDirection() == direction ) )
184         {
185             return plug;
186         }
187     }
188     return 0;
189 }
190
191
192 bool
193 BeBoB::AvDeviceSubunit::serialize( Glib::ustring basePath,
194                                    Util::IOSerialize& ser ) const
195 {
196     bool result;
197
198     result  = ser.write( basePath + "m_sbType", m_sbType );
199     result &= ser.write( basePath + "m_sbId", m_sbId );
200     result &= ser.write( basePath + "m_verboseLevel", m_verboseLevel );
201     result &= serializeChild( basePath, ser );
202
203     return result;
204 }
205
206 BeBoB::AvDeviceSubunit*
207 BeBoB::AvDeviceSubunit::deserialize( Glib::ustring basePath,
208                                      Util::IODeserialize& deser,
209                                      AvDevice& avDevice )
210 {
211     bool result;
212     AVCCommand::ESubunitType sbType;
213     result  = deser.read( basePath + "m_sbType", sbType );
214
215     AvDeviceSubunit* pSubunit = 0;
216     switch( sbType ) {
217     case AVCCommand::eST_Audio:
218         pSubunit = new AvDeviceSubunitAudio;
219         break;
220     case AVCCommand::eST_Music:
221         pSubunit = new AvDeviceSubunitMusic;
222         break;
223     default:
224         pSubunit = 0;
225     }
226
227     if ( !pSubunit ) {
228         return 0;
229     }
230
231     pSubunit->m_avDevice = &avDevice;
232     pSubunit->m_sbType = sbType;
233     result &= deser.read( basePath + "m_sbId", pSubunit->m_sbId );
234     result &= deser.read( basePath + "m_verboseLevel", pSubunit->m_verboseLevel );
235     result &= pSubunit->deserializeChild( basePath, deser, avDevice );
236
237     if ( !result ) {
238         delete pSubunit;
239         return 0;
240     }
241
242     return pSubunit;
243 }
244
245 ////////////////////////////////////////////
246
247 BeBoB::AvDeviceSubunitAudio::AvDeviceSubunitAudio( AvDevice& avDevice,
248                                                    subunit_t id,
249                                                    int verboseLevel )
250     : AvDeviceSubunit( avDevice, AVCCommand::eST_Audio, id, verboseLevel )
251 {
252 }
253
254 BeBoB::AvDeviceSubunitAudio::AvDeviceSubunitAudio()
255     : AvDeviceSubunit()
256 {
257 }
258
259 BeBoB::AvDeviceSubunitAudio::~AvDeviceSubunitAudio()
260 {
261     for ( FunctionBlockVector::iterator it = m_functions.begin();
262           it != m_functions.end();
263           ++it )
264     {
265         delete *it;
266     }
267 }
268
269 bool
270 BeBoB::AvDeviceSubunitAudio::discover()
271 {
272     debugOutput(DEBUG_LEVEL_NORMAL, "Discovering Audio Subunit...\n");
273    
274     if ( !AvDeviceSubunit::discover() ) {
275         return false;
276     }
277
278     if ( !discoverFunctionBlocks() ) {
279         debugError( "function block discovering failed\n" );
280         return false;
281     }
282
283     return true;
284 }
285
286 bool
287 BeBoB::AvDeviceSubunitAudio::discoverConnections()
288 {
289     debugOutput(DEBUG_LEVEL_NORMAL, "Discovering connections...\n");
290     if ( !AvDeviceSubunit::discoverConnections() ) {
291         return false;
292     }
293
294     for ( FunctionBlockVector::iterator it = m_functions.begin();
295           it != m_functions.end();
296           ++it )
297     {
298         FunctionBlock* function = *it;
299         if ( !function->discoverConnections() ) {
300             debugError( "functionblock connection discovering failed ('%s')\n",
301                         function->getName() );
302             return false;
303         }
304     }
305
306     return true;
307 }
308
309 const char*
310 BeBoB::AvDeviceSubunitAudio::getName()
311 {
312     return "AudioSubunit";
313 }
314
315 bool
316 BeBoB::AvDeviceSubunitAudio::discoverFunctionBlocks()
317 {
318     debugOutput( DEBUG_LEVEL_NORMAL,
319                  "Discovering function blocks...\n");
320
321     if ( !discoverFunctionBlocksDo(
322              ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector) )
323     {
324         debugError( "Could not discover function block selector\n" );
325         return false;
326     }
327     if ( !discoverFunctionBlocksDo(
328              ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature) )
329     {
330         debugError( "Could not discover function block feature\n" );
331         return false;
332     }
333     if ( !discoverFunctionBlocksDo(
334              ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing) )
335     {
336         debugError( "Could not discover function block processing\n" );
337         return false;
338     }
339     if ( !discoverFunctionBlocksDo(
340              ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec) )
341     {
342         debugError( "Could not discover function block codec\n" );
343         return false;
344     }
345
346     // print a function block list
347 #ifdef DEBUG
348     if (getDebugLevel() >= DEBUG_LEVEL_NORMAL) {
349    
350         for ( FunctionBlockVector::iterator it = m_functions.begin();
351             it != m_functions.end();
352             ++it )
353         {
354             debugOutput(DEBUG_LEVEL_NORMAL, "%20s FB, type 0x%X, id=%d\n",
355                 (*it)->getName(),
356                 (*it)->getType(),
357                 (*it)->getId());
358         }
359     }
360 #endif
361
362     return true;
363 }
364
365 bool
366 BeBoB::AvDeviceSubunitAudio::discoverFunctionBlocksDo(
367     ExtendedSubunitInfoCmd::EFunctionBlockType fbType )
368 {
369     int page = 0;
370     bool cmdSuccess = false;
371     bool finished = false;
372
373     do {
374         ExtendedSubunitInfoCmd
375             extSubunitInfoCmd( m_avDevice->get1394Service() );
376         extSubunitInfoCmd.setNodeId( m_avDevice->getConfigRom().getNodeId() );
377         extSubunitInfoCmd.setCommandType( AVCCommand::eCT_Status );
378         extSubunitInfoCmd.setSubunitId( getSubunitId() );
379         extSubunitInfoCmd.setSubunitType( getSubunitType() );
380         extSubunitInfoCmd.setVerbose( m_verboseLevel );
381
382         extSubunitInfoCmd.m_fbType = fbType;
383         extSubunitInfoCmd.m_page = page;
384
385         cmdSuccess = extSubunitInfoCmd.fire();
386         if ( cmdSuccess
387              && ( extSubunitInfoCmd.getResponse()
388                   == AVCCommand::eR_Implemented ) )
389         {
390             for ( ExtendedSubunitInfoPageDataVector::iterator it =
391                       extSubunitInfoCmd.m_infoPageDatas.begin();
392                   cmdSuccess
393                       && ( it != extSubunitInfoCmd.m_infoPageDatas.end() );
394                   ++it )
395             {
396                 cmdSuccess = createFunctionBlock( fbType, **it );
397             }
398             if ( ( extSubunitInfoCmd.m_infoPageDatas.size() != 0 )
399                  && ( extSubunitInfoCmd.m_infoPageDatas.size() == 5 ) )
400             {
401                 page++;
402             } else {
403                 finished = true;
404             }
405         } else {
406             finished = true;
407         }
408     } while ( cmdSuccess && !finished );
409
410     return cmdSuccess;
411 }
412
413 bool
414 BeBoB::AvDeviceSubunitAudio::createFunctionBlock(
415     ExtendedSubunitInfoCmd::EFunctionBlockType fbType,
416     ExtendedSubunitInfoPageData& data )
417 {
418     FunctionBlock::ESpecialPurpose purpose
419         = convertSpecialPurpose(  data.m_functionBlockSpecialPupose );
420
421     FunctionBlock* fb = 0;
422
423     switch ( fbType ) {
424     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector:
425     {
426         fb = new FunctionBlockSelector( *this,
427                                         data.m_functionBlockId,
428                                         purpose,
429                                         data.m_noOfInputPlugs,
430                                         data.m_noOfOutputPlugs,
431                                         m_verboseLevel );
432     }
433     break;
434     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature:
435     {
436         fb = new FunctionBlockFeature( *this,
437                                        data.m_functionBlockId,
438                                        purpose,
439                                        data.m_noOfInputPlugs,
440                                        data.m_noOfOutputPlugs,
441                                        m_verboseLevel );
442     }
443     break;
444     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing:
445     {
446         switch ( data.m_functionBlockType ) {
447         case ExtendedSubunitInfoCmd::ePT_EnhancedMixer:
448         {
449             fb = new FunctionBlockEnhancedMixer( *this,
450                                                  data.m_functionBlockId,
451                                                  purpose,
452                                                  data.m_noOfInputPlugs,
453                                                  data.m_noOfOutputPlugs,
454                                                  m_verboseLevel );
455         }
456         break;
457         case ExtendedSubunitInfoCmd::ePT_Mixer:
458         case ExtendedSubunitInfoCmd::ePT_Generic:
459         case ExtendedSubunitInfoCmd::ePT_UpDown:
460         case ExtendedSubunitInfoCmd::ePT_DolbyProLogic:
461         case ExtendedSubunitInfoCmd::ePT_3DStereoExtender:
462         case ExtendedSubunitInfoCmd::ePT_Reverberation:
463         case ExtendedSubunitInfoCmd::ePT_Chorus:
464         case ExtendedSubunitInfoCmd::ePT_DynamicRangeCompression:
465         default:
466             fb = new FunctionBlockProcessing( *this,
467                                               data.m_functionBlockId,
468                                               purpose,
469                                               data.m_noOfInputPlugs,
470                                               data.m_noOfOutputPlugs,
471                                               m_verboseLevel );
472             debugWarning( "Dummy function block processing created. "
473                           "Implementation is missing\n" );
474         }
475     }
476     break;
477     case ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec:
478     {
479         fb = new FunctionBlockCodec( *this,
480                                      data.m_functionBlockId,
481                                      purpose,
482                                      data.m_noOfInputPlugs,
483                                      data.m_noOfOutputPlugs,
484                                      m_verboseLevel );
485         debugWarning( "Dummy function block codec created. "
486                       "Implementation is missing\n" );
487     }
488     break;
489     default:
490         debugError( "Unhandled function block type found\n" );
491         return false;
492     }
493
494     if ( !fb ) {
495         debugError( "Could create function block\n" );
496         return false;
497     }
498     if ( !fb->discover() ) {
499         debugError( "Could not discover function block %s\n",
500                     fb->getName() );
501         delete fb;
502         return false;
503     }
504     m_functions.push_back( fb );
505
506     return true;
507 }
508
509 BeBoB::FunctionBlock::ESpecialPurpose
510 BeBoB::AvDeviceSubunitAudio::convertSpecialPurpose(
511     function_block_special_purpose_t specialPurpose )
512 {
513     FunctionBlock::ESpecialPurpose p;
514     switch ( specialPurpose ) {
515     case ExtendedSubunitInfoPageData::eSP_InputGain:
516         p  = FunctionBlock::eSP_InputGain;
517         break;
518     case ExtendedSubunitInfoPageData::eSP_OutputVolume:
519         p = FunctionBlock::eSP_OutputVolume;
520     break;
521     default:
522         p = FunctionBlock::eSP_NoSpecialPurpose;
523     }
524     return p;
525 }
526
527 bool
528 BeBoB::AvDeviceSubunitAudio::serializeChild( Glib::ustring basePath,
529                                              Util::IOSerialize& ser ) const
530 {
531     bool result = true;
532     int i = 0;
533
534     for ( FunctionBlockVector::const_iterator it = m_functions.begin();
535           it != m_functions.end();
536           ++it )
537     {
538         FunctionBlock* pFB = *it;
539         std::ostringstream strstrm;
540         strstrm << basePath << "FunctionBlock" << i << "/";
541
542         result &= pFB->serialize( strstrm.str() , ser );
543
544         i++;
545     }
546
547     return result;
548 }
549
550 bool
551 BeBoB::AvDeviceSubunitAudio::deserializeChild( Glib::ustring basePath,
552                                                Util::IODeserialize& deser,
553                                                AvDevice& avDevice )
554 {
555     int i = 0;
556     bool bFinished = false;
557     do {
558         std::ostringstream strstrm;
559         strstrm << basePath << "FunctionBlock" << i << "/";
560         FunctionBlock* pFB = FunctionBlock::deserialize( strstrm.str(),
561                                                          deser,
562                                                          avDevice,
563                                                          *this );
564         if ( pFB ) {
565             m_functions.push_back( pFB );
566             i++;
567         } else {
568             bFinished = true;
569         }
570     } while ( !bFinished );
571
572     return true;
573 }
574
575 ////////////////////////////////////////////
576
577 BeBoB::AvDeviceSubunitMusic::AvDeviceSubunitMusic( AvDevice& avDevice,
578                                                    subunit_t id,
579                                                    int verboseLevel )
580     : AvDeviceSubunit( avDevice, AVCCommand::eST_Music, id, verboseLevel )
581 {
582 }
583
584 BeBoB::AvDeviceSubunitMusic::AvDeviceSubunitMusic()
585     : AvDeviceSubunit()
586 {
587 }
588
589 BeBoB::AvDeviceSubunitMusic::~AvDeviceSubunitMusic()
590 {
591 }
592
593 const char*
594 BeBoB::AvDeviceSubunitMusic::getName()
595 {
596     return "MusicSubunit";
597 }
598
599 bool
600 BeBoB::AvDeviceSubunitMusic::serializeChild( Glib::ustring basePath,
601                                              Util::IOSerialize& ser ) const
602 {
603     return true;
604 }
605
606 bool
607 BeBoB::AvDeviceSubunitMusic::deserializeChild( Glib::ustring basePath,
608                                                Util::IODeserialize& deser,
609                                                AvDevice& avDevice )
610 {
611     return true;
612 }
Note: See TracBrowser for help on using the browser.