root/trunk/libffado/src/devicemanager.cpp

Revision 525, 17.8 kB (checked in by jwoithe, 14 years ago)

The new device cache code breaks things for non-AVC interfaces such as the MOTU. Make certain that the cache code (which uses AVC commands) is only used by BeBoB devices. The solution in this patch may need revisiting but at least it restores functionality for now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Copyright (C) 2005-2007 by Daniel Wagner
3  * Copyright (C) 2005-2007 by Pieter Palmers
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License version 2.1, as published by the Free Software Foundation;
13  *
14  * This library 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 GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  * MA 02110-1301 USA
23  */
24
25 #include "fbtypes.h"
26
27 #include "devicemanager.h"
28 #include "iavdevice.h"
29
30 #include "libieee1394/configrom.h"
31 #include "libieee1394/ieee1394service.h"
32
33 #include "libstreaming/StreamProcessor.h"
34
35 #include "debugmodule/debugmodule.h"
36
37 #ifdef ENABLE_BEBOB
38 #include "bebob/bebob_avdevice.h"
39 #include "maudio/maudio_avdevice.h"
40 #endif
41
42 #ifdef ENABLE_BOUNCE
43 #include "bounce/bounce_avdevice.h"
44 #include "bounce/bounce_slave_avdevice.h"
45 #endif
46
47 #ifdef ENABLE_MOTU
48 #include "motu/motu_avdevice.h"
49 #endif
50
51 #ifdef ENABLE_RME
52 #include "rme/rme_avdevice.h"
53 #endif
54
55 #ifdef ENABLE_DICE
56 #include "dice/dice_avdevice.h"
57 #endif
58
59 #ifdef ENABLE_METRIC_HALO
60 #include "metrichalo/mh_avdevice.h"
61 #endif
62
63 #include <iostream>
64 #include <sstream>
65 #include <unistd.h>
66 #include <sys/stat.h>
67
68 using namespace std;
69
70 IMPL_DEBUG_MODULE( DeviceManager, DeviceManager, DEBUG_LEVEL_NORMAL );
71
72 DeviceManager::DeviceManager()
73     : OscNode("devicemanager")
74     , m_1394Service( 0 )
75     , m_oscServer( NULL )
76     , m_verboseLevel( DEBUG_LEVEL_NORMAL )
77 {
78     addOption(Util::OptionContainer::Option("slaveMode",false));
79     addOption(Util::OptionContainer::Option("snoopMode",false));
80 }
81
82 DeviceManager::~DeviceManager()
83 {
84     if (m_oscServer) {
85         m_oscServer->stop();
86         delete m_oscServer;
87     }
88
89     for ( IAvDeviceVectorIterator it = m_avDevices.begin();
90           it != m_avDevices.end();
91           ++it )
92     {
93         delete *it;
94     }
95
96     delete m_1394Service;
97 }
98
99 void
100 DeviceManager::setVerboseLevel(int l)
101 {
102     m_verboseLevel=l;
103     setDebugLevel(l);
104
105     if (m_1394Service) m_1394Service->setVerboseLevel(l);
106     if (m_oscServer) m_oscServer->setVerboseLevel(l);
107     OscNode::setVerboseLevel(l);
108
109     for ( IAvDeviceVectorIterator it = m_avDevices.begin();
110           it != m_avDevices.end();
111           ++it )
112     {
113         (*it)->setVerboseLevel(l);
114     }
115 }
116
117 bool
118 DeviceManager::initialize( int port )
119 {
120     m_1394Service = new Ieee1394Service();
121     if ( !m_1394Service ) {
122         debugFatal( "Could not create Ieee1349Service object\n" );
123         return false;
124     }
125
126     if ( !m_1394Service->initialize( port ) ) {
127         debugFatal( "Could not initialize Ieee1349Service object\n" );
128         delete m_1394Service;
129         m_1394Service = 0;
130         return false;
131     }
132
133     m_oscServer = new OSC::OscServer("17820");
134
135     if (!m_oscServer) {
136         debugFatal("failed to create osc server\n");
137         delete m_1394Service;
138         m_1394Service = 0;
139         return false;
140     }
141
142     if (!m_oscServer->init()) {
143         debugFatal("failed to init osc server\n");
144         delete m_oscServer;
145         m_oscServer = NULL;
146         delete m_1394Service;
147         m_1394Service = 0;
148         return false;
149     }
150
151     if (!m_oscServer->registerAtRootNode(this)) {
152         debugFatal("failed to register devicemanager at server\n");
153         delete m_oscServer;
154         m_oscServer = NULL;
155         delete m_1394Service;
156         m_1394Service = 0;
157         return false;
158     }
159
160     if (!m_oscServer->start()) {
161         debugFatal("failed to start osc server\n");
162         delete m_oscServer;
163         m_oscServer = NULL;
164         delete m_1394Service;
165         m_1394Service = 0;
166         return false;
167     }
168
169     setVerboseLevel(m_verboseLevel);
170     return true;
171 }
172
173 bool
174 DeviceManager::discover( )
175 {
176     bool slaveMode=false;
177     if(!getOption("slaveMode", slaveMode)) {
178         debugWarning("Could not retrieve slaveMode parameter, defauling to false\n");
179     }
180     bool snoopMode=false;
181     if(!getOption("snoopMode", snoopMode)) {
182         debugWarning("Could not retrieve snoopMode parameter, defauling to false\n");
183     }
184
185     setVerboseLevel(m_verboseLevel);
186
187     for ( IAvDeviceVectorIterator it = m_avDevices.begin();
188           it != m_avDevices.end();
189           ++it )
190     {
191         if (!removeChildOscNode(*it)) {
192             debugWarning("failed to unregister AvDevice from OSC server\n");
193         }
194         delete *it;
195     }
196     m_avDevices.clear();
197
198     if (!slaveMode) {
199         for ( fb_nodeid_t nodeId = 0;
200               nodeId < m_1394Service->getNodeCount();
201               ++nodeId )
202         {
203             debugOutput( DEBUG_LEVEL_VERBOSE, "Probing node %d...\n", nodeId );
204
205             if (nodeId == m_1394Service->getLocalNodeId()) {
206                 debugOutput( DEBUG_LEVEL_VERBOSE, "Skipping local node (%d)...\n", nodeId );
207                 continue;
208             }
209
210             std::auto_ptr<ConfigRom> configRom =
211                 std::auto_ptr<ConfigRom>( new ConfigRom( *m_1394Service,
212                                                          nodeId ) );
213             if ( !configRom->initialize() ) {
214                 // \todo If a PHY on the bus is in power safe mode then
215                 // the config rom is missing. So this might be just
216                 // such this case and we can safely skip it. But it might
217                 // be there is a real software problem on our side.
218                 // This should be handlede more carefuly.
219                 debugOutput( DEBUG_LEVEL_NORMAL,
220                              "Could not read config rom from device (node id %d). "
221                              "Skip device discovering for this node\n",
222                              nodeId );
223                 continue;
224             }
225
226             bool isFromCache = false;
227             IAvDevice* avDevice = loadFromCache( *configRom );
228             if ( avDevice ) {
229                 debugOutput( DEBUG_LEVEL_VERBOSE, "could load from cache\n" );
230                 isFromCache = true;
231             } else {
232                 avDevice = getDriverForDevice( configRom, nodeId );
233             }
234
235             if ( avDevice ) {
236                 debugOutput( DEBUG_LEVEL_NORMAL,
237                              "driver found for device %d\n",
238                              nodeId );
239
240                 avDevice->setVerboseLevel( m_verboseLevel );
241
242                 if ( !isFromCache ) {
243                     if ( !avDevice->discover() ) {
244                         debugError( "could not discover device\n" );
245                         delete avDevice;
246                         continue;
247                     }
248                 }
249
250                 if ( !avDevice->setId( m_avDevices.size() ) ) {
251                     debugError( "setting Id failed\n" );
252                 }
253
254                 if (snoopMode) {
255                     debugOutput( DEBUG_LEVEL_VERBOSE,
256                                  "Enabling snoop mode on node %d...\n", nodeId );
257
258                     if(!avDevice->setOption("snoopMode", snoopMode)) {
259                         debugWarning("Could not set snoop mode for device on node %d\n", nodeId);
260                         delete avDevice;
261                         continue;
262                     }
263                 }
264
265                 if ( m_verboseLevel >= DEBUG_LEVEL_VERBOSE ) {
266                     avDevice->showDevice();
267                 }
268
269                 if ( !isFromCache ) {
270                     if ( !saveCache( avDevice ) ) {
271                         debugWarning( "Could not create cached version of AVC model\n" );
272                     }
273                 }
274
275                 m_avDevices.push_back( avDevice );
276
277                 if (!addChildOscNode(avDevice)) {
278                     debugWarning("failed to register AvDevice at OSC server\n");
279                 }
280
281             }
282         }
283         return true;
284
285     } else { // slave mode
286         fb_nodeid_t nodeId = m_1394Service->getLocalNodeId();
287         debugOutput( DEBUG_LEVEL_VERBOSE, "Starting in slave mode on node %d...\n", nodeId );
288
289         std::auto_ptr<ConfigRom> configRom =
290             std::auto_ptr<ConfigRom>( new ConfigRom( *m_1394Service,
291                                                      nodeId ) );
292         if ( !configRom->initialize() ) {
293             // \todo If a PHY on the bus is in power safe mode then
294             // the config rom is missing. So this might be just
295             // such this case and we can safely skip it. But it might
296             // be there is a real software problem on our side.
297             // This should be handled more carefuly.
298             debugOutput( DEBUG_LEVEL_NORMAL,
299                          "Could not read config rom from device (node id %d). "
300                          "Skip device discovering for this node\n",
301                          nodeId );
302             return false;
303         }
304
305         IAvDevice* avDevice = getSlaveDriver( configRom );
306         if ( avDevice ) {
307             debugOutput( DEBUG_LEVEL_NORMAL,
308                          "driver found for device %d\n",
309                          nodeId );
310
311             avDevice->setVerboseLevel( m_verboseLevel );
312
313             if ( !avDevice->discover() ) {
314                 debugError( "could not discover device\n" );
315                 delete avDevice;
316                 return false;
317             }
318
319             if ( !avDevice->setId( m_avDevices.size() ) ) {
320                 debugError( "setting Id failed\n" );
321             }
322             if ( m_verboseLevel >= DEBUG_LEVEL_VERBOSE ) {
323                 avDevice->showDevice();
324             }
325
326             m_avDevices.push_back( avDevice );
327         }
328
329         return true;
330     }
331 }
332
333
334 IAvDevice*
335 DeviceManager::getDriverForDevice( std::auto_ptr<ConfigRom>( configRom ),
336                                    int id )
337 {
338 #ifdef ENABLE_BEBOB
339     debugOutput( DEBUG_LEVEL_VERBOSE, "Trying BeBoB...\n" );
340     if ( BeBoB::AvDevice::probe( *configRom.get() ) ) {
341         return new BeBoB::AvDevice( configRom, *m_1394Service, id );
342     }
343 #endif
344
345 #ifdef ENABLE_BEBOB
346     debugOutput( DEBUG_LEVEL_VERBOSE, "Trying M-Audio...\n" );
347     if ( MAudio::AvDevice::probe( *configRom.get() ) ) {
348         return new MAudio::AvDevice( configRom, *m_1394Service, id );
349     }
350 #endif
351
352 #ifdef ENABLE_MOTU
353     debugOutput( DEBUG_LEVEL_VERBOSE, "Trying Motu...\n" );
354     if ( Motu::MotuDevice::probe( *configRom.get() ) ) {
355         return new Motu::MotuDevice( configRom, *m_1394Service, id );
356     }
357 #endif
358
359 #ifdef ENABLE_DICE
360     debugOutput( DEBUG_LEVEL_VERBOSE, "Trying Dice...\n" );
361     if ( Dice::DiceAvDevice::probe( *configRom.get() ) ) {
362         return new Dice::DiceAvDevice( configRom, *m_1394Service, id );
363     }
364 #endif
365
366 #ifdef ENABLE_METRIC_HALO
367     debugOutput( DEBUG_LEVEL_VERBOSE, "Trying Metric Halo...\n" );
368     if ( MetricHalo::MHAvDevice::probe( *configRom.get() ) ) {
369         return new MetricHalo::MHAvDevice( configRom, *m_1394Service, id );
370     }
371 #endif
372
373 #ifdef ENABLE_RME
374     debugOutput( DEBUG_LEVEL_VERBOSE, "Trying RME...\n" );
375     if ( Rme::RmeDevice::probe( *configRom.get() ) ) {
376         return new Rme::RmeDevice( configRom, *m_1394Service, id );
377     }
378 #endif
379
380 #ifdef ENABLE_BOUNCE
381     debugOutput( DEBUG_LEVEL_VERBOSE, "Trying Bounce...\n" );
382     if ( Bounce::BounceDevice::probe( *configRom.get() ) ) {
383         return new Bounce::BounceDevice( configRom, *m_1394Service, id );
384     }
385 #endif
386
387     return 0;
388 }
389
390 IAvDevice*
391 DeviceManager::getSlaveDriver( std::auto_ptr<ConfigRom>( configRom ) )
392 {
393
394 #ifdef ENABLE_BOUNCE
395     if ( Bounce::BounceSlaveDevice::probe( *configRom.get() ) ) {
396         return new Bounce::BounceSlaveDevice( configRom, *m_1394Service );
397     }
398 #endif
399
400     return 0;
401 }
402
403 bool
404 DeviceManager::isValidNode(int node)
405 {
406     for ( IAvDeviceVectorIterator it = m_avDevices.begin();
407           it != m_avDevices.end();
408           ++it )
409     {
410         IAvDevice* avDevice = *it;
411
412         if (avDevice->getConfigRom().getNodeId() == node) {
413             return true;
414     }
415     }
416     return false;
417 }
418
419 int
420 DeviceManager::getNbDevices()
421 {
422     return m_avDevices.size();
423 }
424
425 int
426 DeviceManager::getDeviceNodeId( int deviceNr )
427 {
428     if ( ! ( deviceNr < getNbDevices() ) ) {
429         debugError( "Device number out of range (%d)\n", deviceNr );
430         return -1;
431     }
432
433     IAvDevice* avDevice = m_avDevices.at( deviceNr );
434
435     if ( !avDevice ) {
436         debugError( "Could not get device at position (%d)\n",  deviceNr );
437     }
438
439     return avDevice->getConfigRom().getNodeId();
440 }
441
442 IAvDevice*
443 DeviceManager::getAvDevice( int nodeId )
444 {
445     for ( IAvDeviceVectorIterator it = m_avDevices.begin();
446           it != m_avDevices.end();
447           ++it )
448     {
449         IAvDevice* avDevice = *it;
450         if ( avDevice->getConfigRom().getNodeId() == nodeId ) {
451             return avDevice;
452         }
453     }
454
455     return 0;
456 }
457
458 IAvDevice*
459 DeviceManager::getAvDeviceByIndex( int idx )
460 {
461     return m_avDevices.at(idx);
462 }
463
464 unsigned int
465 DeviceManager::getAvDeviceCount( )
466 {
467     return m_avDevices.size();
468 }
469
470 /**
471  * Return the streamprocessor that is to be used as
472  * the sync source.
473  *
474  * Algorithm still to be determined
475  *
476  * @return StreamProcessor that is sync source
477  */
478 Streaming::StreamProcessor *
479 DeviceManager::getSyncSource() {
480     IAvDevice* device = getAvDeviceByIndex(0);
481
482     bool slaveMode=false;
483     if(!getOption("slaveMode", slaveMode)) {
484         debugWarning("Could not retrieve slaveMode parameter, defauling to false\n");
485     }
486
487     #warning TEST CODE FOR BOUNCE DEVICE !!
488     // this makes the bounce slave use the xmit SP as sync source
489     if (slaveMode) {
490         return device->getStreamProcessorByIndex(1);
491     } else {
492         return device->getStreamProcessorByIndex(0);
493     }
494 }
495
496 bool
497 DeviceManager::deinitialize()
498 {
499     return true;
500 }
501
502 bool
503 DeviceManager::buildCache()
504 {
505     bool result = true;
506     for ( IAvDeviceVectorIterator it = m_avDevices.begin();
507           it != m_avDevices.end();
508           ++it )
509     {
510         IAvDevice* pAvDevice = *it;
511         result &= saveCache( pAvDevice );
512     }
513
514     return result;
515 }
516
517 Glib::ustring
518 DeviceManager::getCachePath()
519 {
520     Glib::ustring cachePath;
521     char* pCachePath;
522     if ( asprintf( &pCachePath, "%s/cache/libffado/",  CACHEDIR ) < 0 ) {
523         debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
524         cachePath == "/var/cache/libffado/";
525     } else {
526         cachePath = pCachePath;
527         free( pCachePath );
528     }
529     return cachePath;
530 }
531
532 bool
533 DeviceManager::saveCache( IAvDevice* pAvDevice )
534 {
535     // so far only BeBoB based devices needed a cache for speed up.
536     BeBoB::AvDevice* pBeBoBDevice = reinterpret_cast<BeBoB::AvDevice*>( pAvDevice );
537     if ( !pBeBoBDevice ) {
538         return true;
539     }
540     // FIXME: the above test doesn't have the desired effect - MOTU devices
541     // are still allowed to proceed.  Therefore for the moment include a
542     // further check.
543     // If the device isn't a BeBoB device we can't assume it will accept AVC
544     // commands (for example, trying to send AVC commands to a MOTU via
545     // libiec61883 gives an endless stream of "send oops" messages).
546     // Therefore only proceed if the device is a known BeBoB device.
547     if (!BeBoB::AvDevice::probe(pAvDevice->getConfigRom())) {
548         return true;
549     }
550
551     // the path looks like this:
552     // PATH_TO_CACHE + GUID + CONFIGURATION_ID
553
554     Glib::ustring sDevicePath = getCachePath() + pAvDevice->getConfigRom().getGuidString();
555     struct stat buf;
556     if ( stat( sDevicePath.c_str(), &buf ) == 0 ) {
557         if ( !S_ISDIR( buf.st_mode ) ) {
558             debugError( "\"%s\" is not a directory\n",  sDevicePath.c_str() );
559             return false;
560         }
561     } else {
562         if (  mkdir( sDevicePath.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
563             debugError( "Could not create \"%s\" directory\n", sDevicePath.c_str() );
564             return false;
565         }
566     }
567
568     char* configId;
569     asprintf(&configId, "%08x", BeBoB::AvDevice::getConfigurationId( *m_1394Service,
570                                                                      pAvDevice->getNodeId() ) );
571     if ( !configId ) {
572         debugError( "Could not create id string\n" );
573         return false;
574     }
575     Glib::ustring sFileName = sDevicePath + "/" + configId + ".xml";
576     free( configId );
577     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
578
579     Util::XMLSerialize ser( sFileName );
580     return pBeBoBDevice->serialize( "", ser );
581 }
582
583 IAvDevice*
584 DeviceManager::loadFromCache( const ConfigRom& configRom )
585 {
586     Glib::ustring sDevicePath = getCachePath() + configRom.getGuidString();
587     char* configId;
588     // If the device isn't a BeBoB device we can't assume it will accept AVC
589     // commands (for example, trying to send AVC commands to a MOTU via
590     // libiec61883 gives an endless stream of "send oops" messages).
591     // Therefore only proceed if the device is a known BeBoB device.
592     if (!BeBoB::AvDevice::probe((ConfigRom&)configRom)) {
593         return false;
594     }
595     asprintf(&configId, "%08x",
596     BeBoB::AvDevice::getConfigurationId(*m_1394Service,
597     configRom.getNodeId()) );
598     if ( !configId ) {
599         debugError( "could not create id string\n" );
600         return false;
601     }
602     Glib::ustring sFileName = sDevicePath + "/" + configId + ".xml";
603     free( configId );
604     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
605
606     Util::XMLDeserialize deser( sFileName, m_verboseLevel );
607
608     BeBoB::AvDevice* pBeBoBDevice = BeBoB::AvDevice::deserialize( "",
609                                                                   deser,
610                                                                   *m_1394Service );
611     if ( pBeBoBDevice ) {
612         debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n", sFileName.c_str() );
613         pBeBoBDevice->getConfigRom().setNodeId( configRom.getNodeId() );
614     }
615
616     return pBeBoBDevice;
617 }
618
Note: See TracBrowser for help on using the browser.