root/trunk/libffado/src/libosc/OscNode.cpp

Revision 560, 8.7 kB (checked in by ppalmers, 16 years ago)

- Sort the FFADODevice vector on GUID before assigning device id's

This results in the same device id for identical device setups,
independent of the way they are connected or the node numbers they
have been assigned.

- Sanitized debug message reporting a bit
- Cosmetic changes

Line 
1 /*
2  * Copyright (C) 2005-2007 by Pieter Palmers
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 "OscNode.h"
25 #include "OscMessage.h"
26 #include "OscResponse.h"
27 #include <assert.h>
28
29 namespace OSC {
30
31 IMPL_DEBUG_MODULE( OscNode, OscNode, DEBUG_LEVEL_NORMAL );
32
33 OscNode::OscNode()
34     : m_oscBase("")
35     , m_oscAutoDelete(false)
36 {}
37
38 OscNode::OscNode(string b)
39     : m_oscBase(b)
40     , m_oscAutoDelete(false)
41 {}
42
43 OscNode::OscNode(string b, bool autodelete)
44     : m_oscBase(b)
45     , m_oscAutoDelete(autodelete)
46 {}
47
48 OscNode::~OscNode() {
49     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Removing child nodes\n");
50
51     for ( OscNodeVectorIterator it = m_ChildNodes.begin();
52       it != m_ChildNodes.end();
53       ++it )
54     {
55         if((*it)->doOscNodeAutoDelete()) {
56             debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " Auto-deleting child node %s\n",
57                          (*it)->getOscBase().c_str());
58             delete (*it);
59         }
60     }
61 }
62
63 void
64 OscNode::setVerboseLevel(int l) {
65     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
66     setDebugLevel(l);
67     for ( OscNodeVectorIterator it = m_ChildNodes.begin();
68       it != m_ChildNodes.end();
69       ++it )
70     {
71         (*it)->setVerboseLevel(l);
72     }
73 }
74
75 // generic message processing
76 OscResponse
77 OscNode::processOscMessage(string path, OscMessage *m)
78 {
79     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) {%s} MSG: %s\n", this, m_oscBase.c_str(), path.c_str());
80
81     // delete leading slash
82     if(path.find_first_of('/')==0) path=path.substr(1,path.size());
83
84     // delete trailing slash
85     if(path.find_last_of('/')==path.size()-1) path=path.substr(0,path.size()-1);
86
87     // continue processing
88     int firstsep=path.find_first_of('/');
89
90     if (firstsep == -1) {
91         OscResponse retVal;
92
93         // process the message
94         m->setPath(""); // handled by the node itself
95         retVal=processOscMessage(m);
96
97         if(retVal.isHandled()) {
98             return retVal; // completely handled
99         } else { // (partially) unhandled
100             return processOscMessageDefault(m, retVal);
101         }
102
103     } else { // it targets a deeper node
104         OscResponse retVal;
105        
106         string newpath=path.substr(firstsep+1);
107         int secondsep=newpath.find_first_of('/');
108         string newbase;
109         if (secondsep==-1) {
110             newbase=newpath;
111         } else {
112             newbase=path.substr(firstsep+1,secondsep);
113         }
114
115         // first try to find a child node that might be able
116         // to handle this.
117         // NOTE: the current model allows only one node to
118         //       handle a request, and then the default
119         //       handler.
120         for ( OscNodeVectorIterator it = m_ChildNodes.begin();
121           it != m_ChildNodes.end();
122           ++it )
123         {
124             if((*it)->getOscBase() == newbase) {
125                 return (*it)->processOscMessage(newpath,m);
126             }
127         }
128        
129         // The path is not registered as a child node.
130         // This node should handle it
131         debugOutput( DEBUG_LEVEL_VERBOSE, "Child node %s not found \n",newbase.c_str());
132
133         m->setPath(newpath); // the remaining portion of the path
134         retVal=processOscMessage(m);
135
136         if(retVal.isHandled()) {
137             return retVal; // completely handled
138         }
139         // (partially) unhandled
140         return processOscMessageDefault(m, retVal);
141     }
142     return OscResponse(OscResponse::eError);
143 }
144
145 // default handlers
146
147 // overload this to make a node process a message
148 OscResponse
149 OscNode::processOscMessage(OscMessage *m)
150 {
151     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) {%s} DEFAULT PROCESS: %s\n", this, m_oscBase.c_str(), m->getPath().c_str());
152     m->print();
153     return OscResponse(OscResponse::eUnhandled); // handled but no response
154 }
155
156 // this provides support for messages that are
157 // supported by all nodes
158 OscResponse
159 OscNode::processOscMessageDefault(OscMessage *m, OscResponse r)
160 {
161     unsigned int nbArgs=m->nbArguments();
162     if (nbArgs>=1) {
163         OscArgument arg0=m->getArgument(0);
164         if(arg0.isString()) { // first argument should be a string command
165             string cmd=arg0.getString();
166             debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) CMD? %s\n", this, cmd.c_str());
167             if(cmd == "list") {
168                 debugOutput( DEBUG_LEVEL_VERBOSE, "Listing node children...\n");
169                 OscMessage rm=oscListChildren(r.getMessage());
170                 return OscResponse(rm);
171             }
172         }
173     }
174     // default action: don't change response
175     return r;
176 }
177
178 OscMessage
179 OscNode::oscListChildren(OscMessage m) {
180
181     for ( OscNodeVectorIterator it = m_ChildNodes.begin();
182       it != m_ChildNodes.end();
183       ++it )
184     {
185         m.addArgument((*it)->getOscBase());
186     }
187     m.print();
188     return m;
189 }
190
191 // child management
192
193 bool
194 OscNode::addChildOscNode(OscNode *n)
195 {
196     assert(n);
197
198     debugOutput( DEBUG_LEVEL_VERBOSE, "Adding child node %s\n",n->getOscBase().c_str());
199     for ( OscNodeVectorIterator it = m_ChildNodes.begin();
200       it != m_ChildNodes.end();
201       ++it )
202     {
203         if(*it == n) {
204             debugOutput( DEBUG_LEVEL_VERBOSE,
205                 "Child node %s already registered\n",
206                 n->getOscBase().c_str());
207             return false;
208         }
209     }
210     m_ChildNodes.push_back(n);
211     return true;
212 }
213
214 /**
215  * Add a child node under a certain path.
216  * e.g. if you have a node with base 'X' and
217  * you want it to be at /base/level1/level2/X
218  * you would add it using this function, by
219  *  addChildOscNode(n, "/base/level1/level2")
220  *
221  * @param n
222  * @param
223  * @return
224  */
225 bool
226 OscNode::addChildOscNode(OscNode *n, string path)
227 {
228     debugOutput( DEBUG_LEVEL_VERBOSE, "add node to: %s\n",path.c_str());
229
230     // delete leading slashes
231     if(path.find_first_of('/')==0) path=path.substr(1,path.size());
232
233     // delete trailing slashes
234     if(path.find_last_of('/')==path.size()-1) path=path.substr(0,path.size()-1);
235
236     // continue processing
237     int firstsep=path.find_first_of('/');
238
239     if (firstsep == -1) {
240         return addChildOscNode(n);
241     } else { // it targets a deeper node
242         string newpath=path.substr(firstsep+1);
243         int secondsep=newpath.find_first_of('/');
244         string newbase;
245         if (secondsep==-1) {
246             newbase=newpath;
247         } else {
248             newbase=path.substr(firstsep+1,secondsep);
249         }
250
251         // if the path is already present, find it
252         for ( OscNodeVectorIterator it = m_ChildNodes.begin();
253           it != m_ChildNodes.end();
254           ++it )
255         {
256             if((*it)->getOscBase() == newbase) {
257                 return (*it)->addChildOscNode(n,newpath);
258             }
259         }
260         debugOutput( DEBUG_LEVEL_VERBOSE, "node %s not found, creating auto-node\n",newbase.c_str());
261
262         OscNode *autoNode=new OscNode(newbase,true);
263
264         // add the auto-node to this node
265         m_ChildNodes.push_back(autoNode);
266
267         // add the child to the node
268         return autoNode->addChildOscNode(n,newpath);
269     }
270     return false;
271 }
272
273 bool
274 OscNode::removeChildOscNode(OscNode *n)
275 {
276     assert(n);
277     debugOutput( DEBUG_LEVEL_VERBOSE, "Removing child node %s\n",n->getOscBase().c_str());
278
279     for ( OscNodeVectorIterator it = m_ChildNodes.begin();
280       it != m_ChildNodes.end();
281       ++it )
282     {
283         if(*it == n) {
284             m_ChildNodes.erase(it);
285             if((*it)->doOscNodeAutoDelete()) {
286                 debugOutput( DEBUG_LEVEL_VERBOSE, " Auto-deleting child node %s\n",n->getOscBase().c_str());
287                 delete (*it);
288             }
289             return true;
290         }
291     }
292
293     debugOutput( DEBUG_LEVEL_VERBOSE, "Child node %s not found \n",n->getOscBase().c_str());
294
295     return false; //not found
296 }
297
298 void
299 OscNode::printOscNode()
300 {
301     printOscNode("");
302 }
303
304 void
305 OscNode::printOscNode(string path)
306 {
307     debugOutput( DEBUG_LEVEL_NORMAL, "%s/%s\n",
308                  path.c_str(),getOscBase().c_str());
309
310     for ( OscNodeVectorIterator it = m_ChildNodes.begin();
311       it != m_ChildNodes.end();
312       ++it )
313     {
314         (*it)->printOscNode(path+"/"+getOscBase());
315     }
316 }
317
318 } // end of namespace OSC
Note: See TracBrowser for help on using the browser.