root/branches/streaming-rework/src/libosc/OscNode.cpp

Revision 432, 7.9 kB (checked in by pieterpalmers, 15 years ago)

- extended OSC support

Line 
1 /* $Id$ */
2
3 /*
4  *   FreeBob Streaming API
5  *   FreeBob = Firewire (pro-)audio for linux
6  *
7  *   http://freebob.sf.net
8  *
9  *   Copyright (C) 2007 Pieter Palmers <pieterpalmers@users.sourceforge.net>
10  *
11  *   This program is free software {} you can redistribute it and/or modify
12  *   it under the terms of the GNU General Public License as published by
13  *   the Free Software Foundation {} either version 2 of the License, or
14  *   (at your option) any later version.
15  *
16  *   This program is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY {} without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with this program {} if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  */
26
27 #include "OscNode.h"
28 #include "OscMessage.h"
29 #include "OscResponse.h"
30 #include <assert.h>
31
32 namespace OSC {
33
34 IMPL_DEBUG_MODULE( OscNode, OscNode, DEBUG_LEVEL_VERBOSE );
35
36 OscNode::OscNode()
37     : m_oscBase("")
38     , m_oscAutoDelete(false)
39 {}
40
41 OscNode::OscNode(string b)
42     : m_oscBase(b)
43     , m_oscAutoDelete(false)
44 {}
45
46 OscNode::OscNode(string b, bool autodelete)
47     : m_oscBase(b)
48     , m_oscAutoDelete(autodelete)
49 {}
50
51 OscNode::~OscNode() {
52     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Removing child nodes\n");
53
54     for ( OscNodeVectorIterator it = m_ChildNodes.begin();
55       it != m_ChildNodes.end();
56       ++it )
57     {
58         if((*it)->doOscNodeAutoDelete()) {
59             debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " Auto-deleting child node %s\n",
60                          (*it)->getOscBase().c_str());
61             delete (*it);
62         }
63     }
64 }
65
66 // generic message processing
67 OscResponse
68 OscNode::processOscMessage(string path, OscMessage *m)
69 {
70     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) MSG: %s\n",this, path.c_str());
71    
72     // delete leading slash
73     if(path.find_first_of('/')==0) path=path.substr(1,path.size());
74    
75     // delete trailing slash
76     if(path.find_last_of('/')==path.size()-1) path=path.substr(0,path.size()-1);
77    
78     // continue processing
79     int firstsep=path.find_first_of('/');
80
81     if (firstsep == -1) {
82         OscResponse retVal;
83        
84         // process the message
85         retVal=processOscMessage(m);
86        
87         if(retVal.isHandled()) {
88             return retVal; // completely handled
89         } else { // (partially) unhandled
90             return processOscMessageDefault(m, retVal);
91         }
92
93     } else { // it targets a deeper node
94         string newpath=path.substr(firstsep+1);
95         int secondsep=newpath.find_first_of('/');
96         string newbase;
97         if (secondsep==-1) {
98             newbase=newpath;
99         } else {
100             newbase=path.substr(firstsep+1,secondsep);
101         }
102
103         for ( OscNodeVectorIterator it = m_ChildNodes.begin();
104           it != m_ChildNodes.end();
105           ++it )
106         {
107             if((*it)->getOscBase() == newbase) {
108                 return (*it)->processOscMessage(newpath,m);
109             }
110         }
111         debugOutput( DEBUG_LEVEL_VERBOSE, "Child node %s not found \n",newbase.c_str());
112        
113         return OscResponse(OscResponse::eError);
114     }
115     return OscResponse(OscResponse::eError);
116 }
117
118 // default handlers
119
120 // overload this to make a node process a message
121 OscResponse
122 OscNode::processOscMessage(OscMessage *m)
123 {
124     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) MSG PROCESS: %s\n", this, m->getPath().c_str());
125     m->print();
126     return OscResponse(OscResponse::eUnhandled); // handled but no response
127 }
128
129 // this provides support for messages that are
130 // supported by all nodes
131 OscResponse
132 OscNode::processOscMessageDefault(OscMessage *m, OscResponse r)
133 {
134     unsigned int nbArgs=m->nbArguments();
135     if (nbArgs>=1) {
136         OscArgument arg0=m->getArgument(0);
137         if(arg0.isString()) { // first argument should be a string command
138             string cmd=arg0.getString();
139             debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) CMD? %s\n", this, cmd.c_str());
140             if(cmd == "list") {
141                 debugOutput( DEBUG_LEVEL_VERBOSE, "Listing node children...\n");
142                 OscMessage rm=oscListChildren(r.getMessage());
143                 return OscResponse(rm);
144             }
145         }
146     }
147     // default action: don't change response
148     return r;
149 }
150
151 OscMessage
152 OscNode::oscListChildren(OscMessage m) {
153    
154     for ( OscNodeVectorIterator it = m_ChildNodes.begin();
155       it != m_ChildNodes.end();
156       ++it )
157     {
158         m.addArgument((*it)->getOscBase());
159     }
160     m.print();
161     return m;
162 }
163
164 // child management
165
166 bool
167 OscNode::addChildOscNode(OscNode *n)
168 {
169     assert(n);
170    
171     debugOutput( DEBUG_LEVEL_VERBOSE, "Adding child node %s\n",n->getOscBase().c_str());
172     for ( OscNodeVectorIterator it = m_ChildNodes.begin();
173       it != m_ChildNodes.end();
174       ++it )
175     {
176         if(*it == n) {
177             debugOutput( DEBUG_LEVEL_VERBOSE,
178                 "Child node %s already registered\n",
179                 n->getOscBase().c_str());
180             return false;
181         }
182     }
183     m_ChildNodes.push_back(n);
184     return true;
185 }
186
187 /**
188  * Add a child node under a certain path.
189  * e.g. if you have a node with base 'X' and
190  * you want it to be at /base/level1/level2/X
191  * you would add it using this function, by
192  *  addChildOscNode(n, "/base/level1/level2")
193  *
194  * @param n
195  * @param 
196  * @return
197  */
198 bool
199 OscNode::addChildOscNode(OscNode *n, string path)
200 {
201     debugOutput( DEBUG_LEVEL_VERBOSE, "add node to: %s\n",path.c_str());
202    
203     // delete leading slashes
204     if(path.find_first_of('/')==0) path=path.substr(1,path.size());
205    
206     // delete trailing slashes
207     if(path.find_last_of('/')==path.size()-1) path=path.substr(0,path.size()-1);
208    
209     // continue processing
210     int firstsep=path.find_first_of('/');
211
212     if (firstsep == -1) {
213         return addChildOscNode(n);
214     } else { // it targets a deeper node
215         string newpath=path.substr(firstsep+1);
216         int secondsep=newpath.find_first_of('/');
217         string newbase;
218         if (secondsep==-1) {
219             newbase=newpath;
220         } else {
221             newbase=path.substr(firstsep+1,secondsep);
222         }
223
224         // if the path is already present, find it
225         for ( OscNodeVectorIterator it = m_ChildNodes.begin();
226           it != m_ChildNodes.end();
227           ++it )
228         {
229             if((*it)->getOscBase() == newbase) {
230                 return (*it)->addChildOscNode(n,newpath);
231             }
232         }
233         debugOutput( DEBUG_LEVEL_VERBOSE, "node %s not found, creating auto-node\n",newbase.c_str());
234        
235         OscNode *autoNode=new OscNode(newbase,true);
236        
237         // add the auto-node to this node
238         m_ChildNodes.push_back(autoNode);
239        
240         // add the child to the node
241         return autoNode->addChildOscNode(n,newpath);
242     }
243     return false;
244 }
245
246 bool
247 OscNode::removeChildOscNode(OscNode *n)
248 {
249     assert(n);
250     debugOutput( DEBUG_LEVEL_VERBOSE, "Removing child node %s\n",n->getOscBase().c_str());
251
252     for ( OscNodeVectorIterator it = m_ChildNodes.begin();
253       it != m_ChildNodes.end();
254       ++it )
255     {
256         if(*it == n) {
257             m_ChildNodes.erase(it);
258             if((*it)->doOscNodeAutoDelete()) {
259                 debugOutput( DEBUG_LEVEL_VERBOSE, " Auto-deleting child node %s\n",n->getOscBase().c_str());
260                 delete (*it);
261             }
262             return true;
263         }
264     }
265
266     debugOutput( DEBUG_LEVEL_VERBOSE, "Child node %s not found \n",n->getOscBase().c_str());
267    
268     return false; //not found
269 }
270
271 void
272 OscNode::printOscNode()
273 {
274     printOscNode("");
275 }
276
277 void
278 OscNode::printOscNode(string path)
279 {
280     debugOutput( DEBUG_LEVEL_NORMAL, "%s/%s\n",
281                  path.c_str(),getOscBase().c_str());
282
283     for ( OscNodeVectorIterator it = m_ChildNodes.begin();
284       it != m_ChildNodes.end();
285       ++it )
286     {
287         (*it)->printOscNode(path+"/"+getOscBase());
288     }
289 }
290
291 } // end of namespace OSC
Note: See TracBrowser for help on using the browser.