root/trunk/libffado/src/devicemanager.cpp

Revision 516, 16.9 kB (checked in by wagi, 17 years ago)

- some de/serialing bugs found and fixed
- caching enabled for bebob devices

(finally online again! big thanks to my free wireless internet provider. s/he is finally back from
her/his holiday :)

  • 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
541     // the path looks like this:
542     // PATH_TO_CACHE + GUID + CONFIGURATION_ID
543
544     Glib::ustring sDevicePath = getCachePath() + pAvDevice->getConfigRom().getGuidString();
545     struct stat buf;
546     if ( stat( sDevicePath.c_str(), &buf ) == 0 ) {
547         if ( !S_ISDIR( buf.st_mode ) ) {
548             debugError( "\"%s\" is not a directory\n",  sDevicePath.c_str() );
549             return false;
550         }
551     } else {
552         if (  mkdir( sDevicePath.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
553             debugError( "Could not create \"%s\" directory\n", sDevicePath.c_str() );
554             return false;
555         }
556     }
557
558     char* configId;
559     asprintf(&configId, "%08x", BeBoB::AvDevice::getConfigurationId( *m_1394Service,
560                                                                      pAvDevice->getNodeId() ) );
561     if ( !configId ) {
562         debugError( "Could not create id string\n" );
563         return false;
564     }
565     Glib::ustring sFileName = sDevicePath + "/" + configId + ".xml";
566     free( configId );
567     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
568
569     Util::XMLSerialize ser( sFileName );
570     return pBeBoBDevice->serialize( "", ser );
571 }
572
573 IAvDevice*
574 DeviceManager::loadFromCache( const ConfigRom& configRom )
575 {
576     Glib::ustring sDevicePath = getCachePath() + configRom.getGuidString();
577     char* configId;
578     asprintf(&configId, "%08x",
579     BeBoB::AvDevice::getConfigurationId(*m_1394Service,
580     configRom.getNodeId()) );
581     if ( !configId ) {
582         debugError( "could not create id string\n" );
583         return false;
584     }
585     Glib::ustring sFileName = sDevicePath + "/" + configId + ".xml";
586     free( configId );
587     debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
588
589     Util::XMLDeserialize deser( sFileName, m_verboseLevel );
590
591     BeBoB::AvDevice* pBeBoBDevice = BeBoB::AvDevice::deserialize( "",
592                                                                   deser,
593                                                                   *m_1394Service );
594     if ( pBeBoBDevice ) {
595         debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n", sFileName.c_str() );
596         pBeBoBDevice->getConfigRom().setNodeId( configRom.getNodeId() );
597     }
598
599     return pBeBoBDevice;
600 }
601
Note: See TracBrowser for help on using the browser.