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

Revision 739, 14.6 kB (checked in by ppalmers, 16 years ago)

- Adapt the ffado external API (upgrade to v3)

NEEDS NEW JACK BACKEND

- simplify FFADODevice constructor even more
- implement first framework support for supporting multiple adapters.

currently all firewire adapters are scanned for supported devices unless specified otherwise
however attaching devices to separate adapters is not supported. using multiple adapters at
that are connected together might work.

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