Ibiltari Nora / OSC
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers OSCBundle.cpp Source File

OSCBundle.cpp

00001 /*
00002  Written by Yotam Mann, The Center for New Music and Audio Technologies,
00003  University of California, Berkeley.  Copyright (c) 2012, The Regents of
00004  the University of California (Regents).
00005  
00006  Permission to use, copy, modify, distribute, and distribute modified versions
00007  of this software and its documentation without fee and without a signed
00008  licensing agreement, is hereby granted, provided that the above copyright
00009  notice, this paragraph and the following two paragraphs appear in all copies,
00010  modifications, and distributions.
00011  
00012  IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
00013  SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
00014  OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
00015  BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00016  
00017  REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
00018  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00019  PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
00020  HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
00021  MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
00022  
00023  For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu
00024  */
00025 
00026 #include "OSCBundle.h"
00027 
00028 #include <stdlib.h>
00029 #include <string.h>
00030 
00031  /*=============================================================================
00032     CONSTRUCTORS / DESTRUCTOR
00033 =============================================================================*/
00034 
00035 OSCBundle::OSCBundle(osctime_t _timetag){
00036     setTimetag(_timetag);
00037     numMessages = 0;
00038     error = OSC_OK;
00039     messages = NULL;
00040     incomingBuffer = NULL;
00041     incomingBufferSize = 0;
00042     decodeState = STANDBY;
00043 }
00044 
00045 OSCBundle::~OSCBundle(){
00046     for (int i = 0; i < numMessages; i++){
00047         OSCMessage * msg = getOSCMessage(i);
00048         delete msg;
00049     }
00050     free(messages);
00051     free(incomingBuffer);
00052 }
00053 
00054 //clears all of the OSCMessages inside
00055 OSCBundle& OSCBundle::empty(){
00056     error = OSC_OK;
00057     for (int i = 0; i < numMessages; i++){
00058         OSCMessage * msg = getOSCMessage(i);
00059         delete msg;
00060     }
00061     free(messages);
00062     messages = NULL;
00063     clearIncomingBuffer();
00064     numMessages = 0;
00065     return *this;
00066 }
00067 
00068 /*=============================================================================
00069  SETTERS
00070  =============================================================================*/
00071 
00072 OSCMessage & OSCBundle::add(const char * _address){
00073     OSCMessage * msg = new OSCMessage(_address);
00074     if (!msg->hasError()){
00075         //realloc the array to fit the message
00076         OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
00077         if (messageMem != NULL){
00078             messages = messageMem;
00079             messages[numMessages] = msg;
00080             numMessages++;
00081         } else {
00082             error = ALLOCFAILED;
00083         }
00084     }
00085     return *msg;
00086 }
00087 
00088 OSCMessage & OSCBundle::add(){
00089     OSCMessage * msg = new OSCMessage();
00090     //realloc the array to fit the message
00091     OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
00092     if (messageMem != NULL){
00093         messages = messageMem;
00094         messages[numMessages] = msg;
00095         numMessages++;
00096     } else {
00097         error = ALLOCFAILED;
00098     }
00099     return *msg;
00100 }
00101 
00102 OSCMessage & OSCBundle::add(OSCMessage & _msg){
00103     OSCMessage * msg = new OSCMessage(&_msg);
00104     if (!msg->hasError()){
00105         //realloc the array to fit the message
00106         OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
00107         if (messageMem != NULL){
00108             messages = messageMem;
00109             messages[numMessages] = msg;
00110             numMessages++;
00111         } else {
00112             error = ALLOCFAILED;
00113         }
00114     }
00115     return *msg;
00116 }
00117 
00118 /*=============================================================================
00119     GETTERS
00120  =============================================================================*/
00121 
00122 //returns the first fullMatch.
00123 OSCMessage * OSCBundle::getOSCMessage( char * addr){
00124     for (int i = 0; i < numMessages; i++){
00125         OSCMessage * msg = getOSCMessage(i);
00126         if (msg->fullMatch(addr)){
00127             return msg;
00128         }
00129     }
00130     return NULL;
00131 }
00132 
00133 //the position is the same as the order they were declared in
00134 OSCMessage * OSCBundle::getOSCMessage(int pos){
00135     if (pos < numMessages){
00136         return messages[pos];
00137     } 
00138     return NULL;
00139 }
00140 
00141 /*=============================================================================
00142     PATTERN MATCHING
00143  =============================================================================*/
00144 
00145 
00146 bool OSCBundle::dispatch(const char * pattern, void (*callback)(OSCMessage&), int initial_offset){
00147     bool called = false;
00148     for (int i = 0; i < numMessages; i++){
00149         OSCMessage msg = getOSCMessage(i);
00150         called = msg.dispatch(pattern, callback, initial_offset) || called ;
00151     }
00152     return called;
00153 }
00154 
00155 
00156 bool OSCBundle::route(const char * pattern, void (*callback)(OSCMessage&, int), int initial_offset){
00157     bool called = false;
00158     for (int i = 0; i < numMessages; i++){
00159         OSCMessage msg = getOSCMessage(i);
00160         called =  msg.route(pattern, callback, initial_offset) || called;
00161     }
00162     return called;
00163 }
00164 
00165 /*=============================================================================
00166     SIZE
00167  =============================================================================*/
00168 
00169 
00170 int OSCBundle::size(){
00171     return numMessages;
00172 }
00173 
00174 /*=============================================================================
00175  ERROR HANDLING
00176  =============================================================================*/
00177 
00178 bool OSCBundle::hasError(){
00179     bool retError = error != OSC_OK;
00180     //test each of the data
00181     for (int i = 0; i < numMessages; i++){
00182         OSCMessage * msg = getOSCMessage(i);
00183         retError |= msg->hasError();
00184     }
00185     return retError;
00186 }
00187 
00188 OSCErrorCode OSCBundle::getError(){
00189     return error;
00190 }
00191 
00192 
00193 /*=============================================================================
00194  SENDING
00195  =============================================================================*/
00196 
00197 OSCBundle& OSCBundle::send(UDPSocket &p, const SocketAddress &address){
00198 
00199     char  buff[128];
00200     uint8_t lengthEnd;
00201     uint8_t lengthStart;
00202     uint8_t nullChar = '\0';
00203     buff[0]=nullChar;
00204 
00205     //don't send a bundle with errors
00206     if (hasError()){
00207         return *this;
00208     }
00209     //write the bundle header
00210     static const uint8_t header[] = {'#', 'b', 'u', 'n', 'd', 'l', 'e', 0};
00211     strcat(buff, (char *)header);
00212     lengthEnd=strlen(buff);
00213 
00214 //    p.write(header, 8);
00215     //write the timetag
00216 {
00217     osctime_t time =  timetag;
00218     uint32_t d = BigEndian(time.seconds);
00219     uint8_t * ptr = (uint8_t *)    &d;
00220     for(int i = 0; i < 4; i++){
00221         buff[lengthEnd++]=ptr[i];
00222     }
00223 //    p.write(ptr, 4);
00224     d = BigEndian(time.fractionofseconds);
00225     ptr = (uint8_t *)    &d;
00226     for(int i = 0; i < 4; i++){
00227         buff[lengthEnd++]=ptr[i];
00228     }
00229 //    p.write(ptr, 4);
00230 }
00231 
00232     //send the messages
00233     for (int i = 0; i < numMessages; i++){
00234         OSCMessage * msg = getOSCMessage(i);
00235         int msgSize = msg->bytes();
00236         //turn the message size into a pointer
00237         uint32_t s32 = BigEndian((uint32_t) msgSize);
00238         uint8_t * sptr = (uint8_t *) &s32;
00239         //write the messsage size
00240         for(int i = 0; i < 4; i++){
00241                 buff[lengthEnd++]=sptr[i];
00242             }
00243 
00244 //        p.write(sptr, 4);
00245         msg->send(p, address);
00246     }
00247     p.sendto(address, buff, lengthEnd);
00248     return *this;
00249 }
00250 
00251 /*=============================================================================
00252     FILLING
00253  =============================================================================*/
00254 
00255 OSCBundle& OSCBundle::fill(uint8_t incomingByte){
00256     decode(incomingByte);
00257     return *this;
00258 }
00259 
00260 OSCBundle& OSCBundle::fill(const uint8_t * incomingBytes, int length){
00261     while (length--){
00262         decode(*incomingBytes++);
00263     }
00264     return *this;
00265 }
00266 
00267 /*=============================================================================
00268     DECODING
00269  =============================================================================*/
00270 
00271 void OSCBundle::decodeTimetag(){
00272     //parse the incoming buffer as a uint64
00273     setTimetag(incomingBuffer);
00274     //make sure the endianness is right
00275     //xxx time tag    timetag = BigEndian(timetag);
00276     decodeState = MESSAGE_SIZE;
00277     clearIncomingBuffer();
00278 }
00279 
00280 void OSCBundle::decodeHeader(){
00281     const char * header = "#bundle";
00282     if (strcmp(header, (char *) incomingBuffer)!=0){
00283         //otherwise go back to the top and wait for a new bundle header
00284         decodeState = STANDBY;
00285         error = INVALID_OSC;
00286     } else {
00287         decodeState = TIMETAG;
00288     }
00289     clearIncomingBuffer();
00290 }
00291 
00292 void OSCBundle::decodeMessage(uint8_t incomingByte){
00293     //get the current message
00294     if (numMessages > 0){
00295        OSCMessage * lastMessage = messages[numMessages - 1];
00296         //put the bytes in there
00297         lastMessage->fill(incomingByte);
00298         //if it's all done
00299         if (incomingBufferSize == incomingMessageSize){
00300             //move onto the next message
00301             decodeState = MESSAGE_SIZE;
00302             clearIncomingBuffer();
00303         } else if (incomingBufferSize > incomingMessageSize){
00304             error = INVALID_OSC;
00305         }
00306     }
00307 }
00308 
00309 //does not validate the incoming OSC for correctness
00310 void OSCBundle::decode(uint8_t incomingByte){
00311     addToIncomingBuffer(incomingByte);
00312     switch (decodeState){
00313         case STANDBY:
00314             if (incomingByte == '#'){
00315                 decodeState = HEADER;
00316             } else if (incomingByte == '/'){
00317                 add();//add a simple message to the bundle
00318                 decodeMessage(incomingByte);
00319                 decodeState = MESSAGE;
00320             }
00321             break;
00322         case HEADER:
00323             if (incomingBufferSize == 8){
00324                 decodeHeader();
00325                 decodeState = TIMETAG;
00326             }
00327             break;
00328         case TIMETAG:
00329             if (incomingBufferSize == 8){
00330                 decodeTimetag();
00331                 decodeState = MESSAGE_SIZE;
00332             }
00333             break;
00334         case MESSAGE_SIZE:
00335             if (incomingBufferSize == 4){
00336                 //make sure the message size is valid
00337                 int32_t msgSize;
00338                 memcpy(&msgSize, incomingBuffer, 4);
00339                 msgSize = BigEndian(msgSize);
00340                 if (msgSize % 4 != 0 || msgSize == 0){
00341                     error = INVALID_OSC;
00342                 } else {
00343                     //add a message to the buffer
00344                     decodeState = MESSAGE;
00345                     incomingMessageSize = msgSize;
00346                     clearIncomingBuffer();
00347                     //add a new empty message
00348                     add();
00349                 }
00350             }
00351             break;
00352         case MESSAGE:
00353             decodeMessage(incomingByte);
00354             break;
00355     }
00356 }
00357 
00358 
00359 /*=============================================================================
00360  INCOMING BUFFER MANAGEMENT
00361  =============================================================================*/
00362 
00363 void OSCBundle::addToIncomingBuffer(uint8_t incomingByte){
00364     //realloc some space for the new byte and stick it on the end
00365     incomingBuffer = (uint8_t *) realloc ( incomingBuffer, incomingBufferSize + 1);
00366     if (incomingBuffer != NULL){
00367         incomingBuffer[incomingBufferSize++] = incomingByte;
00368     } else {
00369         error = ALLOCFAILED;
00370     }
00371 }
00372 
00373 void OSCBundle::clearIncomingBuffer(){
00374     incomingBufferSize = 0;
00375     free(incomingBuffer);
00376     incomingBuffer = NULL;
00377 }
00378 
00379 
00380