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

Revision 554, 16.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_avdevice.h"
25 #include "bebob/bebob_avdevice_subunit.h"
26 #include "bebob/GenericMixer.h"
27
28 #include "libieee1394/configrom.h"
29 #include "libieee1394/ieee1394service.h"
30
31 #include "libavc/general/avc_plug_info.h"
32 #include "libavc/general/avc_extended_plug_info.h"
33 #include "libavc/general/avc_subunit_info.h"
34 #include "libavc/streamformat/avc_extended_stream_format.h"
35 #include "libavc/util/avc_serialize.h"
36 #include "libavc/avc_definitions.h"
37
38 #include "debugmodule/debugmodule.h"
39
40 #include <iostream>
41 #include <sstream>
42 #include <unistd.h>
43 #include <sys/stat.h>
44
45 using namespace AVC;
46
47 namespace BeBoB {
48
49 static GenericAVC::VendorModelEntry supportedDeviceList[] =
50 {
51     {0x00000f, 0x00010065, "Mackie", "Onyx Firewire"},
52
53     {0x0003db, 0x00010048, "Apogee Electronics", "Rosetta 200"},
54
55     {0x0007f5, 0x00010048, "BridgeCo", "RD Audio1"},
56
57     {0x000a92, 0x00010000, "PreSonus", "FIREBOX"},
58     {0x000a92, 0x00010066, "PreSonus", "FirePOD"},
59
60     {0x000aac, 0x00000003, "TerraTec Electronic GmbH", "Phase 88 FW"},
61     {0x000aac, 0x00000004, "TerraTec Electronic GmbH", "Phase X24 FW (model version 4)"},
62     {0x000aac, 0x00000007, "TerraTec Electronic GmbH", "Phase X24 FW (model version 7)"},
63
64     {0x000f1b, 0x00010064, "ESI", "Quatafire 610"},
65
66     {0x00130e, 0x00000000, "Focusrite", "Saffire (LE)"},
67     {0x00130e, 0x00000003, "Focusrite", "Saffire Pro26IO"},
68     {0x00130e, 0x00000006, "Focusrite", "Saffire Pro10IO"},
69
70     {0x0040ab, 0x00010048, "EDIROL", "FA-101"},
71     {0x0040ab, 0x00010049, "EDIROL", "FA-66"},
72
73     {0x000d6c, 0x00010062, "M-Audio", "FW Solo"},
74     {0x000d6c, 0x00010081, "M-Audio", "NRV10"},
75 };
76
77 AvDevice::AvDevice( std::auto_ptr< ConfigRom >( configRom ),
78                     Ieee1394Service& ieee1394service,
79                     int nodeId )
80     : GenericAVC::AvDevice( configRom, ieee1394service, nodeId )
81     , m_Mixer ( NULL )
82 {
83     debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::AvDevice (NodeID %d)\n",
84                  nodeId );
85 }
86
87 AvDevice::~AvDevice()
88 {
89     if(m_Mixer != NULL) {
90         if (!removeChildOscNode(m_Mixer)) {
91             debugWarning("failed to unregister mixer from OSC namespace\n");
92         }
93         delete m_Mixer;
94     }
95 }
96
97 AVC::Subunit*
98 AvDevice::createSubunit(AVC::Unit& unit,
99                                AVC::ESubunitType type,
100                                AVC::subunit_t id )
101 {
102     switch (type) {
103         case AVC::eST_Audio:
104             return new BeBoB::SubunitAudio(unit, id );
105         case AVC::eST_Music:
106             return new BeBoB::SubunitMusic(unit, id );
107         default:
108             return NULL;
109     }
110 }
111
112 AVC::Plug *
113 AvDevice::createPlug( AVC::Unit* unit,
114                      AVC::Subunit* subunit,
115                      AVC::function_block_type_t functionBlockType,
116                      AVC::function_block_type_t functionBlockId,
117                      AVC::Plug::EPlugAddressType plugAddressType,
118                      AVC::Plug::EPlugDirection plugDirection,
119                      AVC::plug_id_t plugId )
120 {
121
122     return new BeBoB::Plug( unit,
123                      subunit,
124                      functionBlockType,
125                      functionBlockId,
126                      plugAddressType,
127                      plugDirection,
128                      plugId );
129 }
130
131 bool
132 AvDevice::probe( ConfigRom& configRom )
133 {
134     unsigned int vendorId = configRom.getNodeVendorId();
135     unsigned int modelId = configRom.getModelId();
136
137     //ConfigParser configParser( "/home/wagi/src/libffado/src/bebob/ffado_driver_bebob.txt" );
138
139     for ( unsigned int i = 0;
140           i < ( sizeof( supportedDeviceList )/sizeof( GenericAVC::VendorModelEntry ) );
141           ++i )
142     {
143         if ( ( supportedDeviceList[i].vendor_id == vendorId )
144              && ( supportedDeviceList[i].model_id == modelId ) )
145         {
146             return true;
147         }
148     }
149     return false;
150 }
151
152 bool
153 AvDevice::discover()
154 {
155     unsigned int vendorId = m_pConfigRom->getNodeVendorId();
156     unsigned int modelId = m_pConfigRom->getModelId();
157
158     for ( unsigned int i = 0;
159           i < ( sizeof( supportedDeviceList )/sizeof( GenericAVC::VendorModelEntry ) );
160           ++i )
161     {
162         if ( ( supportedDeviceList[i].vendor_id == vendorId )
163              && ( supportedDeviceList[i].model_id == modelId )
164            )
165         {
166             m_model = &(supportedDeviceList[i]);
167             break;
168         }
169     }
170
171     if (m_model != NULL) {
172         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
173                 m_model->vendor_name, m_model->model_name);
174     } else return false;
175
176     if ( !Unit::discover() ) {
177         debugError( "Could not discover unit\n" );
178         return false;
179     }
180
181     if((getAudioSubunit( 0 ) == NULL)) {
182         debugError( "Unit doesn't have an Audio subunit.\n");
183         return false;
184     }
185     if((getMusicSubunit( 0 ) == NULL)) {
186         debugError( "Unit doesn't have a Music subunit.\n");
187         return false;
188     }
189
190 // replaced by the previous Unit discovery
191 //     if ( !enumerateSubUnits() ) {
192 //         debugError( "Could not enumarate sub units\n" );
193 //         return false;
194 //     }
195
196     // create a GenericMixer and add it as an OSC child node
197     //  remove if already there
198     if(m_Mixer != NULL) {
199         if (!removeChildOscNode(m_Mixer)) {
200             debugWarning("failed to unregister mixer from OSC namespace\n");
201         }
202         delete m_Mixer;
203     }
204    
205     //  create the mixer & register it
206     if(getAudioSubunit(0) == NULL) {
207         debugWarning("Could not find audio subunit, mixer not available.\n");
208         m_Mixer = NULL;
209     } else {
210         m_Mixer = new GenericMixer(*m_p1394Service , *this);
211         if (!addChildOscNode(m_Mixer)) {
212             debugWarning("failed to register mixer in OSC namespace\n");
213         }
214     }
215     return true;
216 }
217
218 bool
219 AvDevice::propagatePlugInfo() {
220     // we don't have to propagate since we discover things
221     // another way
222     debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
223     return true;
224 }
225
226
227 int
228 AvDevice::getConfigurationIdSampleRate()
229 {
230     ExtendedStreamFormatCmd extStreamFormatCmd( *m_p1394Service );
231     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
232                                      m_nodeId );
233     extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
234                                                     PlugAddress::ePAM_Unit,
235                                                     unitPlugAddress ) );
236
237     extStreamFormatCmd.setNodeId( m_nodeId );
238     extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
239     extStreamFormatCmd.setVerbose( true );
240
241     if ( !extStreamFormatCmd.fire() ) {
242         debugError( "Stream format command failed\n" );
243         return false;
244     }
245
246     FormatInformation* formatInfo =
247         extStreamFormatCmd.getFormatInformation();
248     FormatInformationStreamsCompound* compoundStream
249         = dynamic_cast< FormatInformationStreamsCompound* > (
250             formatInfo->m_streams );
251     if ( compoundStream ) {
252         debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
253                     compoundStream->m_samplingFrequency );
254         return compoundStream->m_samplingFrequency;
255     }
256
257     debugError( "Could not retrieve sample rate\n" );
258     return 0;
259 }
260
261 int
262 AvDevice::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
263 {
264     ExtendedPlugInfoCmd extPlugInfoCmd( *m_p1394Service );
265     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
266                                      m_nodeId );
267     extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
268                                                 PlugAddress::ePAM_Unit,
269                                                 unitPlugAddress ) );
270     extPlugInfoCmd.setNodeId( m_nodeId );
271     extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
272     extPlugInfoCmd.setVerbose( true );
273     ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
274         ExtendedPlugInfoInfoType::eIT_NoOfChannels );
275     extendedPlugInfoInfoType.initialize();
276     extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
277
278     if ( !extPlugInfoCmd.fire() ) {
279         debugError( "Number of channels command failed\n" );
280         return false;
281     }
282
283     ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
284     if ( infoType
285          && infoType->m_plugNrOfChns )
286     {
287         debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
288                     infoType->m_plugNrOfChns->m_nrOfChannels );
289         return infoType->m_plugNrOfChns->m_nrOfChannels;
290     }
291
292     debugError( "Could not retrieve number of channels\n" );
293     return 0;
294 }
295
296 int
297 AvDevice::getConfigurationIdSyncMode()
298 {
299     SignalSourceCmd signalSourceCmd( *m_p1394Service );
300     SignalUnitAddress signalUnitAddr;
301     signalUnitAddr.m_plugId = 0x01;
302     signalSourceCmd.setSignalDestination( signalUnitAddr );
303     signalSourceCmd.setNodeId( m_nodeId );
304     signalSourceCmd.setSubunitType( eST_Unit  );
305     signalSourceCmd.setSubunitId( 0xff );
306
307     signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
308
309     if ( !signalSourceCmd.fire() ) {
310         debugError( "Number of channels command failed\n" );
311         return false;
312     }
313
314     SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
315     SignalSubunitAddress* pSyncPlugSubunitAddress
316         = dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
317     if ( pSyncPlugSubunitAddress ) {
318         debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
319                     ( pSyncPlugSubunitAddress->m_subunitType << 3
320                       | pSyncPlugSubunitAddress->m_subunitId ) << 8
321                     | pSyncPlugSubunitAddress->m_plugId );
322
323         return ( pSyncPlugSubunitAddress->m_subunitType << 3
324                  | pSyncPlugSubunitAddress->m_subunitId ) << 8
325             | pSyncPlugSubunitAddress->m_plugId;
326     }
327
328     debugError( "Could not retrieve sync mode\n" );
329     return 0;
330 }
331
332 int
333 AvDevice::getConfigurationId()
334 {
335     // create a unique configuration id.
336     int id = 0;
337     id = getConfigurationIdSampleRate();
338     id |= ( getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input )
339             + getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) ) << 8;
340     id |= getConfigurationIdSyncMode() << 16;
341
342     return id;
343 }
344
345
346 template <typename T> bool serializeVector( Glib::ustring path,
347                                             Util::IOSerialize& ser,
348                                             const T& vec )
349 {
350     bool result = true; // if vec.size() == 0
351     int i = 0;
352     for ( typename T::const_iterator it = vec.begin(); it != vec.end(); ++it ) {
353         std::ostringstream strstrm;
354         strstrm << path << i;
355         result &= ( *it )->serialize( strstrm.str() + "/", ser );
356         i++;
357     }
358     return result;
359 }
360
361 template <typename T, typename VT> bool deserializeVector( Glib::ustring path,
362                                                            Util::IODeserialize& deser,
363                                                            Unit& avDevice,
364                                                            VT& vec )
365 {
366     int i = 0;
367     bool bFinished = false;
368     do {
369         std::ostringstream strstrm;
370         strstrm << path << i << "/";
371         T* ptr = T::deserialize( strstrm.str(),
372                                  deser,
373                                  avDevice );
374         if ( ptr ) {
375             vec.push_back( ptr );
376             i++;
377         } else {
378             bFinished = true;
379         }
380     } while ( !bFinished );
381
382     return true;
383 }
384
385 bool
386 AvDevice::serialize( Glib::ustring basePath,
387                      Util::IOSerialize& ser ) const
388 {
389
390     bool result;
391     result  = m_pConfigRom->serialize( basePath + "m_pConfigRom/", ser );
392     result &= ser.write( basePath + "m_verboseLevel", getDebugLevel() );
393     result &= m_pPlugManager->serialize( basePath + "Plug", ser ); // serialize all av plugs
394     result &= serializeVector( basePath + "PlugConnection", ser, m_plugConnections );
395     result &= serializeVector( basePath + "Subunit", ser, m_subunits );
396     #warning broken at echoaudio merge
397     //result &= serializeSyncInfoVector( basePath + "SyncInfo", ser, m_syncInfos );
398
399     int i = 0;
400     for ( SyncInfoVector::const_iterator it = m_syncInfos.begin();
401           it != m_syncInfos.end();
402           ++it )
403     {
404         const SyncInfo& info = *it;
405         if ( m_activeSyncInfo == &info ) {
406             result &= ser.write( basePath + "m_activeSyncInfo",  i );
407             break;
408         }
409         i++;
410     }
411
412     result &= serializeOptions( basePath + "Options", ser );
413
414 //     result &= ser.write( basePath + "m_id", id );
415
416     return result;
417 }
418
419 AvDevice*
420 AvDevice::deserialize( Glib::ustring basePath,
421                        Util::IODeserialize& deser,
422                        Ieee1394Service& ieee1394Service )
423 {
424
425 //     ConfigRom *configRom =
426 //         ConfigRom::deserialize( basePath + "m_pConfigRom/", deser, ieee1394Service );
427 //
428 //     if ( !configRom ) {
429 //         return NULL;
430 //     }
431 //
432 //     AvDevice* pDev = new AvDevice(
433 //         std::auto_ptr<ConfigRom>(configRom),
434 //         ieee1394Service, configRom->getNodeId());
435 //
436 //     if ( pDev ) {
437 //         bool result;
438 //         int verboseLevel;
439 //         result  = deser.read( basePath + "m_verboseLevel", verboseLevel );
440 //         setDebugLevel( verboseLevel );
441 //         
442 //         result &= AVC::Unit::deserialize(basePath, pDev, deser, ieee1394Service);
443 //
444 //         result &= deserializeOptions( basePath + "Options", deser, *pDev );
445 //     }
446 //
447 //     return pDev;
448     return NULL;
449 }
450
451 Glib::ustring
452 AvDevice::getCachePath()
453 {
454     Glib::ustring cachePath;
455     char* pCachePath;
456     if ( asprintf( &pCachePath, "%s/cache/libffado/",  CACHEDIR ) < 0 ) {
457         debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
458         cachePath == "/var/cache/libffado/";
459     } else {
460         cachePath = pCachePath;
461         free( pCachePath );
462     }
463     return cachePath;
464 }
465
466 bool
467 AvDevice::loadFromCache()
468 {
469 /*    Glib::ustring sDevicePath = getCachePath() + m_pConfigRom->getGuidString();
470
471     char* configId;
472     asprintf(&configId, "%08x", getConfigurationId() );
473     if ( !configId ) {
474         debugError( "could not create id string\n" );
475         return false;
476     }
477
478     Glib::ustring sFileName = sDevicePath + "/" + configId + ".xml";
479     free( configId );
480     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
481
482     Util::XMLDeserialize deser( sFileName, m_verboseLevel );
483
484     bool result = deserialize( "", deser );
485     if ( result ) {
486         debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
487                      sFileName.c_str() );
488     }
489
490     return result;*/
491     return false;
492 }
493
494 bool
495 AvDevice::saveCache()
496 {
497 //     // the path looks like this:
498 //     // PATH_TO_CACHE + GUID + CONFIGURATION_ID
499 //
500 //     Glib::ustring sDevicePath = getCachePath() + m_pConfigRom->getGuidString();
501 //     struct stat buf;
502 //     if ( stat( sDevicePath.c_str(), &buf ) == 0 ) {
503 //         if ( !S_ISDIR( buf.st_mode ) ) {
504 //             debugError( "\"%s\" is not a directory\n",  sDevicePath.c_str() );
505 //             return false;
506 //         }
507 //     } else {
508 //         if (  mkdir( sDevicePath.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
509 //             debugError( "Could not create \"%s\" directory\n", sDevicePath.c_str() );
510 //             return false;
511 //         }
512 //     }
513 //
514 //     char* configId;
515 //     asprintf(&configId, "%08x", BeBoB::AvDevice::getConfigurationId() );
516 //     if ( !configId ) {
517 //         debugError( "Could not create id string\n" );
518 //         return false;
519 //     }
520 //     Glib::ustring sFileName = sDevicePath + "/" + configId + ".xml";
521 //     free( configId );
522 //     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
523 //
524 //     Util::XMLSerialize ser( sFileName );
525 //     return serialize( "", ser );
526     return false;
527 }
528
529 } // end of namespace
Note: See TracBrowser for help on using the browser.