Jamoma API  0.6.0.a19
OSC.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup modularOSC
4  *
5  * @brief The OSC Protocol
6  *
7  * @details
8  *
9  * @authors Théo de la Hogue
10  *
11  * @copyright © 2013, Théo de la Hogue @n
12  * This code is licensed under the terms of the "New BSD License" @n
13  * http://creativecommons.org/licenses/BSD/
14  */
15 
16 
17 #include "TTProtocol.h"
18 #include "OSC.h"
19 
20 #define thisTTClass OSC
21 #define thisTTClassName "OSC"
22 #define thisTTClassTags "network, protocol, osc"
23 
24 #define thisProtocolVersion "0.1"
25 #define thisProtocolAuthor "Theo de la Hogue"
26 #define thisProtocolGet NO
27 #define thisProtocolSet YES
28 #define thisProtocolListen NO
29 #define thisProtocolDiscover NO
30 #define thisProtocolDiscoverAll NO
31 
32 extern "C" TT_EXTENSION_EXPORT TTErr TTLoadJamomaExtension_OSC(void)
33 {
34  TTFoundationInit();
35  OSC::registerClass();
36  return kTTErrNone;
37 }
38 
40 mSenderManager(NULL)
41 {
43 
46 
47  addMessageWithArguments(receivedMessage);
48  addMessageProperty(receivedMessage, hidden, YES);
49 }
50 
51 OSC::~OSC()
52 {
53  TTValue keys, out;
54  TTSymbol distantApplicationName;
55  TTUInt16 i;
56 
57  // Stop all distant applications
58  mDistantApplicationOscReceivers.getKeys(keys);
59  for (i = 0; i < keys.size(); i++) {
60 
61  distantApplicationName = keys[i];
62  Stop(distantApplicationName, out);
63  }
64 
65  // Stop local application
66  Stop(kTTValNONE, out);
67 
68  // release the sender manager
69  if (mSenderManager)
70  delete mSenderManager;
71 }
72 
73 TTErr OSC::getParameterNames(TTValue& value)
74 {
75  value.clear();
76  value.append(TTSymbol("ip"));
77  value.append(TTSymbol("port"));
78 
79  return kTTErrNone;
80 }
81 
82 TTErr OSC::Scan(const TTValue& inputValue, TTValue& outputValue)
83 {
84  // TODO : using Bonjour
85  return kTTErrGeneric;
86 }
87 
88 /*!
89  * Run the arguments reception thread
90  * Prepare the receive callback method to be passed to the ApplicationManager to intercept the arguments
91  *
92  */
93 TTErr OSC::Run(const TTValue& inputValue, TTValue& outputValue)
94 {
95  // run OSC for all applications
96  if (inputValue.size() == 0) {
97 
98  TTValue keys;
99  TTErr err = kTTErrNone;
100 
101  outputValue.clear();
102 
103  mApplicationParameters.getKeys(keys);
104  for (TTUInt32 i = 0 ; i < keys.size() ; i++)
105  if (Run(keys[i], outputValue))
106  err = kTTErrGeneric;
107 
108  return err;
109  }
110 
111  // run OSC for one application
112  TTSymbol applicationName;
113  TTErr err;
114 
115  if (inputValue.size() == 1) {
116 
117  if (inputValue[0].type() == kTypeSymbol)
118 
119  applicationName = inputValue[0];
120  }
121 
122  // for any application
123  if (!mRunning) {
124 
125  // instantiate the sender manager
126  mSenderManager = new OSCSenderManager();
127  }
128 
129  // for local application
130  if (applicationName == mLocalApplicationName) {
131 
132  if (!mRunning) {
133 
134  // create an osc.receiver local application
135  mLocalApplicationOscReceiver = TTObject("osc.receive");
136 
137  if (mLocalApplicationOscReceiver.valid()) {
138 
139  TTValue v;
140  TTObject oscProtocol(this);
141  TTUInt16 port;
142 
143  // select local application to get its port parameter
144  ApplicationSelectLocal();
145  oscProtocol.get("port", v);
146 
147  port = v[0];
148 
149  err = mLocalApplicationOscReceiver.set("port", port);
150 
151  if (!err) {
152 
153  // register for notification using our 'receivedMessage' method
154  mLocalApplicationOscReceiver.registerObserverForNotifications(oscProtocol);
155 
156  mRunning = YES;
157 
158  TTLogMessage("OSC::Run : connected to port %ld for local application\n", port);
159 
160  return kTTErrNone;
161  }
162  else {
163 
164  // return the port
165  outputValue.append(port);
166 
167  TTLogError("OSC::Run : unable to connect to port %ld for local application\n", port);
168  }
169  }
170  }
171  else
172  return kTTErrNone;
173  }
174 
175  // for distant application case
176  else {
177 
178  TTValue v, args;
179  TTHashPtr parameters;
180  TTObject anOscReceiver, returnMessageCallback;
181  TTValue returnMessageBaton;
182  TTUInt16 receptionPort;
183 
184  // if the application have already a reception thread : return an error
185  if (!mDistantApplicationOscReceivers.lookup(applicationName, v))
186  return kTTErrGeneric;
187 
188  // get application parameters
189  err = mApplicationParameters.lookup(applicationName, v);
190 
191  if (!err) {
192 
193  parameters = TTHashPtr((TTPtr)v[0]);
194 
195  if (parameters) {
196 
197  // get port attribute
198  err = parameters->lookup(TTSymbol("port"), v);
199 
200  if (!err && v.size() == 2) {
201 
202  // the second port is for reception
203  receptionPort = v[1];
204 
205  // prepare arguments
206  returnMessageCallback = TTObject("callback");
207 
208  returnMessageBaton = TTValue(TTObject(this), applicationName);
209  returnMessageCallback.set(kTTSym_baton, returnMessageBaton);
210 
211  returnMessageCallback.set(kTTSym_function, TTPtr(&OSCReceiveMessageCallback));
212 
213  // create an osc.receive instance
214  anOscReceiver = TTObject("osc.receive", returnMessageCallback);
215 
216  if (anOscReceiver.valid()) {
217 
218  err = anOscReceiver.set("port", receptionPort);
219 
220  if (!err) {
221 
222  // don't register for notification because we use callback mechanism
223 
224  // append the osc.receive to the table
225  mDistantApplicationOscReceivers.append(applicationName, anOscReceiver);
226 
227  mRunning = YES;
228 
229  TTLogMessage("OSC::Run : connected to port %ld for %s application\n", receptionPort, applicationName.c_str());
230 
231  return kTTErrNone;
232  }
233  else {
234 
235  // return the port
236  outputValue.append(receptionPort);
237 
238  TTLogError("OSC::Run : unable to connect to port %ld for %s application\n", receptionPort, applicationName.c_str());
239  }
240  }
241  }
242  }
243  }
244  }
245 
246  return kTTErrGeneric;
247 }
248 
249 /*!
250  * Stop the arguments reception thread
251  *
252  */
253 TTErr OSC::Stop(const TTValue& inputValue, TTValue& outputValue)
254 {
255  // run OSC for all applications
256  if (inputValue.size() == 0) {
257 
258  TTValue keys, out;
259 
260  // stop local
261  Stop(mLocalApplicationName, out);
262 
263  // stop each distant
264  mApplicationParameters.getKeys(keys);
265  for (TTUInt32 i = 0 ; i < keys.size() ; i++)
266  Stop(keys[i], out);
267 
268  return kTTErrNone;
269  }
270 
271  // stop OSC for one application
272  TTSymbol applicationName;
273 
274  if (inputValue.size() == 1) {
275 
276  if (inputValue[0].type() == kTypeSymbol)
277 
278  applicationName = inputValue[0];
279  }
280 
281  // for any application
282  if (mRunning) {
283 
284  // release the sender manager
285  delete mSenderManager;
286  mSenderManager = NULL;
287  }
288 
289  // for local application
290  if (applicationName == mLocalApplicationName) {
291 
292  if (mRunning) {
293 
294  // delete osc.receive dedicated to local application
295  mLocalApplicationOscReceiver = TTObject();
296 
297  mRunning = NO;
298 
299  return kTTErrNone;
300  }
301  }
302 
303  // for distant application case
304  else {
305 
306  TTValue v;
307 
308  // if the application have a reception thread
309  if (!mDistantApplicationOscReceivers.lookup(applicationName, v)) {
310 
311  // remove key
312  mDistantApplicationOscReceivers.remove(applicationName);
313 
314  mRunning = NO;
315 
316  return kTTErrNone;
317  }
318  }
319 
320  return kTTErrGeneric;
321 }
322 
323 /**************************************************************************************************************************
324  *
325  * SEND REQUEST METHODS
326  *
327  **************************************************************************************************************************/
328 
329 /*!
330  * Send a discover request to an application to get a part of the namespace at the given address
331  *
332  * \param to : the application where to discover
333  * \param address : the address to discover
334  * \param returnedType : the type of the node at the address (default is none which means no type)
335  * \param returnedChildren : all names of nodes below the address
336  * \param returnedAttributes : all attributes the node at the address
337  * \param tryCount : number of try for this request
338  * \return errorcode : kTTErrNone means the answer has been received, kTTErrValueNotFound means something is bad in the request
339  else it returns kTTErrGeneric if no answer or timeout
340  */
341 TTErr OSC::SendDiscoverRequest(TTSymbol to, TTAddress address,
342  TTSymbol& returnedType,
343  TTValue& returnedChildren,
344  TTValue& returnedAttributes,
345  TTUInt8 tryCount)
346 {
347  return kTTErrGeneric;
348 }
349 
350 /*!
351  * Send a discover all request to an application to fill all the directory under this address
352  *
353  * \param to : the application where to discover
354  * \param address : the address to discover
355  * \param node : the node for this address
356  * \param tryCount : number of try for this request
357  * \return errorcode : kTTErrNone means the answer has been received, kTTErrValueNotFound means something is bad in the request
358  else it returns kTTErrGeneric if no answer or timeout
359  */
360 TTErr OSC::SendDiscoverAllRequest(TTSymbol to, TTAddress address,
361  TTNodePtr node,
362  TTUInt8 tryCount)
363 {
364  return kTTErrGeneric;
365 }
366 
367 /*!
368  * Send a get request to an application to get a value at the given address
369  *
370  * \param to : the application where to get
371  * \param address : the address to get
372  * \param returnedValue : the value which is going to be filled
373  * \param tryCount : number of try for this request
374  * \return errorcode : kTTErrNone means the answer has been received, kTTErrValueNotFound means something is bad in the request
375  else it returns kTTErrGeneric if no answer or timeout
376  */
377 TTErr OSC::SendGetRequest(TTSymbol to, TTAddress address,
378  TTValue& returnedValue,
379  TTUInt8 tryCount)
380 {
381  return kTTErrGeneric;
382 }
383 
384 /*!
385  * Send a set request to set a value of a specific application
386  *
387  * \param to : the application where to set
388  * \param address : the address to set
389  * \param value : anything to send
390  * \param tryCount : number of try for this request
391  * \return errorcode : kTTErrNone means the answer has been received, kTTErrValueNotFound means something is bad in the request
392  */
393 TTErr OSC::SendSetRequest(TTSymbol to, TTAddress address,
394  TTValue& value,
395  TTUInt8 tryCount)
396 {
397  // avoid loop (see in OSCReceiveMessageCallback)
398  if (address == mReceivedAddress && to == mReceivedFrom)
399  return kTTErrGeneric;
400 
401 #ifdef TT_PROTOCOL_DEBUG
402  std::cout << "OSC::SendSetRequest : to " << address.c_str() << std::endl;
403 #endif
404 
405  if (address.getAttribute() == kTTSym_value)
406  return sendMessage(to, address.removeAttribute(), value);
407  else
408  return sendMessage(to, address, value);
409 }
410 
411 /*!
412  * Send a listen request to a specific application
413  *
414  * \param to : the application where to listen
415  * \param address : the address to listen
416  * \param enable : enable/disable the listening
417  * \param tryCount : number of try for this request
418  * \return errorcode : kTTErrNone means the answer has been received, kTTErrValueNotFound means something is bad in the request
419  */
420 TTErr OSC::SendListenRequest(TTSymbol to, TTAddress address,
421  TTBoolean enable,
422  TTUInt8 tryCount)
423 {
424  return kTTErrGeneric;
425 }
426 
427 
428 /**************************************************************************************************************************
429  *
430  * SEND ANSWER METHODS
431  *
432  **************************************************************************************************************************/
433 
434 /*!
435  * Send a disover answer to a application which ask for.
436  *
437  * \param to : the application where to send answer
438  * \param address : the address where comes from the description
439  * \param returnedType : the type of the node at the address (default is none which means no type)
440  * \param returnedChildren : all names of nodes below the address
441  * \param returnedAttributes : all attributes the node at the address
442  */
443 TTErr OSC::SendDiscoverAnswer(TTSymbol to, TTAddress address,
444  TTSymbol& returnedType,
445  TTValue& returnedChildren,
446  TTValue& returnedAttributes,
447  TTErr err)
448 {
449  return kTTErrGeneric;
450 }
451 
452 /*!
453  * Send a discover answer to a application which ask for.
454  *
455  * \param to : the application where to send answer
456  * \param address : the address where comes from the description
457  * \param node : the node for this address
458  */
459 TTErr OSC::SendDiscoverAllAnswer(TTSymbol to, TTAddress address,
460  TTNodePtr node,
461  TTErr err)
462 {
463  return kTTErrGeneric;
464 }
465 
466 /*!
467  * Send a get answer to an application which ask for.
468  *
469  * \param to : the application where to send answer
470  * \param address : the address where comes from the value
471  * \param returnedValue : the value of the attribute at the address
472  */
473 TTErr OSC::SendGetAnswer(TTSymbol to, TTAddress address,
474  const TTValue& returnedValue,
475  TTErr err)
476 {
477  return kTTErrGeneric;
478 }
479 
480 /*!
481  * Send a listen answer to an application which ask for.
482  *
483  * \param to : the application where to send answer
484  * \param address : the address where comes from the value
485  * \param returnedValue : the value of the attribute at the address
486  */
487 TTErr OSC::SendListenAnswer(TTSymbol to, TTAddress address,
488  const TTValue& returnedValue,
489  TTErr err)
490 {
491  return kTTErrGeneric;
492 }
493 
494 TTErr OSC::sendMessage(TTSymbol applicationName, TTSymbol header, TTValue& arguments)
495 {
496  if (!mSenderManager)
497  return kTTErrGeneric;
498 
499  // Check application registration
500  TTValue v;
501  TTErr err = mApplicationParameters.lookup(applicationName, v);
502 
503  if (!err)
504  {
505  TTHashPtr parameters = TTHashPtr((TTPtr)v[0]);
506  TTValue vIp, vPort;
507  TTErr errIp = parameters->lookup(TTSymbol("ip"), vIp);
508  TTErr errPort = parameters->lookup(TTSymbol("port"), vPort);
509 
510  if (errIp || errPort)
511  return kTTErrGeneric;
512 
513  TTValue message(header);
514  message.append((TTPtr)&arguments);
515 
516  err = mSenderManager->send(applicationName, vIp, vPort, message);
517 
518  if (err)
519  {
520  ; // can't send message to the application because the osc.sender is busy
521  ; // TODO : have bundle system
522 
523  }
524 
525  else if (mActivity)
526  {
527  v = arguments;
528  v.prepend(header);
529  ActivityOutMessage(v);
530  }
531  }
532 
533  return err;
534 }
535 
536 TTErr OSC::receivedMessage(const TTValue& message, TTValue& outputValue)
537 {
538  TTSymbol aSymbol;
539  TTString headerString;
540  TTValue arguments;
541  TTAddress whereTo = kTTAdrsEmpty;
542 
543  /*
544  if message starts with '/'
545  */
546 
547  if (mActivity) ActivityInMessage(message);
548 
549  aSymbol = message[0];
550  headerString = aSymbol.string();
551 
552  // if message starts with '/'
553  if (headerString[0] == '/')
554  {
555  whereTo = TTAddress(aSymbol.c_str());
556  arguments.copyFrom(message, 1);
557 
558 #ifdef TT_PROTOCOL_DEBUG
559  cout << "OSC::receivedMessage : at " << whereTo.c_str() << endl;
560 #endif
561 
562  return ReceiveSetRequest(kTTSymEmpty, whereTo, arguments);
563  }
564 
565  return kTTErrGeneric;
566 }
567 
568 TTErr OSCReceiveMessageCallback(const TTValue& baton, const TTValue& data)
569 {
570  TTObject o;
571  OSCPtr anOscProtocol;
572  TTSymbol from, aSymbol;
573  TTString headerString;
574  TTValue arguments;
575  TTErr err;
576 
577  // unpack baton
578  o = baton[0];
579  anOscProtocol = (OSCPtr)o.instance();
580  from = baton[1];
581 
582  // clear mReceiveFrom and mReceivedAddress
583  anOscProtocol->mReceivedFrom = kTTSymEmpty;
584  anOscProtocol->mReceivedAddress = kTTAdrsEmpty;
585 
586  /*
587  if message starts with '/'
588  */
589 
590  if (anOscProtocol->mActivity) anOscProtocol->ActivityInMessage(data);
591 
592  aSymbol = data[0];
593  headerString = aSymbol.string();
594 
595  // if message starts with '/'
596  if (headerString[0] == '/')
597  {
598  // meorize who send the message and the address to avoid loop
599  anOscProtocol->mReceivedFrom = from;
600  anOscProtocol->mReceivedAddress = TTAddress(aSymbol.c_str());
601  if (anOscProtocol->mReceivedAddress.getAttribute() == NO_ATTRIBUTE)
602  anOscProtocol->mReceivedAddress = anOscProtocol->mReceivedAddress.appendAttribute(kTTSym_value);
603 
604  arguments.copyFrom(data, 1);
605 
606 #ifdef TT_PROTOCOL_DEBUG
607  cout << "OSCReceiveMessageCallback : from " << from.c_str() << " at " << anOscProtocol->mReceivedAddress.c_str() << endl;
608 #endif
609 
610  err = anOscProtocol->ReceiveListenAnswer(from, anOscProtocol->mReceivedAddress, arguments);
611 
612  // clear mReceiveFrom and mReceivedAddress
613  anOscProtocol->mReceivedFrom = kTTSymEmpty;
614  anOscProtocol->mReceivedAddress = kTTAdrsEmpty;
615 
616  return err;
617  }
618 
619  return kTTErrGeneric;
620 }
TTErr sendMessage(const TTSymbol name)
TODO: Document this function.
bool TTBoolean
Boolean flag, same as Boolean on the Mac.
Definition: TTBase.h:167
std::uint16_t TTUInt16
16 bit unsigned integer
Definition: TTBase.h:176
#define TT_PROTOCOL_INITIALIZE
Declares all members needed by any protocol class.
Definition: TTProtocol.h:31
TTAddress appendAttribute(TTSymbol anAttribute)
Return a new TTAddress with attribute part.
Definition: TTAddress.h:161
TTErr lookup(const TTSymbol key, TTValue &value)
Find the value for the given key.
Definition: TTHash.cpp:76
We build a directory of TTNodes, and you can request a pointer for any TTNode, or add an observer to ...
Definition: TTNode.h:59
void copyFrom(const TTValue &obj, TTUInt16 index)
Copy a value starting from an index until the last element.
Definition: TTValue.h:147
The TTAddress class is used to represent a string and efficiently pass and compare that string...
Definition: TTAddress.h:29
Create and use Jamoma object instances.
Definition: TTObject.h:29
size_type size() const noexcept
Return the number of elements.
Maintain a collection of TTValue objects indexed by TTSymbol pointers.
Definition: TTHash.h:36
Symbol type.
Definition: TTBase.h:282
TTErr OSCReceiveMessageCallback(const TTValue &baton, const TTValue &data)
Definition: OSC.cpp:568
16-bit unsigned integer, range is 0 through 65,535.
Definition: TTBase.h:276
void prepend(const TTValue &aValueToPrepend)
Insert another TTValue before the first element.
Definition: TTValue.h:162
void append(const T &anElementValueToAppend)
Insert a single TTElement at the end.
Definition: TTValue.h:243
void * TTPtr
A generic pointer.
Definition: TTBase.h:248
A Protocol interface.
TTErr set(const TTSymbol aName, T aValue)
Set an attribute value for an object.
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
void TTFOUNDATION_EXPORT TTLogError(TTImmutableCString message,...)
Platform and host independent method for posting errors.
Definition: TTBase.cpp:572
TTSymbol & getAttribute()
Get the attribute part.
Definition: TTAddress.h:130
#define addMessageWithArguments(name)
A convenience macro to be used by subclasses for registering messages.
Definition: TTMessage.h:27
const char * c_str() const
Return a pointer to the internal string as a C-string.
Definition: TTSymbol.h:77
The OSC Protocol.
void clear()
Clear all values from the vector, leaving with size of 0.
Definition: TTValue.h:131
void set(const TTUInt16 index, const T &anElementValue)
DEPRECATED.
Definition: TTValue.h:569
void TTFOUNDATION_EXPORT TTLogMessage(TTImmutableCString message,...)
Platform and host independent method for posting log messages.
Definition: TTBase.cpp:534
Something went wrong, but what exactly is not known. Typically used for context-specific problems...
Definition: TTBase.h:344
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
std::uint32_t TTUInt32
32 bit unsigned integer
Definition: TTBase.h:178
TTObjectBase * instance() const
Return a direct pointer to the internal instance.
Definition: TTObject.cpp:105
No Error.
Definition: TTBase.h:343
#define TT_PROTOCOL_CONSTRUCTOR
Declares instantiation and registration methods to add the protocol class as any TTObject class...
Definition: TTProtocol.h:23
#define addAttributeAsProtocolParameter(name, type)
Add a protocol parameter as an attribute of the class.
Definition: TTProtocol.h:48
TTAddress removeAttribute()
Return a new TTAddress without attribute part.
Definition: TTAddress.h:155
The TTString class is used to represent a string.
Definition: TTString.h:34
TTBoolean valid() const
Determine if the object contained by this TTObject is truly ready for use.
Definition: TTObject.cpp:179
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
unsigned char TTUInt8
8 bit unsigned integer (char)
Definition: TTBase.h:174
#define addMessageProperty(messageName, propertyName, initialValue)
A convenience macro to be used for registering properties of messages.
Definition: TTMessage.h:37