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

Revision 661, 14.6 kB (checked in by ppalmers, 15 years ago)

- Implement more complete mixer support for the saffire pro
- fix some cleanup issues with control elements

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 "config.h"
25
26 #include "bebob/bebob_avdevice.h"
27 #include "bebob/bebob_avdevice_subunit.h"
28 #include "bebob/bebob_mixer.h"
29
30 #include "bebob/focusrite/focusrite_saffirepro.h"
31 #include "bebob/terratec/terratec_device.h"
32
33 #include "libieee1394/configrom.h"
34 #include "libieee1394/ieee1394service.h"
35
36 #include "genericavc/avc_vendormodel.h"
37
38 #include "libavc/general/avc_plug_info.h"
39 #include "libavc/general/avc_extended_plug_info.h"
40 #include "libavc/general/avc_subunit_info.h"
41 #include "libavc/streamformat/avc_extended_stream_format.h"
42 #include "libutil/cmd_serialize.h"
43 #include "libavc/avc_definitions.h"
44
45 #include "debugmodule/debugmodule.h"
46
47 #include <iostream>
48 #include <sstream>
49 #include <unistd.h>
50 #include <sys/stat.h>
51
52 using namespace AVC;
53
54 namespace BeBoB {
55
56 AvDevice::AvDevice( Ieee1394Service& ieee1394service,
57                     std::auto_ptr< ConfigRom >( configRom ) )
58     : GenericAVC::AvDevice( ieee1394service, configRom )
59     , m_Mixer ( 0 )
60 {
61     debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::AvDevice (NodeID %d)\n",
62                  getConfigRom().getNodeId() );
63
64     // DM1500 based devices seem to upset the linux1394 stack when commands are
65     // sent too fast.
66     if (AVC::AVCCommand::getSleepAfterAVCCommand() < 200) {
67         AVC::AVCCommand::setSleepAfterAVCCommand( 200 );
68     }
69
70 }
71
72 AvDevice::~AvDevice()
73 {
74     destroyMixer();
75 }
76
77 bool
78 AvDevice::probe( ConfigRom& configRom )
79 {
80     unsigned int vendorId = configRom.getNodeVendorId();
81     unsigned int modelId = configRom.getModelId();
82
83     GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_bebob.txt" );
84     if ( vendorModel.parse() ) {
85         return vendorModel.isPresent( vendorId, modelId );
86     }
87
88     return false;
89 }
90
91 FFADODevice *
92 AvDevice::createDevice( Ieee1394Service& ieee1394Service,
93                         std::auto_ptr<ConfigRom>( configRom ))
94 {
95     unsigned int vendorId = configRom->getNodeVendorId();
96     unsigned int modelId = configRom->getModelId();
97
98     switch (vendorId) {
99         case FW_VENDORID_TERRATEC:
100             return new Terratec::PhaseSeriesDevice(ieee1394Service, configRom);
101         case FW_VENDORID_FOCUSRITE:
102             switch(modelId) {
103                 case 0x00000003:
104                 case 0x00000006:
105                     return new Focusrite::SaffireProDevice(ieee1394Service, configRom);
106                 default: // return a plain BeBoB device
107                     return new AvDevice(ieee1394Service, configRom);
108            }
109         default:
110             return new AvDevice(ieee1394Service, configRom);
111     }
112     return NULL;
113 }
114
115 bool
116 AvDevice::discover()
117 {
118     unsigned int vendorId = m_pConfigRom->getNodeVendorId();
119     unsigned int modelId = m_pConfigRom->getModelId();
120
121     GenericAVC::VendorModel vendorModel( SHAREDIR "/ffado_driver_bebob.txt" );
122     if ( vendorModel.parse() ) {
123         m_model = vendorModel.find( vendorId, modelId );
124     }
125
126     if (GenericAVC::VendorModel::isValid(m_model)) {
127         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
128                      m_model.vendor_name.c_str(),
129                      m_model.model_name.c_str());
130     } else return false;
131
132     if ( !Unit::discover() ) {
133         debugError( "Could not discover unit\n" );
134         return false;
135     }
136
137     if((getAudioSubunit( 0 ) == NULL)) {
138         debugError( "Unit doesn't have an Audio subunit.\n");
139         return false;
140     }
141     if((getMusicSubunit( 0 ) == NULL)) {
142         debugError( "Unit doesn't have a Music subunit.\n");
143         return false;
144     }
145
146     if(!buildMixer()) {
147         debugWarning("Could not build mixer\n");
148     }
149     return true;
150 }
151
152 bool
153 AvDevice::buildMixer()
154 {
155     debugOutput(DEBUG_LEVEL_VERBOSE, "Building a generic BeBoB mixer...\n");
156     // create a Mixer
157     // this removes the mixer if it already exists
158     // note: a mixer self-registers to it's parent
159     delete m_Mixer;
160
161     // create the mixer & register it
162     if(getAudioSubunit(0) == NULL) {
163         debugWarning("Could not find audio subunit, mixer not available.\n");
164         m_Mixer = NULL;
165     } else {
166         m_Mixer = new Mixer(*this);
167     }
168     return m_Mixer != NULL;
169 }
170
171 bool
172 AvDevice::destroyMixer()
173 {
174     delete m_Mixer;
175     return true;
176 }
177
178 void
179 AvDevice::showDevice()
180 {
181     debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
182     GenericAVC::AvDevice::showDevice();
183     flushDebugOutput();
184 }
185
186 AVC::Subunit*
187 AvDevice::createSubunit(AVC::Unit& unit,
188                         AVC::ESubunitType type,
189                         AVC::subunit_t id )
190 {
191     AVC::Subunit* s=NULL;
192     switch (type) {
193         case eST_Audio:
194             s=new BeBoB::SubunitAudio(unit, id );
195             break;
196         case eST_Music:
197             s=new BeBoB::SubunitMusic(unit, id );
198             break;
199         default:
200             s=NULL;
201             break;
202     }
203     if(s) s->setVerboseLevel(getDebugLevel());
204     return s;
205 }
206
207
208 AVC::Plug *
209 AvDevice::createPlug( AVC::Unit* unit,
210                       AVC::Subunit* subunit,
211                       AVC::function_block_type_t functionBlockType,
212                       AVC::function_block_type_t functionBlockId,
213                       AVC::Plug::EPlugAddressType plugAddressType,
214                       AVC::Plug::EPlugDirection plugDirection,
215                       AVC::plug_id_t plugId )
216 {
217
218     Plug *p= new BeBoB::Plug( unit,
219                               subunit,
220                               functionBlockType,
221                               functionBlockId,
222                               plugAddressType,
223                               plugDirection,
224                               plugId );
225     if (p) p->setVerboseLevel(getDebugLevel());
226     return p;
227 }
228
229 bool
230 AvDevice::propagatePlugInfo() {
231     // we don't have to propagate since we discover things
232     // another way
233     debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
234     return true;
235 }
236
237
238 int
239 AvDevice::getConfigurationIdSampleRate()
240 {
241     ExtendedStreamFormatCmd extStreamFormatCmd( *m_p1394Service );
242     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
243     extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
244                                                     PlugAddress::ePAM_Unit,
245                                                     unitPlugAddress ) );
246
247     extStreamFormatCmd.setNodeId( getNodeId() );
248     extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
249     extStreamFormatCmd.setVerbose( true );
250
251     if ( !extStreamFormatCmd.fire() ) {
252         debugError( "Stream format command failed\n" );
253         return false;
254     }
255
256     FormatInformation* formatInfo =
257         extStreamFormatCmd.getFormatInformation();
258     FormatInformationStreamsCompound* compoundStream
259         = dynamic_cast< FormatInformationStreamsCompound* > (
260             formatInfo->m_streams );
261     if ( compoundStream ) {
262         debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
263                     compoundStream->m_samplingFrequency );
264         return compoundStream->m_samplingFrequency;
265     }
266
267     debugError( "Could not retrieve sample rate\n" );
268     return 0;
269 }
270
271 int
272 AvDevice::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
273 {
274     ExtendedPlugInfoCmd extPlugInfoCmd( *m_p1394Service );
275     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
276                                      getNodeId() );
277     extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
278                                                 PlugAddress::ePAM_Unit,
279                                                 unitPlugAddress ) );
280     extPlugInfoCmd.setNodeId( getNodeId() );
281     extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
282     extPlugInfoCmd.setVerbose( true );
283     ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
284         ExtendedPlugInfoInfoType::eIT_NoOfChannels );
285     extendedPlugInfoInfoType.initialize();
286     extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
287
288     if ( !extPlugInfoCmd.fire() ) {
289         debugError( "Number of channels command failed\n" );
290         return false;
291     }
292
293     ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
294     if ( infoType
295          && infoType->m_plugNrOfChns )
296     {
297         debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
298                     infoType->m_plugNrOfChns->m_nrOfChannels );
299         return infoType->m_plugNrOfChns->m_nrOfChannels;
300     }
301
302     debugError( "Could not retrieve number of channels\n" );
303     return 0;
304 }
305
306 int
307 AvDevice::getConfigurationIdSyncMode()
308 {
309     SignalSourceCmd signalSourceCmd( *m_p1394Service );
310     SignalUnitAddress signalUnitAddr;
311     signalUnitAddr.m_plugId = 0x01;
312     signalSourceCmd.setSignalDestination( signalUnitAddr );
313     signalSourceCmd.setNodeId( getNodeId() );
314     signalSourceCmd.setSubunitType( eST_Unit  );
315     signalSourceCmd.setSubunitId( 0xff );
316
317     signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
318
319     if ( !signalSourceCmd.fire() ) {
320         debugError( "Number of channels command failed\n" );
321         return false;
322     }
323
324     SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
325     SignalSubunitAddress* pSyncPlugSubunitAddress
326         = dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
327     if ( pSyncPlugSubunitAddress ) {
328         debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
329                     ( pSyncPlugSubunitAddress->m_subunitType << 3
330                       | pSyncPlugSubunitAddress->m_subunitId ) << 8
331                     | pSyncPlugSubunitAddress->m_plugId );
332
333         return ( pSyncPlugSubunitAddress->m_subunitType << 3
334                  | pSyncPlugSubunitAddress->m_subunitId ) << 8
335             | pSyncPlugSubunitAddress->m_plugId;
336     }
337
338     debugError( "Could not retrieve sync mode\n" );
339     return 0;
340 }
341
342 int
343 AvDevice::getConfigurationId()
344 {
345     // create a unique configuration id.
346     int id = 0;
347     id = getConfigurationIdSampleRate();
348     id |= ( getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input )
349             + getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) ) << 8;
350     id |= getConfigurationIdSyncMode() << 16;
351
352     return id;
353 }
354
355 bool
356 AvDevice::serialize( Glib::ustring basePath,
357                      Util::IOSerialize& ser ) const
358 {
359     bool result;
360     result  = GenericAVC::AvDevice::serialize( basePath, ser );
361     return result;
362 }
363
364 bool
365 AvDevice::deserialize( Glib::ustring basePath,
366                        Util::IODeserialize& deser )
367 {
368     bool result;
369     result  = GenericAVC::AvDevice::deserialize( basePath, deser );
370     return result;
371 }
372
373 Glib::ustring
374 AvDevice::getCachePath()
375 {
376     Glib::ustring cachePath;
377     char* pCachePath;
378
379     string path = CACHEDIR;
380     if ( path.size() && path[0] == '~' ) {
381         path.erase( 0, 1 ); // remove ~
382         path.insert( 0, getenv( "HOME" ) ); // prepend the home path
383     }
384
385     if ( asprintf( &pCachePath, "%s/cache/",  path.c_str() ) < 0 ) {
386         debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
387         cachePath == "/var/cache/libffado/";
388     } else {
389         cachePath = pCachePath;
390         free( pCachePath );
391     }
392     return cachePath;
393 }
394
395 bool
396 AvDevice::loadFromCache()
397 {
398     // XXX disable this part as long it is not correctly working
399     return false;
400
401     Glib::ustring sDevicePath = getCachePath() + m_pConfigRom->getGuidString();
402
403     char* configId;
404     asprintf(&configId, "%08x", getConfigurationId() );
405     if ( !configId ) {
406         debugError( "could not create id string\n" );
407         return false;
408     }
409
410     Glib::ustring sFileName = sDevicePath + "/" + configId + ".xml";
411     free( configId );
412     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
413
414     struct stat buf;
415     if ( stat( sFileName.c_str(), &buf ) != 0 ) {
416         debugOutput( DEBUG_LEVEL_NORMAL,  "\"%s\" does not exist\n",  sFileName.c_str() );
417         return false;
418     } else {
419         if ( !S_ISREG( buf.st_mode ) ) {
420             debugOutput( DEBUG_LEVEL_NORMAL,  "\"%s\" is not a regular file\n",  sFileName.c_str() );
421             return false;
422         }
423     }
424
425     Util::XMLDeserialize deser( sFileName, getDebugLevel() );
426
427     bool result = deserialize( "", deser );
428     if ( result ) {
429         debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
430                      sFileName.c_str() );
431     }
432
433     // XXX only for testing purpose here. Can be removed when loadFromCache works
434     AVC::Plug* inputPlug = getPlugById( m_pcrPlugs, Plug::eAPD_Input, 0 );
435     if ( !inputPlug ) {
436         debugError( "loadFromCache: Could not retrieve iso input plug 0\n" );
437     }
438
439     return result;
440 }
441
442 bool
443 AvDevice::saveCache()
444 {
445     // the path looks like this:
446     // PATH_TO_CACHE + GUID + CONFIGURATION_ID
447     string tmp_path = getCachePath() + m_pConfigRom->getGuidString();
448
449     // the following piece should do something like
450     // 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
451     vector<string> tokens;
452     tokenize( tmp_path, tokens, "/" );
453     string path;
454     for ( vector<string>::const_iterator it = tokens.begin();
455           it != tokens.end();
456           ++it )
457     {
458         path +=  "/" + *it;
459
460         struct stat buf;
461         if ( stat( path.c_str(), &buf ) == 0 ) {
462             if ( !S_ISDIR( buf.st_mode ) ) {
463                 debugError( "\"%s\" is not a directory\n",  path.c_str() );
464                 return false;
465             }
466         } else {
467             if (  mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
468                 debugError( "Could not create \"%s\" directory\n", path.c_str() );
469                 return false;
470             }
471         }
472     }
473
474     // come up with an unique file name for the current settings
475     char* configId;
476     asprintf(&configId, "%08x", BeBoB::AvDevice::getConfigurationId() );
477     if ( !configId ) {
478         debugError( "Could not create id string\n" );
479         return false;
480     }
481     string filename = path + "/" + configId + ".xml";
482     free( configId );
483     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
484
485     Util::XMLSerialize ser( filename );
486     return serialize( "", ser );
487 }
488
489 } // end of namespace
Note: See TracBrowser for help on using the browser.