root/branches/streaming-rework/src/bounce/bounce_avdevice.cpp

Revision 416, 16.7 kB (checked in by pieterpalmers, 16 years ago)

- Introduced a generic option mechanism. AvDevices? now automatically

inherit from OptionContainer? (via IAvDevice) and can specify options
(e.g. at construction). These can then be get/set using the container
functions from the outside.

- Modified the bebob, bounce, motu, mh, rme AvDevices? to make use of the

option system for their Id value and the 'snoopMode' option.

- Made M-Audio avdevice a subclass of the BeBoB avdevice to avoid code

duplication.

- Extended the bounce device

Line 
1 /* bounce_avdevice.cpp
2  * Copyright (C) 2006 by Pieter Palmers
3  * Copyright (C) 2006 by Daniel Wagner
4  *
5  * This file is part of FreeBoB.
6  *
7  * FreeBoB is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  * FreeBoB is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with FreeBoB; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19  * MA 02111-1307 USA.
20  */
21 #include "bounce/bounce_avdevice.h"
22
23 #include "libieee1394/configrom.h"
24 #include "libieee1394/ieee1394service.h"
25
26 #include "libfreebobavc/avc_plug_info.h"
27 #include "libfreebobavc/avc_extended_plug_info.h"
28 #include "libfreebobavc/avc_subunit_info.h"
29 #include "libfreebobavc/avc_extended_stream_format.h"
30 #include "libfreebobavc/avc_serialize.h"
31 #include "libfreebobavc/avc_definitions.h"
32
33 #include "debugmodule/debugmodule.h"
34
35 #include <iostream>
36 #include <sstream>
37 #include <stdint.h>
38
39 #include <string>
40 #include <netinet/in.h>
41
42 namespace Bounce {
43
44 // to define the supported devices
45 static VendorModelEntry supportedDeviceList[] =
46 {
47     {0x0B0001, 0x0B0001, 0x0B0001, "FreeBoB", "Bounce"},
48 };
49
50 IMPL_DEBUG_MODULE( BounceDevice, BounceDevice, DEBUG_LEVEL_VERBOSE );
51
52
53 BounceDevice::BounceDevice( std::auto_ptr< ConfigRom >( configRom ),
54                             Ieee1394Service& ieee1394service,
55                             int nodeId,
56                             int verboseLevel )
57     : m_configRom( configRom )
58     , m_p1394Service( &ieee1394service )
59     , m_nodeId( nodeId )
60     , m_verboseLevel( verboseLevel )
61     , m_samplerate (44100)
62     , m_model( NULL )
63     , m_Notifier ( NULL )
64 {
65     setDebugLevel( verboseLevel );
66
67     debugOutput( DEBUG_LEVEL_VERBOSE, "Created Bounce::BounceDevice (NodeID %d)\n",
68                  nodeId );
69     addOption(FreebobUtil::OptionContainer::Option("snoopMode",false));
70     addOption(FreebobUtil::OptionContainer::Option("id",std::string("dev?")));
71 }
72
73 BounceDevice::~BounceDevice()
74 {
75
76 }
77
78 ConfigRom&
79 BounceDevice::getConfigRom() const
80 {
81     return *m_configRom;
82 }
83
84 bool
85 BounceDevice::probe( ConfigRom& configRom )
86 {
87 //     unsigned int vendorId = configRom.getNodeVendorId();
88     unsigned int modelId = configRom.getModelId();
89     unsigned int unitSpecifierId = configRom.getUnitSpecifierId();
90
91     for ( unsigned int i = 0;
92           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
93           ++i )
94     {
95         if (
96 //             ( supportedDeviceList[i].vendor_id == vendorId )
97              ( supportedDeviceList[i].model_id == modelId )
98              && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
99            )
100         {
101             return true;
102         }
103     }
104
105     return false;
106 }
107
108 bool
109 BounceDevice::discover()
110 {
111 //      unsigned int resp_len=0;
112 //      quadlet_t request[6];
113 //      quadlet_t *resp;
114
115 //     unsigned int vendorId = m_configRom->getNodeVendorId();
116     unsigned int modelId = m_configRom->getModelId();
117     unsigned int unitSpecifierId = m_configRom->getUnitSpecifierId();
118
119     for ( unsigned int i = 0;
120           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
121           ++i )
122     {
123         if ( //( supportedDeviceList[i].vendor_id == vendorId )
124              ( supportedDeviceList[i].model_id == modelId )
125              && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
126            )
127         {
128             m_model = &(supportedDeviceList[i]);
129         }
130     }
131
132     if (m_model != NULL) {
133         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
134                 m_model->vendor_name, m_model->model_name);
135         return true;
136     }
137    
138     debugOutput( DEBUG_LEVEL_VERBOSE, "Discovering...\n" );
139
140         std::string vendor=std::string(FREEBOB_BOUNCE_SERVER_VENDORNAME);
141         std::string model=std::string(FREEBOB_BOUNCE_SERVER_MODELNAME);
142
143         if (!(m_configRom->getVendorName().compare(0,vendor.length(),vendor,0,vendor.length())==0)
144             || !(m_configRom->getModelName().compare(0,model.length(),model,0,model.length())==0)) {
145                 return false;
146         }
147 /*
148 // AVC1394_COMMAND_INPUT_PLUG_SIGNAL_FORMAT
149         request[0] = htonl( AVC1394_CTYPE_STATUS | (AVC1394_SUBUNIT_TYPE_FREEBOB_BOUNCE_SERVER << 19) | (0 << 16)
150                         | AVC1394_COMMAND_INPUT_PLUG_SIGNAL_FORMAT | 0x00);
151
152         request[1] =  0xFFFFFFFF;
153         resp = m_p1394Service->transactionBlock( m_nodeId,
154                                                        request,
155                                                        2,
156                                                                &resp_len );
157 //      hexDump((unsigned char *)request,6*4);
158         if(resp) {
159                 char *buffer=(char *)&resp[1];
160                 resp[resp_len-1]=0;
161                 xmlDescription=buffer;
162 //              hexDump((unsigned char *)resp,6*4);
163         }
164 */
165         return true;
166 }
167
168 int BounceDevice::getSamplingFrequency( ) {
169     return m_samplerate;
170 }
171
172 bool BounceDevice::setSamplingFrequency( ESamplingFrequency samplingFrequency ) {
173     int retval=convertESamplingFrequency( samplingFrequency );
174     if (retval) {
175         m_samplerate=retval;
176         return true;
177     } else return false;
178 }
179
180 bool BounceDevice::setId( unsigned int id) {
181     // FIXME: decent ID system nescessary
182     std::ostringstream idstr;
183
184     idstr << "dev" << id;
185    
186     debugOutput( DEBUG_LEVEL_VERBOSE, "Set id to %s...\n", idstr.str().c_str());
187    
188     return setOption("id",idstr.str());
189 }
190
191 bool
192 BounceDevice::lock() {
193
194     return true;
195 }
196
197
198 bool
199 BounceDevice::unlock() {
200
201     return true;
202 }
203
204 void
205 BounceDevice::showDevice() const
206 {
207     debugOutput(DEBUG_LEVEL_NORMAL, "\nI am the bouncedevice, the bouncedevice I am...\n" );
208     debugOutput(DEBUG_LEVEL_NORMAL, "Vendor            :  %s\n", m_configRom->getVendorName().c_str());
209     debugOutput(DEBUG_LEVEL_NORMAL, "Model             :  %s\n", m_configRom->getModelName().c_str());
210     debugOutput(DEBUG_LEVEL_NORMAL, "Vendor Name       :  %s\n", m_model->vendor_name);
211     debugOutput(DEBUG_LEVEL_NORMAL, "Model Name        :  %s\n", m_model->model_name);
212     debugOutput(DEBUG_LEVEL_NORMAL, "Node              :  %d\n", m_nodeId);
213     debugOutput(DEBUG_LEVEL_NORMAL, "GUID              :  0x%016llX\n", m_configRom->getGuid());
214     debugOutput(DEBUG_LEVEL_NORMAL, "AVC test response :  %s\n", xmlDescription.c_str());
215     debugOutput(DEBUG_LEVEL_NORMAL, "\n" );
216 }
217
218 bool
219 BounceDevice::addXmlDescription( xmlNodePtr deviceNode )
220 {
221
222     return false;
223
224 }
225
226 #define BOUNCE_NR_OF_CHANNELS 2
227
228 bool
229 BounceDevice::addPortsToProcessor(
230     FreebobStreaming::StreamProcessor *processor,
231     FreebobStreaming::Port::E_Direction direction) {
232
233     debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to processor\n");
234    
235     std::string id=std::string("dev?");
236     if(!getOption("id", id)) {
237         debugWarning("Could not retrieve id parameter, defauling to 'dev?'\n");
238     }
239    
240     int i=0;
241     for (i=0;i<BOUNCE_NR_OF_CHANNELS;i++) {
242         char *buff;
243         asprintf(&buff,"%s%s_Port%d",id.c_str(),direction==FreebobStreaming::AmdtpAudioPort::E_Playback?"p":"c",i);
244
245         FreebobStreaming::Port *p=NULL;
246         p=new FreebobStreaming::AmdtpAudioPort(
247                 buff,
248                 direction,
249                 // \todo: streaming backend expects indexing starting from 0
250                 // but bebob reports it starting from 1. Decide where
251                 // and how to handle this (pp: here)
252                 i,
253                 0,
254                 FreebobStreaming::AmdtpPortInfo::E_MBLA
255         );
256
257         if (!p) {
258             debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
259         } else {
260
261             if (!processor->addPort(p)) {
262                 debugWarning("Could not register port with stream processor\n");
263                 free(buff);
264                 return false;
265             } else {
266                 debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
267             }
268         }
269
270         free(buff);
271
272      }
273
274         return true;
275 }
276
277 bool
278 BounceDevice::prepare() {
279     debugOutput(DEBUG_LEVEL_NORMAL, "Preparing BounceDevice...\n" );
280    
281     bool snoopMode=false;
282     if(!getOption("snoopMode", snoopMode)) {
283         debugWarning("Could not retrieve snoopMode parameter, defauling to false\n");
284     }
285
286     // create & add streamprocessors
287     FreebobStreaming::StreamProcessor *p;
288    
289     p=new FreebobStreaming::AmdtpReceiveStreamProcessor(
290                              m_p1394Service->getPort(),
291                              m_samplerate,
292                              BOUNCE_NR_OF_CHANNELS);
293
294     if(!p->init()) {
295         debugFatal("Could not initialize receive processor!\n");
296         delete p;
297         return false;
298     }
299
300     if (!addPortsToProcessor(p,
301             FreebobStreaming::Port::E_Capture)) {
302         debugFatal("Could not add plug to processor!\n");
303         delete p;
304         return false;
305     }
306
307     m_receiveProcessors.push_back(p);
308
309     // do the transmit processor
310     if (snoopMode) {
311         // we are snooping, so this is receive too.
312         p=new FreebobStreaming::AmdtpReceiveStreamProcessor(
313                                   m_p1394Service->getPort(),
314                                   m_samplerate,
315                                   BOUNCE_NR_OF_CHANNELS);
316     } else {
317         p=new FreebobStreaming::AmdtpTransmitStreamProcessor(
318                                 m_p1394Service->getPort(),
319                                 m_samplerate,
320                                 BOUNCE_NR_OF_CHANNELS);
321     }
322    
323     if(!p->init()) {
324         debugFatal("Could not initialize transmit processor %s!\n",
325             (snoopMode?" in snoop mode":""));
326         delete p;
327         return false;
328     }
329
330     if (snoopMode) {
331         if (!addPortsToProcessor(p,
332             FreebobStreaming::Port::E_Capture)) {
333             debugFatal("Could not add plug to processor!\n");
334             delete p;
335             return false;
336         }
337         m_receiveProcessors.push_back(p);
338     } else {
339         if (!addPortsToProcessor(p,
340             FreebobStreaming::Port::E_Playback)) {
341             debugFatal("Could not add plug to processor!\n");
342             delete p;
343             return false;
344         }
345         m_transmitProcessors.push_back(p);
346     }
347
348     return true;
349 }
350
351 int
352 BounceDevice::getStreamCount() {
353     return m_receiveProcessors.size() + m_transmitProcessors.size();
354 }
355
356 FreebobStreaming::StreamProcessor *
357 BounceDevice::getStreamProcessorByIndex(int i) {
358     if (i<(int)m_receiveProcessors.size()) {
359         return m_receiveProcessors.at(i);
360     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
361         return m_transmitProcessors.at(i-m_receiveProcessors.size());
362     }
363
364     return NULL;
365 }
366
367 bool
368 BounceDevice::startStreamByIndex(int i) {
369     if (i<(int)m_receiveProcessors.size()) {
370         int n=i;
371         FreebobStreaming::StreamProcessor *p=m_receiveProcessors.at(n);
372        
373         // allocate ISO channel
374         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
375         if(isochannel<0) {
376             debugError("Could not allocate iso channel for SP %d\n",i);
377             return false;
378         }
379         p->setChannel(isochannel);
380        
381         fb_quadlet_t reg_isoch;
382         // check value of ISO_CHANNEL register
383         if(!readReg(BOUNCE_REGISTER_TX_ISOCHANNEL, &reg_isoch)) {
384             debugError("Could not read ISO_CHANNEL register\n", n);
385             p->setChannel(-1);
386             deallocateIsoChannel(isochannel);
387             return false;
388         }
389         if(reg_isoch != 0xFFFFFFFFUL) {
390             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X)\n", reg_isoch);
391             p->setChannel(-1);
392             deallocateIsoChannel(isochannel);
393             return false;
394         }
395        
396         // write value of ISO_CHANNEL register
397         reg_isoch=isochannel;
398         if(!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, reg_isoch)) {
399             debugError("Could not write ISO_CHANNEL register\n");
400             p->setChannel(-1);
401             deallocateIsoChannel(isochannel);
402             return false;
403         }
404        
405         return true;
406        
407     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
408         int n=i-m_receiveProcessors.size();
409         FreebobStreaming::StreamProcessor *p=m_transmitProcessors.at(n);
410        
411         // allocate ISO channel
412         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
413         if(isochannel<0) {
414             debugError("Could not allocate iso channel for SP %d\n",i);
415             return false;
416         }
417         p->setChannel(isochannel);
418        
419         fb_quadlet_t reg_isoch;
420         // check value of ISO_CHANNEL register
421         if(!readReg(BOUNCE_REGISTER_RX_ISOCHANNEL, &reg_isoch)) {
422             debugError("Could not read ISO_CHANNEL register\n");
423             p->setChannel(-1);
424             deallocateIsoChannel(isochannel);
425             return false;
426         }
427         if(reg_isoch != 0xFFFFFFFFUL) {
428             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X)\n", reg_isoch);
429             p->setChannel(-1);
430             deallocateIsoChannel(isochannel);
431             return false;
432         }
433        
434         // write value of ISO_CHANNEL register
435         reg_isoch=isochannel;
436         if(!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, reg_isoch)) {
437             debugError("Could not write ISO_CHANNEL register\n");
438             p->setChannel(-1);
439             deallocateIsoChannel(isochannel);
440             return false;
441         }
442        
443         return true;
444     }
445    
446     debugError("SP index %d out of range!\n",i);
447    
448     return false;
449 }
450
451 bool
452 BounceDevice::stopStreamByIndex(int i) {
453
454         return false;
455 }
456
457 // helper functions
458
459 // allocate ISO resources for the SP's
460 int BounceDevice::allocateIsoChannel(unsigned int packet_size) {
461     unsigned int bandwidth=8+packet_size;
462    
463     int ch=m_p1394Service->allocateIsoChannelGeneric(bandwidth);
464        
465     debugOutput(DEBUG_LEVEL_VERBOSE, "allocated channel %d, bandwidth %d\n",
466         ch, bandwidth);
467    
468     return ch;
469 }
470 // deallocate ISO resources
471 bool BounceDevice::deallocateIsoChannel(int channel) {
472     debugOutput(DEBUG_LEVEL_VERBOSE, "freeing channel %d\n",channel);
473     return m_p1394Service->freeIsoChannel(channel);
474 }
475
476 // I/O functions
477
478 bool
479 BounceDevice::readReg(fb_nodeaddr_t offset, fb_quadlet_t *result) {
480     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX\n", offset);
481    
482     if(offset >= BOUNCE_INVALID_OFFSET) {
483         debugError("invalid offset: 0x%016llX\n", offset);
484         return false;
485     }
486    
487     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
488     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
489    
490     if(!m_p1394Service->read_quadlet( nodeId, addr, result ) ) {
491         debugError("Could not read from node 0x%04X addr 0x%012X\n", nodeId, addr);
492         return false;
493     }
494     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Read result: 0x%08X\n", *result);
495    
496     return true;
497 }
498
499 bool
500 BounceDevice::writeReg(fb_nodeaddr_t offset, fb_quadlet_t data) {
501     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, data: 0x%08X\n", 
502         offset, data);
503    
504     if(offset >= BOUNCE_INVALID_OFFSET) {
505         debugError("invalid offset: 0x%016llX\n", offset);
506         return false;
507     }
508    
509     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
510     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
511    
512     if(!m_p1394Service->write_quadlet( nodeId, addr, data ) ) {
513         debugError("Could not write to node 0x%04X addr 0x%012X\n", nodeId, addr);
514         return false;
515     }
516     return true;
517 }
518
519 bool
520 BounceDevice::readRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
521     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX, length %u\n",
522         offset, length);
523    
524     if(offset >= BOUNCE_INVALID_OFFSET) {
525         debugError("invalid offset: 0x%016llX\n", offset);
526         return false;
527     }
528    
529     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
530     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
531    
532     if(!m_p1394Service->read( nodeId, addr, length, data ) ) {
533         debugError("Could not read from node 0x%04X addr 0x%012llX\n", nodeId, addr);
534         return false;
535     }
536     return true;
537 }
538
539 bool
540 BounceDevice::writeRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
541     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, length: %u\n", 
542         offset, length);
543    
544     if(offset >= BOUNCE_INVALID_OFFSET) {
545         debugError("invalid offset: 0x%016llX\n", offset);
546         return false;
547     }
548    
549     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
550     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
551
552     if(!m_p1394Service->write( nodeId, addr, length, data ) ) {
553         debugError("Could not write to node 0x%04X addr 0x%012llX\n", nodeId, addr);
554         return false;
555     }
556     return true;
557 }
558
559
560 } // namespace
Note: See TracBrowser for help on using the browser.