Marsyas  0.5.0-beta1
/Users/jleben/code/marsyas/src/marsyas/realtime/osc_receiver.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 2014 George Tzanetakis <gtzan@cs.uvic.ca>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include "osc_receiver.h"
00020 
00021 #include <oscpack/ip/IpEndpointName.h>
00022 #include <oscpack/osc/OscPacketListener.h>
00023 #include <oscpack/osc/OscReceivedElements.h>
00024 
00025 #include <string>
00026 #include <algorithm>
00027 
00028 using namespace std;
00029 
00030 namespace Marsyas {
00031 namespace RealTime {
00032 
00033 void process_packet( MarSystem * root_system, const char * data, size_t size );
00034 void process_bundle( MarSystem * root_system, const osc::ReceivedBundle& bundle );
00035 void process_message( MarSystem * root_system, const osc::ReceivedMessage& message );
00036 
00037 void OscReceiver::addProvider( OscProvider * provider )
00038 {
00039   auto provider_pos = find(m_providers.begin(), m_providers.end(), provider);
00040   if (provider_pos == m_providers.end())
00041     m_providers.push_back(provider);
00042 }
00043 
00044 void OscReceiver::removeProvider( OscProvider * provider )
00045 {
00046   auto provider_pos = find(m_providers.begin(), m_providers.end(), provider);
00047   if (provider_pos != m_providers.end())
00048     m_providers.erase(provider_pos);
00049 }
00050 
00051 void OscReceiver::processPacket(const char *data, size_t size)
00052 {
00053   process_packet(m_system, data, size);
00054 }
00055 
00056 void OscReceiver::run()
00057 {
00058   OscProviderDestination me(this);
00059 
00060   for ( OscProvider *provider : m_providers )
00061   {
00062     provider->provide(me);
00063   }
00064 }
00065 
00066 MarSystem *find_child_system(MarSystem * parent, const char * name, size_t count)
00067 {
00068   const std::vector<MarSystem*> & children = parent->children();
00069   for( MarSystem * child : children )
00070   {
00071     const string & child_name = child->getName();
00072     if (child_name.size() == count &&
00073         equal(name, name + count, child_name.data()))
00074     {
00075       return child;
00076     }
00077   }
00078 
00079   return 0;
00080 }
00081 
00082 MarControlPtr find_local_control(MarSystem * system, const char *name, size_t count)
00083 {
00084   const auto & controls = system->controls();
00085   for ( const auto & mapping : controls )
00086   {
00087     const MarControlPtr & control = mapping.second;
00088     const string & id = control->id();
00089     if (id.size() == count &&
00090         equal(name, name + count, id.data()))
00091     {
00092       return control;
00093     }
00094   }
00095 
00096   return MarControlPtr();
00097 }
00098 
00099 MarControlPtr find_control( MarSystem *root_system, const char * path )
00100 {
00101   size_t path_len = strlen(path);
00102   const char * path_end = path + path_len;
00103   const char * component = path;
00104 
00105   MarSystem * system = root_system;
00106 
00107   while(system)
00108   {
00109     const char * separator = std::find(component, path_end, '/');
00110     size_t component_len = separator - component;
00111     if (separator != path_end)
00112     {
00113       system = find_child_system(system, component, component_len );
00114     }
00115     else
00116     {
00117       return find_local_control(system, component, component_len);
00118     }
00119     component = separator + 1;
00120   }
00121 
00122   return MarControlPtr();
00123 }
00124 
00125 void process_packet( MarSystem * root_system, const char * data, size_t size )
00126 {
00127   osc::ReceivedPacket packet( data, size );
00128   if( packet.IsBundle() )
00129       process_bundle( root_system, osc::ReceivedBundle(packet) );
00130   else
00131       process_message( root_system, osc::ReceivedMessage(packet) );
00132 }
00133 
00134 void process_bundle( MarSystem * root_system, const osc::ReceivedBundle& bundle )
00135 {
00136   // ignore bundle time tag for now
00137   for( osc::ReceivedBundle::const_iterator i = bundle.ElementsBegin();
00138        i != bundle.ElementsEnd(); ++i )
00139   {
00140     if( i->IsBundle() )
00141       process_bundle( root_system, osc::ReceivedBundle(*i) );
00142     else
00143       process_message( root_system, osc::ReceivedMessage(*i) );
00144   }
00145 }
00146 
00147 void process_message( MarSystem * root_system, const osc::ReceivedMessage& message )
00148 {
00149   const char * path = message.AddressPattern();
00150   if (path[0] == '/') ++path;
00151 
00152   // FIXME: Constructing std::string is not real-time-safe.
00153   MarControlPtr control = find_control(root_system, path);
00154   if (control.isInvalid())
00155   {
00156     MRSWARN("OSC receiver: no control for path: " << path);
00157     return;
00158   }
00159 
00160   try
00161   {
00162     osc::ReceivedMessage::const_iterator it = message.ArgumentsBegin();
00163     if (it == message.ArgumentsEnd())
00164       throw std::runtime_error("OSC receiver: Message has no arguments.");
00165 
00166     char tag = it->TypeTag();
00167     switch(tag)
00168     {
00169     case osc::TRUE_TYPE_TAG:
00170     case osc::FALSE_TYPE_TAG:
00171       control->setValue(it->AsBoolUnchecked());
00172       break;
00173     case osc::INT32_TYPE_TAG:
00174       control->setValue(it->AsInt32Unchecked());
00175       break;
00176     case osc::FLOAT_TYPE_TAG:
00177       control->setValue((mrs_real) it->AsFloatUnchecked());
00178       break;
00179     case osc::DOUBLE_TYPE_TAG:
00180       control->setValue((mrs_real) it->AsDoubleUnchecked());
00181       break;
00182     case osc::STRING_TYPE_TAG:
00183       control->setValue(it->AsStringUnchecked());
00184       break;
00185     default:
00186       throw std::runtime_error("OSC receiver: Unsupported message argument type.");
00187     }
00188   }
00189   catch ( std::exception & e )
00190   {
00191     MRSWARN("OSC receiver: error while parsing message: " << e.what());
00192   }
00193 }
00194 
00195 void OscQueueProvider::provide( OscProviderDestination & destination )
00196 {
00197   size_t packet_size;
00198 
00199   while( (packet_size = m_queue->pop(m_buffer, m_buffer_size)) )
00200   {
00201     if (packet_size > m_buffer_size)
00202     {
00203       MRSWARN("OSC receiver: dropped too large OSC packet.");
00204       continue;
00205     }
00206     destination.provide(m_buffer, packet_size);
00207   }
00208 }
00209 
00210 }
00211 }