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

Revision 630, 13.8 kB (checked in by wagi, 17 years ago)

Some more fixing of the cashing code. The loading is still disabled because it seems not to work right. But at least it doesn't crash anymore. Some further debugging is
needed.

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