root/branches/libffado-2.0/src/bebob/bebob_avdevice.cpp

Revision 1299, 21.8 kB (checked in by ppalmers, 16 years ago)

implement configuration file mechanism to ease device support and packaging. this mechanism replaces the vendormodel text files. it loads two files, one system-wide and a second in the user directory. the user config file takes precedence. this should ease adding
device id's on a per-user base. it also allows for other settings to be carried by the same 'Configuration' object (present in the devicemanager). The idea is that it will also replace the OptionContainer? mechanism on the long run, and allow for easy integration
of system options (e.g. the pre-transmit amount).

Line 
1 /*
2  * Copyright (C) 2005-2008 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 program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "config.h"
25
26 #include "devicemanager.h"
27 #include "bebob/bebob_avdevice.h"
28 #include "bebob/bebob_avdevice_subunit.h"
29 #include "bebob/bebob_mixer.h"
30
31 #include "bebob/focusrite/focusrite_saffire.h"
32 #include "bebob/focusrite/focusrite_saffirepro.h"
33 #include "bebob/terratec/terratec_device.h"
34 #include "bebob/mackie/onyxmixer.h"
35 #include "bebob/edirol/edirol_fa101.h"
36 #include "bebob/edirol/edirol_fa66.h"
37 #include "bebob/esi/quatafire610.h"
38
39 #include "libieee1394/configrom.h"
40 #include "libieee1394/ieee1394service.h"
41
42 #include "libavc/general/avc_plug_info.h"
43 #include "libavc/general/avc_extended_plug_info.h"
44 #include "libavc/general/avc_subunit_info.h"
45 #include "libavc/streamformat/avc_extended_stream_format.h"
46 #include "libutil/cmd_serialize.h"
47 #include "libavc/avc_definitions.h"
48
49 #include "debugmodule/debugmodule.h"
50
51 #include <iostream>
52 #include <sstream>
53 #include <unistd.h>
54 #include <cstdlib>
55 #include <cstring>
56 #include <sys/stat.h>
57
58 using namespace AVC;
59
60 namespace BeBoB {
61
62 AvDevice::AvDevice( DeviceManager& d, std::auto_ptr< ConfigRom >( configRom ) )
63     : GenericAVC::AvDevice( d, configRom )
64     , m_Mixer ( 0 )
65 {
66     debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::AvDevice (NodeID %d)\n",
67                  getConfigRom().getNodeId() );
68
69     // DM1500 based devices seem to upset the linux1394 stack when commands are
70     // sent too fast.
71     if (AVC::AVCCommand::getSleepAfterAVCCommand() < 200) {
72         AVC::AVCCommand::setSleepAfterAVCCommand( 200 );
73     }
74
75 }
76
77 AvDevice::~AvDevice()
78 {
79     destroyMixer();
80 }
81
82 bool
83 AvDevice::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
84 {
85     if(generic) {
86         return false;
87         // try a bebob-specific command to check for the firmware
88         ExtendedPlugInfoCmd extPlugInfoCmd( configRom.get1394Service() );
89         UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
90                                          configRom.getNodeId() );
91         extPlugInfoCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
92                                                     PlugAddress::ePAM_Unit,
93                                                     unitPlugAddress ) );
94         extPlugInfoCmd.setNodeId( configRom.getNodeId() );
95         extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
96         extPlugInfoCmd.setVerbose( configRom.getVerboseLevel() );
97         ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
98             ExtendedPlugInfoInfoType::eIT_NoOfChannels );
99         extendedPlugInfoInfoType.initialize();
100         extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
101    
102         if ( !extPlugInfoCmd.fire() ) {
103             debugError( "Number of channels command failed\n" );
104             return false;
105         }
106    
107         ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
108         if ( infoType
109             && infoType->m_plugNrOfChns )
110         {
111             return true;
112         }
113         return false;
114     } else {
115         // check if device is in supported devices list
116         unsigned int vendorId = configRom.getNodeVendorId();
117         unsigned int modelId = configRom.getModelId();
118
119         Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
120         return c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB;
121     }
122 }
123
124 FFADODevice *
125 AvDevice::createDevice(DeviceManager& d, std::auto_ptr<ConfigRom>( configRom ))
126 {
127     unsigned int vendorId = configRom->getNodeVendorId();
128     unsigned int modelId = configRom->getModelId();
129
130     switch (vendorId) {
131         case FW_VENDORID_MACKIE:
132             if (modelId == 0x00010065 ) {
133                 return new Mackie::OnyxMixerDevice(d, configRom);
134             }
135         case FW_VENDORID_EDIROL:
136             switch (modelId) {
137                 case 0x00010048:
138                     return new Edirol::EdirolFa101Device(d, configRom);
139                 case 0x00010049:
140                     return new Edirol::EdirolFa66Device(d, configRom);
141                 default:
142                     return new AvDevice(d, configRom);
143             }
144         case FW_VENDORID_ESI:
145             if (modelId == 0x00010064) {
146                 return new ESI::QuataFireDevice(d, configRom);
147             }
148             break;
149         case FW_VENDORID_TERRATEC:
150             switch(modelId) {
151                 case 0x00000003:
152                     return new Terratec::Phase88Device(d, configRom);
153                 default: // return a plain BeBoB device
154                     return new AvDevice(d, configRom);
155             }
156         case FW_VENDORID_FOCUSRITE:
157             switch(modelId) {
158                 case 0x00000003:
159                 case 0x00000006:
160                     return new Focusrite::SaffireProDevice(d, configRom);
161                 case 0x00000000:
162                     return new Focusrite::SaffireDevice(d, configRom);
163                 default: // return a plain BeBoB device
164                     return new AvDevice(d, configRom);
165            }
166         default:
167             return new AvDevice(d, configRom);
168     }
169     return NULL;
170 }
171
172 #define BEBOB_CHECK_AND_ADD_SR(v, x) \
173     { if(supportsSamplingFrequency(x)) \
174       v.push_back(x); }
175 bool
176 AvDevice::discover()
177 {
178     unsigned int vendorId = getConfigRom().getNodeVendorId();
179     unsigned int modelId = getConfigRom().getModelId();
180
181     Util::Configuration &c = getDeviceManager().getConfiguration();
182     Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
183
184     if (c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB) {
185         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
186                      vme.vendor_name.c_str(),
187                      vme.model_name.c_str());
188     } else {
189         debugWarning("Using generic BeBoB support for unsupported device '%s %s'\n",
190                      getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
191     }
192
193     if ( !Unit::discover() ) {
194         debugError( "Could not discover unit\n" );
195         return false;
196     }
197
198     if((getAudioSubunit( 0 ) == NULL)) {
199         debugError( "Unit doesn't have an Audio subunit.\n");
200         return false;
201     }
202     if((getMusicSubunit( 0 ) == NULL)) {
203         debugError( "Unit doesn't have a Music subunit.\n");
204         return false;
205     }
206
207     if(!buildMixer()) {
208         debugWarning("Could not build mixer\n");
209     }
210     return true;
211 }
212
213 bool
214 AvDevice::buildMixer()
215 {
216     debugOutput(DEBUG_LEVEL_VERBOSE, "Building a generic BeBoB mixer...\n");
217     // create a Mixer
218     // this removes the mixer if it already exists
219     // note: a mixer self-registers to it's parent
220     delete m_Mixer;
221
222     // create the mixer & register it
223     if(getAudioSubunit(0) == NULL) {
224         debugWarning("Could not find audio subunit, mixer not available.\n");
225         m_Mixer = NULL;
226     } else {
227         m_Mixer = new Mixer(*this);
228     }
229     if (m_Mixer) m_Mixer->setVerboseLevel(getDebugLevel());
230     return m_Mixer != NULL;
231 }
232
233 bool
234 AvDevice::destroyMixer()
235 {
236     delete m_Mixer;
237     return true;
238 }
239
240 bool
241 AvDevice::setSelectorFBValue(int id, int value) {
242     FunctionBlockCmd fbCmd( get1394Service(),
243                             FunctionBlockCmd::eFBT_Selector,
244                             id,
245                             FunctionBlockCmd::eCA_Current );
246     fbCmd.setNodeId( getNodeId() );
247     fbCmd.setSubunitId( 0x00 );
248     fbCmd.setCommandType( AVCCommand::eCT_Control );
249     fbCmd.m_pFBSelector->m_inputFbPlugNumber = (value & 0xFF);
250     fbCmd.setVerboseLevel( getDebugLevel() );
251
252     if ( !fbCmd.fire() ) {
253         debugError( "cmd failed\n" );
254         return false;
255     }
256
257 //     if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
258 //         Util::CoutSerializer se;
259 //         fbCmd.serialize( se );
260 //     }
261 //     
262     if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
263         debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
264     }
265
266     return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
267 }
268
269 int
270 AvDevice::getSelectorFBValue(int id) {
271
272     FunctionBlockCmd fbCmd( get1394Service(),
273                             FunctionBlockCmd::eFBT_Selector,
274                             id,
275                             FunctionBlockCmd::eCA_Current );
276     fbCmd.setNodeId( getNodeId() );
277     fbCmd.setSubunitId( 0x00 );
278     fbCmd.setCommandType( AVCCommand::eCT_Status );
279     fbCmd.m_pFBSelector->m_inputFbPlugNumber = 0xFF;
280     fbCmd.setVerboseLevel( getDebugLevel() );
281
282     if ( !fbCmd.fire() ) {
283         debugError( "cmd failed\n" );
284         return -1;
285     }
286    
287 //     if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
288 //         Util::CoutSerializer se;
289 //         fbCmd.serialize( se );
290 //     }
291
292     if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
293         debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
294     }
295    
296     return fbCmd.m_pFBSelector->m_inputFbPlugNumber;
297 }
298
299 bool
300 AvDevice::setFeatureFBVolumeValue(int id, int channel, int v) {
301
302     FunctionBlockCmd fbCmd( get1394Service(),
303                             FunctionBlockCmd::eFBT_Feature,
304                             id,
305                             FunctionBlockCmd::eCA_Current );
306     fbCmd.setNodeId( getNodeId() );
307     fbCmd.setSubunitId( 0x00 );
308     fbCmd.setCommandType( AVCCommand::eCT_Control );
309     fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
310     fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
311     fbCmd.m_pFBFeature->m_pVolume->m_volume = v;
312     fbCmd.setVerboseLevel( getDebugLevel() );
313
314     if ( !fbCmd.fire() ) {
315         debugError( "cmd failed\n" );
316         return false;
317     }
318
319 //     if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
320 //         Util::CoutSerializer se;
321 //         fbCmd.serialize( se );
322 //     }
323    
324     if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
325         debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
326     }
327
328     return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
329 }
330
331 int
332 AvDevice::getFeatureFBVolumeValue(int id, int channel) {
333     FunctionBlockCmd fbCmd( get1394Service(),
334                             FunctionBlockCmd::eFBT_Feature,
335                             id,
336                             FunctionBlockCmd::eCA_Current );
337     fbCmd.setNodeId( getNodeId() );
338     fbCmd.setSubunitId( 0x00 );
339     fbCmd.setCommandType( AVCCommand::eCT_Status );
340     fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
341     fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
342     fbCmd.m_pFBFeature->m_pVolume->m_volume = 0;
343     fbCmd.setVerboseLevel( getDebugLevel() );
344
345     if ( !fbCmd.fire() ) {
346         debugError( "cmd failed\n" );
347         return 0;
348     }
349    
350 //     if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
351 //         Util::CoutSerializer se;
352 //         fbCmd.serialize( se );
353 //     }
354
355     if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
356         debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
357     }
358    
359     int16_t volume=(int16_t)(fbCmd.m_pFBFeature->m_pVolume->m_volume);
360    
361     return volume;
362 }
363
364 void
365 AvDevice::showDevice()
366 {
367     debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
368     GenericAVC::AvDevice::showDevice();
369     flushDebugOutput();
370 }
371
372 void
373 AvDevice::setVerboseLevel(int l)
374 {
375     if (m_Mixer) m_Mixer->setVerboseLevel( l );
376     GenericAVC::AvDevice::setVerboseLevel( l );
377     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
378 }
379
380 AVC::Subunit*
381 AvDevice::createSubunit(AVC::Unit& unit,
382                         AVC::ESubunitType type,
383                         AVC::subunit_t id )
384 {
385     AVC::Subunit* s=NULL;
386     switch (type) {
387         case eST_Audio:
388             s=new BeBoB::SubunitAudio(unit, id );
389             break;
390         case eST_Music:
391             s=new BeBoB::SubunitMusic(unit, id );
392             break;
393         default:
394             s=NULL;
395             break;
396     }
397     if(s) s->setVerboseLevel(getDebugLevel());
398     return s;
399 }
400
401
402 AVC::Plug *
403 AvDevice::createPlug( AVC::Unit* unit,
404                       AVC::Subunit* subunit,
405                       AVC::function_block_type_t functionBlockType,
406                       AVC::function_block_type_t functionBlockId,
407                       AVC::Plug::EPlugAddressType plugAddressType,
408                       AVC::Plug::EPlugDirection plugDirection,
409                       AVC::plug_id_t plugId,
410                       int globalId )
411 {
412
413     Plug *p= new BeBoB::Plug( unit,
414                               subunit,
415                               functionBlockType,
416                               functionBlockId,
417                               plugAddressType,
418                               plugDirection,
419                               plugId,
420                               globalId );
421     if (p) p->setVerboseLevel(getDebugLevel());
422     return p;
423 }
424
425 bool
426 AvDevice::propagatePlugInfo() {
427     // we don't have to propagate since we discover things
428     // another way
429     debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
430     return true;
431 }
432
433 uint8_t
434 AvDevice::getConfigurationIdSampleRate()
435 {
436     ExtendedStreamFormatCmd extStreamFormatCmd( get1394Service() );
437     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
438     extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
439                                                     PlugAddress::ePAM_Unit,
440                                                     unitPlugAddress ) );
441
442     extStreamFormatCmd.setNodeId( getNodeId() );
443     extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
444     extStreamFormatCmd.setVerbose( getDebugLevel() );
445
446     if ( !extStreamFormatCmd.fire() ) {
447         debugError( "Stream format command failed\n" );
448         return 0;
449     }
450
451     FormatInformation* formatInfo =
452         extStreamFormatCmd.getFormatInformation();
453     FormatInformationStreamsCompound* compoundStream
454         = dynamic_cast< FormatInformationStreamsCompound* > (
455             formatInfo->m_streams );
456     if ( compoundStream ) {
457         debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
458                     compoundStream->m_samplingFrequency );
459         return compoundStream->m_samplingFrequency;
460     }
461
462     debugError( "Could not retrieve sample rate\n" );
463     return 0;
464 }
465
466 uint8_t
467 AvDevice::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
468 {
469     ExtendedPlugInfoCmd extPlugInfoCmd( get1394Service() );
470     UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
471                                      0 );
472     extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
473                                                 PlugAddress::ePAM_Unit,
474                                                 unitPlugAddress ) );
475     extPlugInfoCmd.setNodeId( getNodeId() );
476     extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
477     extPlugInfoCmd.setVerbose( getDebugLevel() );
478     ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
479         ExtendedPlugInfoInfoType::eIT_NoOfChannels );
480     extendedPlugInfoInfoType.initialize();
481     extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
482
483     if ( !extPlugInfoCmd.fire() ) {
484         debugError( "Number of channels command failed\n" );
485         return 0;
486     }
487
488     ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
489     if ( infoType
490          && infoType->m_plugNrOfChns )
491     {
492         debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
493                     infoType->m_plugNrOfChns->m_nrOfChannels );
494         return infoType->m_plugNrOfChns->m_nrOfChannels;
495     }
496
497     debugError( "Could not retrieve number of channels\n" );
498     return 0;
499 }
500
501 uint16_t
502 AvDevice::getConfigurationIdSyncMode()
503 {
504     SignalSourceCmd signalSourceCmd( get1394Service() );
505     SignalUnitAddress signalUnitAddr;
506     signalUnitAddr.m_plugId = 0x01;
507     signalSourceCmd.setSignalDestination( signalUnitAddr );
508     signalSourceCmd.setNodeId( getNodeId() );
509     signalSourceCmd.setSubunitType( eST_Unit  );
510     signalSourceCmd.setSubunitId( 0xff );
511     signalSourceCmd.setVerbose( getDebugLevel() );
512
513     signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
514
515     if ( !signalSourceCmd.fire() ) {
516         debugError( "Signal source command failed\n" );
517         return 0;
518     }
519
520     SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
521     SignalSubunitAddress* pSyncPlugSubunitAddress
522         = dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
523     if ( pSyncPlugSubunitAddress ) {
524         debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
525                     ( pSyncPlugSubunitAddress->m_subunitType << 3
526                       | pSyncPlugSubunitAddress->m_subunitId ) << 8
527                     | pSyncPlugSubunitAddress->m_plugId );
528
529         return ( pSyncPlugSubunitAddress->m_subunitType << 3
530                  | pSyncPlugSubunitAddress->m_subunitId ) << 8
531             | pSyncPlugSubunitAddress->m_plugId;
532     }
533
534     SignalUnitAddress* pSyncPlugUnitAddress
535       = dynamic_cast<SignalUnitAddress*>( pSyncPlugSignalAddress );
536     if ( pSyncPlugUnitAddress ) {
537         debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
538                       0xff << 8 | pSyncPlugUnitAddress->m_plugId );
539
540         return ( 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
541     }
542
543     debugError( "Could not retrieve sync mode\n" );
544     return 0;
545 }
546
547 uint64_t
548 AvDevice::getConfigurationId()
549 {
550     // create a unique configuration id.
551     uint64_t id = 0;
552     id = getConfigurationIdSampleRate();
553     id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input ) << 8;
554     id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) << 16;
555     id |= ((uint64_t)getConfigurationIdSyncMode()) << 24;
556     return id;
557 }
558
559 bool
560 AvDevice::serialize( std::string basePath,
561                      Util::IOSerialize& ser ) const
562 {
563     bool result;
564     result  = GenericAVC::AvDevice::serialize( basePath, ser );
565     return result;
566 }
567
568 bool
569 AvDevice::deserialize( std::string basePath,
570                        Util::IODeserialize& deser )
571 {
572     bool result;
573     result  = GenericAVC::AvDevice::deserialize( basePath, deser );
574     return result;
575 }
576
577 std::string
578 AvDevice::getCachePath()
579 {
580     std::string cachePath;
581     char* pCachePath;
582
583     string path = CACHEDIR;
584     if ( path.size() && path[0] == '~' ) {
585         path.erase( 0, 1 ); // remove ~
586         path.insert( 0, getenv( "HOME" ) ); // prepend the home path
587     }
588
589     if ( asprintf( &pCachePath, "%s/cache/",  path.c_str() ) < 0 ) {
590         debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
591         cachePath == "/var/cache/libffado/";
592     } else {
593         cachePath = pCachePath;
594         free( pCachePath );
595     }
596     return cachePath;
597 }
598
599 bool
600 AvDevice::loadFromCache()
601 {
602     std::string sDevicePath = getCachePath() + getConfigRom().getGuidString();
603
604     char* configId;
605     asprintf(&configId, "%016llx", getConfigurationId() );
606     if ( !configId ) {
607         debugError( "could not create id string\n" );
608         return false;
609     }
610
611     std::string sFileName = sDevicePath + "/" + configId + ".xml";
612     free( configId );
613     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
614
615     struct stat buf;
616     if ( stat( sFileName.c_str(), &buf ) != 0 ) {
617         debugOutput( DEBUG_LEVEL_NORMAL,  "\"%s\" does not exist\n",  sFileName.c_str() );
618         return false;
619     } else {
620         if ( !S_ISREG( buf.st_mode ) ) {
621             debugOutput( DEBUG_LEVEL_NORMAL,  "\"%s\" is not a regular file\n",  sFileName.c_str() );
622             return false;
623         }
624     }
625
626     Util::XMLDeserialize deser( sFileName, getDebugLevel() );
627
628     if (!deser.isValid()) {
629         debugOutput( DEBUG_LEVEL_NORMAL, "cache not valid: %s\n",
630                      sFileName.c_str() );
631         return false;
632     }
633
634     bool result = deserialize( "", deser );
635     if ( result ) {
636         debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
637                      sFileName.c_str() );
638     }
639
640     if(result) {
641         buildMixer();
642     }
643
644     return result;
645 }
646
647 bool
648 AvDevice::saveCache()
649 {
650     // the path looks like this:
651     // PATH_TO_CACHE + GUID + CONFIGURATION_ID
652     string tmp_path = getCachePath() + getConfigRom().getGuidString();
653
654     // the following piece should do something like
655     // 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
656     vector<string> tokens;
657     tokenize( tmp_path, tokens, "/" );
658     string path;
659     for ( vector<string>::const_iterator it = tokens.begin();
660           it != tokens.end();
661           ++it )
662     {
663         path +=  "/" + *it;
664
665         struct stat buf;
666         if ( stat( path.c_str(), &buf ) == 0 ) {
667             if ( !S_ISDIR( buf.st_mode ) ) {
668                 debugError( "\"%s\" is not a directory\n",  path.c_str() );
669                 return false;
670             }
671         } else {
672             if (  mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
673                 debugError( "Could not create \"%s\" directory\n", path.c_str() );
674                 return false;
675             }
676         }
677     }
678
679     // come up with an unique file name for the current settings
680     char* configId;
681     asprintf(&configId, "%016llx", BeBoB::AvDevice::getConfigurationId() );
682     if ( !configId ) {
683         debugError( "Could not create id string\n" );
684         return false;
685     }
686     string filename = path + "/" + configId + ".xml";
687     free( configId );
688     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
689
690     Util::XMLSerialize ser( filename );
691     return serialize( "", ser );
692 }
693
694 } // end of namespace
Note: See TracBrowser for help on using the browser.