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

Revision 637, 14.1 kB (checked in by wagi, 15 years ago)

- some code cleanup (whitespace, unnecessary ';' removed, code indention, ...)
- loadFromCache: problem identified why it doesn't work. The PCPLugs and ExternaPlugs? in
AVC::Unit are not deserialized.

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     // XXX only for testing purpose here. Can be removed when loadFromCache works
410     AVC::Plug* inputPlug = getPlugById( m_pcrPlugs, Plug::eAPD_Input, 0 );
411     if ( !inputPlug ) {
412         debugError( "loadFromCache: Could not retrieve iso input plug 0\n" );
413     }
414
415     return result;
416 }
417
418 bool
419 AvDevice::saveCache()
420 {
421     // the path looks like this:
422     // PATH_TO_CACHE + GUID + CONFIGURATION_ID
423     string tmp_path = getCachePath() + m_pConfigRom->getGuidString();
424
425     // the following piece should do something like
426     // 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
427     vector<string> tokens;
428     tokenize( tmp_path, tokens, "/" );
429     string path;
430     for ( vector<string>::const_iterator it = tokens.begin();
431           it != tokens.end();
432           ++it )
433     {
434         path +=  "/" + *it;
435
436         struct stat buf;
437         if ( stat( path.c_str(), &buf ) == 0 ) {
438             if ( !S_ISDIR( buf.st_mode ) ) {
439                 debugError( "\"%s\" is not a directory\n",  path.c_str() );
440                 return false;
441             }
442         } else {
443             if (  mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
444                 debugError( "Could not create \"%s\" directory\n", path.c_str() );
445                 return false;
446             }
447         }
448     }
449
450     // come up with an unique file name for the current settings
451     char* configId;
452     asprintf(&configId, "%08x", BeBoB::AvDevice::getConfigurationId() );
453     if ( !configId ) {
454         debugError( "Could not create id string\n" );
455         return false;
456     }
457     string filename = path + "/" + configId + ".xml";
458     free( configId );
459     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
460
461     Util::XMLSerialize ser( filename );
462     return serialize( "", ser );
463 }
464
465 } // end of namespace
Note: See TracBrowser for help on using the browser.