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

Revision 424, 18.0 kB (checked in by pieterpalmers, 15 years ago)

- The library can now be started in 'slave mode', creating a BounceSlaveDevice?.

On a discovering node, this slave device is discovered as a BounceDevice?.
Streaming does not work yet, something wrong with the timestamps.

- Implemented the 'snoop mode', that allows a client to 'snoop' the streams

between another host and a device. It is only implemented for BeBoB devices.
The channel numbers and stream configuration are automatically detected.
Note that it currently relies on a rather hackish support for reading the
{i,o}PCR plugs by using private functions of libiec61883

- changed jack backend to support these two new features

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 "libavc/avc_plug_info.h"
27 #include "libavc/avc_extended_plug_info.h"
28 #include "libavc/avc_subunit_info.h"
29 #include "libavc/avc_extended_stream_format.h"
30 #include "libavc/avc_serialize.h"
31 #include "libavc/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     {0x0B0001LU, 0x0B0001LU, 0x0B0001LU, "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_verboseLevel( DEBUG_LEVEL_VERBOSE )
62     , m_samplerate (44100)
63     , m_model( NULL )
64     , m_Notifier ( NULL )
65 {
66     setDebugLevel( verboseLevel );
67
68     debugOutput( DEBUG_LEVEL_VERBOSE, "Created Bounce::BounceDevice (NodeID %d)\n",
69                  nodeId );
70     addOption(Util::OptionContainer::Option("snoopMode",false));
71     addOption(Util::OptionContainer::Option("id",std::string("dev?")));
72 }
73
74 BounceDevice::~BounceDevice()
75 {
76
77 }
78
79 ConfigRom&
80 BounceDevice::getConfigRom() const
81 {
82     return *m_configRom;
83 }
84
85 bool
86 BounceDevice::probe( ConfigRom& configRom )
87 {
88
89     debugOutput( DEBUG_LEVEL_VERBOSE, "probing BounceDevice\n");
90 //     unsigned int vendorId = configRom.getNodeVendorId();
91     unsigned int modelId = configRom.getModelId();
92     unsigned int unitSpecifierId = configRom.getUnitSpecifierId();
93     debugOutput( DEBUG_LEVEL_VERBOSE, "modelId = 0x%08X, specid = 0x%08X\n", modelId, unitSpecifierId);
94
95     for ( unsigned int i = 0;
96           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
97           ++i )
98     {
99         if (
100 //             ( supportedDeviceList[i].vendor_id == vendorId )
101              ( supportedDeviceList[i].model_id == modelId )
102              && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
103            )
104         {
105             return true;
106         }
107     }
108
109     return false;
110 }
111
112 bool
113 BounceDevice::discover()
114 {
115     debugOutput( DEBUG_LEVEL_VERBOSE, "discovering BounceDevice (NodeID %d)\n",
116                  m_nodeId );
117                  
118 //     unsigned int vendorId = m_configRom->getNodeVendorId();
119     unsigned int modelId = m_configRom->getModelId();
120     unsigned int unitSpecifierId = m_configRom->getUnitSpecifierId();
121
122     for ( unsigned int i = 0;
123           i < ( sizeof( supportedDeviceList )/sizeof( VendorModelEntry ) );
124           ++i )
125     {
126         if ( //( supportedDeviceList[i].vendor_id == vendorId )
127              ( supportedDeviceList[i].model_id == modelId )
128              && ( supportedDeviceList[i].unit_specifier_id == unitSpecifierId )
129            )
130         {
131             m_model = &(supportedDeviceList[i]);
132         }
133     }
134
135     if (m_model != NULL) {
136         debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
137                 m_model->vendor_name, m_model->model_name);
138         return true;
139     }
140     return false;
141 }
142
143 int BounceDevice::getSamplingFrequency( ) {
144     return m_samplerate;
145 }
146
147 bool BounceDevice::setSamplingFrequency( ESamplingFrequency samplingFrequency ) {
148     int retval=convertESamplingFrequency( samplingFrequency );
149     if (retval) {
150         m_samplerate=retval;
151         return true;
152     } else return false;
153 }
154
155 bool BounceDevice::setId( unsigned int id) {
156     // FIXME: decent ID system nescessary
157     std::ostringstream idstr;
158
159     idstr << "dev" << id;
160    
161     debugOutput( DEBUG_LEVEL_VERBOSE, "Set id to %s...\n", idstr.str().c_str());
162    
163     return setOption("id",idstr.str());
164 }
165
166 bool
167 BounceDevice::lock() {
168
169     return true;
170 }
171
172
173 bool
174 BounceDevice::unlock() {
175
176     return true;
177 }
178
179 void
180 BounceDevice::showDevice() const
181 {
182     debugOutput(DEBUG_LEVEL_NORMAL, "\nI am the bouncedevice, the bouncedevice I am...\n" );
183     debugOutput(DEBUG_LEVEL_NORMAL, "Vendor            :  %s\n", m_configRom->getVendorName().c_str());
184     debugOutput(DEBUG_LEVEL_NORMAL, "Model             :  %s\n", m_configRom->getModelName().c_str());
185     debugOutput(DEBUG_LEVEL_NORMAL, "Vendor Name       :  %s\n", m_model->vendor_name);
186     debugOutput(DEBUG_LEVEL_NORMAL, "Model Name        :  %s\n", m_model->model_name);
187     debugOutput(DEBUG_LEVEL_NORMAL, "Node              :  %d\n", m_nodeId);
188     debugOutput(DEBUG_LEVEL_NORMAL, "GUID              :  0x%016llX\n", m_configRom->getGuid());
189     debugOutput(DEBUG_LEVEL_NORMAL, "\n" );
190 }
191
192 bool
193 BounceDevice::addXmlDescription( xmlNodePtr deviceNode )
194 {
195
196     return false;
197
198 }
199
200 #define BOUNCE_NR_OF_CHANNELS 2
201
202 bool
203 BounceDevice::addPortsToProcessor(
204     Streaming::StreamProcessor *processor,
205     Streaming::Port::E_Direction direction) {
206
207     debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to processor\n");
208    
209     std::string id=std::string("dev?");
210     if(!getOption("id", id)) {
211         debugWarning("Could not retrieve id parameter, defauling to 'dev?'\n");
212     }
213    
214     int i=0;
215     for (i=0;i<BOUNCE_NR_OF_CHANNELS;i++) {
216         char *buff;
217         asprintf(&buff,"%s%s_Port%d",id.c_str(),direction==Streaming::AmdtpAudioPort::E_Playback?"p":"c",i);
218
219         Streaming::Port *p=NULL;
220         p=new Streaming::AmdtpAudioPort(
221                 buff,
222                 direction,
223                 // \todo: streaming backend expects indexing starting from 0
224                 // but bebob reports it starting from 1. Decide where
225                 // and how to handle this (pp: here)
226                 i,
227                 0,
228                 Streaming::AmdtpPortInfo::E_MBLA
229         );
230
231         if (!p) {
232             debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
233         } else {
234
235             if (!processor->addPort(p)) {
236                 debugWarning("Could not register port with stream processor\n");
237                 free(buff);
238                 return false;
239             } else {
240                 debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
241             }
242         }
243
244         free(buff);
245
246      }
247
248         return true;
249 }
250
251 bool
252 BounceDevice::prepare() {
253     debugOutput(DEBUG_LEVEL_NORMAL, "Preparing BounceDevice...\n" );
254    
255     bool snoopMode=false;
256     if(!getOption("snoopMode", snoopMode)) {
257         debugWarning("Could not retrieve snoopMode parameter, defauling to false\n");
258     }
259
260     // create & add streamprocessors
261     Streaming::StreamProcessor *p;
262    
263     p=new Streaming::AmdtpReceiveStreamProcessor(
264                              m_p1394Service->getPort(),
265                              m_samplerate,
266                              BOUNCE_NR_OF_CHANNELS);
267
268     if(!p->init()) {
269         debugFatal("Could not initialize receive processor!\n");
270         delete p;
271         return false;
272     }
273
274     if (!addPortsToProcessor(p,
275             Streaming::Port::E_Capture)) {
276         debugFatal("Could not add plug to processor!\n");
277         delete p;
278         return false;
279     }
280
281     m_receiveProcessors.push_back(p);
282
283     // do the transmit processor
284     if (snoopMode) {
285         // we are snooping, so this is receive too.
286         p=new Streaming::AmdtpReceiveStreamProcessor(
287                                   m_p1394Service->getPort(),
288                                   m_samplerate,
289                                   BOUNCE_NR_OF_CHANNELS);
290     } else {
291         p=new Streaming::AmdtpTransmitStreamProcessor(
292                                 m_p1394Service->getPort(),
293                                 m_samplerate,
294                                 BOUNCE_NR_OF_CHANNELS);
295     }
296    
297     if(!p->init()) {
298         debugFatal("Could not initialize transmit processor %s!\n",
299             (snoopMode?" in snoop mode":""));
300         delete p;
301         return false;
302     }
303
304     if (snoopMode) {
305         if (!addPortsToProcessor(p,
306             Streaming::Port::E_Capture)) {
307             debugFatal("Could not add plug to processor!\n");
308             delete p;
309             return false;
310         }
311         m_receiveProcessors.push_back(p);
312     } else {
313         if (!addPortsToProcessor(p,
314             Streaming::Port::E_Playback)) {
315             debugFatal("Could not add plug to processor!\n");
316             delete p;
317             return false;
318         }
319         m_transmitProcessors.push_back(p);
320     }
321
322     return true;
323 }
324
325 int
326 BounceDevice::getStreamCount() {
327     return m_receiveProcessors.size() + m_transmitProcessors.size();
328 }
329
330 Streaming::StreamProcessor *
331 BounceDevice::getStreamProcessorByIndex(int i) {
332     if (i<(int)m_receiveProcessors.size()) {
333         return m_receiveProcessors.at(i);
334     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
335         return m_transmitProcessors.at(i-m_receiveProcessors.size());
336     }
337
338     return NULL;
339 }
340
341 bool
342 BounceDevice::startStreamByIndex(int i) {
343     if (i<(int)m_receiveProcessors.size()) {
344         int n=i;
345         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
346        
347         // allocate ISO channel
348         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
349         if(isochannel<0) {
350             debugError("Could not allocate iso channel for SP %d\n",i);
351             return false;
352         }
353         p->setChannel(isochannel);
354        
355         fb_quadlet_t reg_isoch;
356         // check value of ISO_CHANNEL register
357         if(!readReg(BOUNCE_REGISTER_TX_ISOCHANNEL, &reg_isoch)) {
358             debugError("Could not read ISO_CHANNEL register\n", n);
359             p->setChannel(-1);
360             deallocateIsoChannel(isochannel);
361             return false;
362         }
363         if(reg_isoch != 0xFFFFFFFFUL) {
364             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X)\n", reg_isoch);
365             p->setChannel(-1);
366             deallocateIsoChannel(isochannel);
367             return false;
368         }
369        
370         // write value of ISO_CHANNEL register
371         reg_isoch=isochannel;
372         if(!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, reg_isoch)) {
373             debugError("Could not write ISO_CHANNEL register\n");
374             p->setChannel(-1);
375             deallocateIsoChannel(isochannel);
376             return false;
377         }
378        
379         return true;
380        
381     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
382         int n=i-m_receiveProcessors.size();
383         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
384        
385         // allocate ISO channel
386         int isochannel=allocateIsoChannel(p->getMaxPacketSize());
387         if(isochannel<0) {
388             debugError("Could not allocate iso channel for SP %d\n",i);
389             return false;
390         }
391         p->setChannel(isochannel);
392        
393         fb_quadlet_t reg_isoch;
394         // check value of ISO_CHANNEL register
395         if(!readReg(BOUNCE_REGISTER_RX_ISOCHANNEL, &reg_isoch)) {
396             debugError("Could not read ISO_CHANNEL register\n");
397             p->setChannel(-1);
398             deallocateIsoChannel(isochannel);
399             return false;
400         }
401         if(reg_isoch != 0xFFFFFFFFUL) {
402             debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X)\n", reg_isoch);
403             p->setChannel(-1);
404             deallocateIsoChannel(isochannel);
405             return false;
406         }
407        
408         // write value of ISO_CHANNEL register
409         reg_isoch=isochannel;
410         if(!writeReg(BOUNCE_REGISTER_RX_ISOCHANNEL, reg_isoch)) {
411             debugError("Could not write ISO_CHANNEL register\n");
412             p->setChannel(-1);
413             deallocateIsoChannel(isochannel);
414             return false;
415         }
416        
417         return true;
418     }
419    
420     debugError("SP index %d out of range!\n",i);
421    
422     return false;
423 }
424
425 bool
426 BounceDevice::stopStreamByIndex(int i) {
427     if (i<(int)m_receiveProcessors.size()) {
428         int n=i;
429         Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
430         unsigned int isochannel=p->getChannel();
431        
432         fb_quadlet_t reg_isoch;
433         // check value of ISO_CHANNEL register
434         if(!readReg(BOUNCE_REGISTER_TX_ISOCHANNEL, &reg_isoch)) {
435             debugError("Could not read ISO_CHANNEL register\n");
436             return false;
437         }
438         if(reg_isoch != isochannel) {
439             debugError("ISO_CHANNEL register != 0x%08X (=0x%08X)\n", isochannel, reg_isoch);
440             return false;
441         }
442        
443         // write value of ISO_CHANNEL register
444         reg_isoch=0xFFFFFFFFUL;
445         if(!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, reg_isoch)) {
446             debugError("Could not write ISO_CHANNEL register" );
447             return false;
448         }
449        
450         // deallocate ISO channel
451         if(!deallocateIsoChannel(isochannel)) {
452             debugError("Could not deallocate iso channel for SP\n",i);
453             return false;
454         }
455        
456         p->setChannel(-1);
457         return true;
458        
459     } else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
460         int n=i-m_receiveProcessors.size();
461         Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
462        
463         unsigned int isochannel=p->getChannel();
464        
465         fb_quadlet_t reg_isoch;
466         // check value of ISO_CHANNEL register
467         if(!readReg(BOUNCE_REGISTER_RX_ISOCHANNEL, &reg_isoch)) {
468             debugError("Could not read ISO_CHANNEL register\n");
469             return false;
470         }
471         if(reg_isoch != isochannel) {
472             debugError("ISO_CHANNEL register != 0x%08X (=0x%08X)\n", isochannel, reg_isoch);
473             return false;
474         }
475        
476         // write value of ISO_CHANNEL register
477         reg_isoch=0xFFFFFFFFUL;
478         if(!writeReg(BOUNCE_REGISTER_RX_ISOCHANNEL, reg_isoch)) {
479             debugError("Could not write ISO_CHANNEL register\n");
480             return false;
481         }
482        
483         // deallocate ISO channel
484         if(!deallocateIsoChannel(isochannel)) {
485             debugError("Could not deallocate iso channel for SP (%d)\n",i);
486             return false;
487         }
488        
489         p->setChannel(-1);
490         return true;
491     }
492    
493     debugError("SP index %d out of range!\n",i);
494     return false;
495 }
496
497 // helper functions
498
499 // allocate ISO resources for the SP's
500 int BounceDevice::allocateIsoChannel(unsigned int packet_size) {
501     unsigned int bandwidth=8+packet_size;
502    
503     int ch=m_p1394Service->allocateIsoChannelGeneric(bandwidth);
504        
505     debugOutput(DEBUG_LEVEL_VERBOSE, "allocated channel %d, bandwidth %d\n",
506         ch, bandwidth);
507    
508     return ch;
509 }
510 // deallocate ISO resources
511 bool BounceDevice::deallocateIsoChannel(int channel) {
512     debugOutput(DEBUG_LEVEL_VERBOSE, "freeing channel %d\n",channel);
513     return m_p1394Service->freeIsoChannel(channel);
514 }
515
516 // I/O functions
517
518 bool
519 BounceDevice::readReg(fb_nodeaddr_t offset, fb_quadlet_t *result) {
520     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX\n", offset);
521    
522     if(offset >= BOUNCE_INVALID_OFFSET) {
523         debugError("invalid offset: 0x%016llX\n", offset);
524         return false;
525     }
526    
527     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
528     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
529    
530     if(!m_p1394Service->read_quadlet( nodeId, addr, result ) ) {
531         debugError("Could not read from node 0x%04X addr 0x%012X\n", nodeId, addr);
532         return false;
533     }
534     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Read result: 0x%08X\n", *result);
535    
536     return true;
537 }
538
539 bool
540 BounceDevice::writeReg(fb_nodeaddr_t offset, fb_quadlet_t data) {
541     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, data: 0x%08X\n", 
542         offset, data);
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_quadlet( nodeId, addr, data ) ) {
553         debugError("Could not write to node 0x%04X addr 0x%012X\n", nodeId, addr);
554         return false;
555     }
556     return true;
557 }
558
559 bool
560 BounceDevice::readRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
561     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX, length %u\n",
562         offset, length);
563    
564     if(offset >= BOUNCE_INVALID_OFFSET) {
565         debugError("invalid offset: 0x%016llX\n", offset);
566         return false;
567     }
568    
569     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
570     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
571    
572     if(!m_p1394Service->read( nodeId, addr, length, data ) ) {
573         debugError("Could not read from node 0x%04X addr 0x%012llX\n", nodeId, addr);
574         return false;
575     }
576     return true;
577 }
578
579 bool
580 BounceDevice::writeRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
581     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, length: %u\n", 
582         offset, length);
583    
584     if(offset >= BOUNCE_INVALID_OFFSET) {
585         debugError("invalid offset: 0x%016llX\n", offset);
586         return false;
587     }
588    
589     fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
590     fb_nodeid_t nodeId=m_nodeId | 0xFFC0;
591
592     if(!m_p1394Service->write( nodeId, addr, length, data ) ) {
593         debugError("Could not write to node 0x%04X addr 0x%012llX\n", nodeId, addr);
594         return false;
595     }
596     return true;
597 }
598
599
600 } // namespace
Note: See TracBrowser for help on using the browser.