diff --git a/examples/osgoscdevice/osgoscdevice.cpp b/examples/osgoscdevice/osgoscdevice.cpp index 0e0a7dc70..e4eadf4e1 100755 --- a/examples/osgoscdevice/osgoscdevice.cpp +++ b/examples/osgoscdevice/osgoscdevice.cpp @@ -402,6 +402,9 @@ int main( int argc, char **argv ) osg::ArgumentParser arguments(&argc,argv); arguments.getApplicationUsage()->addCommandLineOption("--zeroconf","uses zeroconf to advertise the osc-plugin and to discover it"); + arguments.getApplicationUsage()->addCommandLineOption("--sender","create a view which sends its events via osc"); + arguments.getApplicationUsage()->addCommandLineOption("--recevier","create a view which receive its events via osc"); + // read the scene from the list of file specified commandline args. @@ -414,13 +417,16 @@ int main( int argc, char **argv ) } bool use_zeroconf(false); + bool use_sender(false); + bool use_receiver(false); if(arguments.find("--zeroconf") > 0) { use_zeroconf = true; } - + if(arguments.find("--sender") > 0) { use_sender = true; } + if(arguments.find("--receiver") > 0) { use_receiver = true; } // construct the viewer. osgViewer::CompositeViewer viewer(arguments); // receiver view - { + if (use_receiver) { osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->x = 600; traits->y = 100; @@ -480,7 +486,7 @@ int main( int argc, char **argv ) } // sender view - { + if(use_sender) { osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->x = 100; traits->y = 100; diff --git a/src/osgPlugins/osc/OscReceivingDevice.cpp b/src/osgPlugins/osc/OscReceivingDevice.cpp index 355cce2fc..f0982e407 100755 --- a/src/osgPlugins/osc/OscReceivingDevice.cpp +++ b/src/osgPlugins/osc/OscReceivingDevice.cpp @@ -722,6 +722,7 @@ OscReceivingDevice::OscReceivingDevice(const std::string& server_address, int li , _listeningPort(listening_port) , _socket(NULL) , _map() + , _lastMsgId(0) { setCapabilities(RECEIVE_EVENTS); OSG_NOTICE << "OscDevice :: listening on " << server_address << ":" << listening_port << " "; @@ -760,7 +761,7 @@ OscReceivingDevice::OscReceivingDevice(const std::string& server_address, int li addRequestHandler(new OscDevice::StandardRequestHandler("/osg/set_user_value", true)); addRequestHandler(new OscDevice::StandardRequestHandler("", false)); - + setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_LOW); start(); } @@ -782,6 +783,10 @@ void OscReceivingDevice::run() void OscReceivingDevice::ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint ) { std::string in_request_path(m.AddressPattern()); + + if (in_request_path == "/osc/msg_id") + return; + std::string request_path = in_request_path + "/"; std::size_t pos(std::string::npos); @@ -807,10 +812,58 @@ void OscReceivingDevice::ProcessMessage( const osc::ReceivedMessage& m, const Ip } +void OscReceivingDevice::ProcessBundle( const osc::ReceivedBundle& b, + const IpEndpointName& remoteEndpoint ) +{ + // find msg-id + MsgIdType msg_id(0); + + for( osc::ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i ){ + const osc::ReceivedMessage& m = osc::ReceivedMessage(*i); + std::string address_pattern(m.AddressPattern()); + if(address_pattern == "/osc/msg_id") + { + osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); + args >> msg_id; + break; + } + } + if (msg_id) + { + osg::Timer_t now(osg::Timer::instance()->tick()); + if (osg::Timer::instance()->delta_s(_lastMsgTimeStamp, now) > 0.5) { + OSG_INFO << "OscReceiver :: resetting msg_id to 0 " << std::endl; + _lastMsgId = 0; + } + _lastMsgTimeStamp = now; + + if (msg_id <= _lastMsgId) { + // already handled + // OSG_WARN << "OscReceiver :: message with lower id received: " << msg_id << std::endl; + return; + } + else { + if ((msg_id > _lastMsgId+1) && (_lastMsgId > 0)) { + OSG_WARN << "OscReceiver :: missed " << (msg_id - _lastMsgId) << " messages, (" << msg_id << "/" << _lastMsgId << ")" << std::endl; + } + _lastMsgId = msg_id; + } + } + + + for( osc::ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i ){ + if( i->IsBundle() ) + ProcessBundle( osc::ReceivedBundle(*i), remoteEndpoint ); + else + { + ProcessMessage( osc::ReceivedMessage(*i), remoteEndpoint ); + } + } +} + + void OscReceivingDevice::ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) { - OSG_INFO << "OscDevice :: receiving " << size << " bytes of data ..." << std::endl; - try { osc::OscPacketListener::ProcessPacket(data, size, remoteEndpoint); } diff --git a/src/osgPlugins/osc/OscReceivingDevice.hpp b/src/osgPlugins/osc/OscReceivingDevice.hpp index 88ea6c2c9..b994fea4e 100755 --- a/src/osgPlugins/osc/OscReceivingDevice.hpp +++ b/src/osgPlugins/osc/OscReceivingDevice.hpp @@ -19,13 +19,15 @@ #include #include #include - +#include "OscSendingDevice.hpp" class OscReceivingDevice : public osgGA::Device, OpenThreads::Thread, osc::OscPacketListener { public: + typedef OscSendingDevice::MsgIdType MsgIdType; + class RequestHandler : public osg::Referenced { public: RequestHandler(const std::string& request_path) @@ -75,7 +77,7 @@ public: virtual void ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint ); virtual void ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ); - + virtual void ProcessBundle( const osc::ReceivedBundle& b, const IpEndpointName& remoteEndpoint ); void addRequestHandler(RequestHandler* handler); void describeTo(std::ostream& out) const; @@ -96,12 +98,16 @@ public: return _userDataEvent.get(); } + virtual const char* className() const { return "OSC receiving device"; } + private: std::string _listeningAddress; unsigned int _listeningPort; UdpListeningReceiveSocket* _socket; RequestHandlerMap _map; osg::ref_ptr _userDataEvent; + MsgIdType _lastMsgId; + osg::Timer_t _lastMsgTimeStamp; }; diff --git a/src/osgPlugins/osc/OscSendingDevice.cpp b/src/osgPlugins/osc/OscSendingDevice.cpp index eba58273a..1c2ab4f4c 100755 --- a/src/osgPlugins/osc/OscSendingDevice.cpp +++ b/src/osgPlugins/osc/OscSendingDevice.cpp @@ -16,14 +16,17 @@ #include "osc/OscHostEndianness.h" #include #include +#include static const unsigned long BUFFER_SIZE = 2048; -OscSendingDevice::OscSendingDevice(const std::string& address, int port) +OscSendingDevice::OscSendingDevice(const std::string& address, int port, unsigned int num_messages_per_event, unsigned int delay_between_sends_in_millisecs) : osgGA::Device() , _transmitSocket(IpEndpointName(address.c_str(), port)) , _buffer(new char[BUFFER_SIZE]) , _oscStream(_buffer, BUFFER_SIZE) + , _numMessagesPerEvent(osg::minimum(1u,num_messages_per_event)) + , _delayBetweenSendsInMilliSecs( (_numMessagesPerEvent > 1) ? delay_between_sends_in_millisecs : 0) { setCapabilities(SEND_EVENTS); @@ -33,6 +36,7 @@ OscSendingDevice::OscSendingDevice(const std::string& address, int port) #elif OSC_HOST_BIG_ENDIAN OSG_NOTICE << "(big endian)"; #endif + OSG_NOTICE << " (" << num_messages_per_event << "msgs/event)"; OSG_NOTICE << std::endl; } @@ -44,42 +48,63 @@ OscSendingDevice::~OscSendingDevice() } void OscSendingDevice::sendEvent(const osgGA::GUIEventAdapter &ea) +{ + static osc::int64 msg_id(0); + bool msg_sent(false); + for(unsigned int i = 0; i < _numMessagesPerEvent; ++i) { + msg_sent = sendEventImpl(ea, msg_id); + if ((_delayBetweenSendsInMilliSecs > 0) && (i < _numMessagesPerEvent-1)) + OpenThreads::Thread::microSleep(1000 * _delayBetweenSendsInMilliSecs); + } + if (msg_sent) + msg_id++; +} + + +bool OscSendingDevice::sendEventImpl(const osgGA::GUIEventAdapter &ea, MsgIdType msg_id) { bool do_send(false); switch(ea.getEventType()) { case osgGA::GUIEventAdapter::RESIZE: + beginBundle(msg_id); _oscStream << osc::BeginMessage("/osgga/resize") << ea.getWindowX() << ea.getWindowY() << ea.getWindowWidth() << ea.getWindowHeight() << osc::EndMessage; + _oscStream << osc::EndBundle; do_send = true; break; case osgGA::GUIEventAdapter::SCROLL: - beginSendInputRange(ea); + beginSendInputRange(ea, msg_id); _oscStream << osc::BeginMessage("/osgga/mouse/scroll") << ea.getScrollingMotion() << ea.getScrollingDeltaX() << ea.getScrollingDeltaY() << osc::EndMessage; _oscStream << osc::EndBundle; do_send = true; break; case osgGA::GUIEventAdapter::PEN_PRESSURE: + beginBundle(msg_id); _oscStream << osc::BeginMessage("/osgga/pen/pressure") << ea.getPenPressure() << osc::EndMessage; + _oscStream << osc::EndBundle; + do_send = true; break; case osgGA::GUIEventAdapter::PEN_ORIENTATION: - - _oscStream + beginBundle(msg_id); + _oscStream << osc::BeginMessage("/osgga/pen/orientation") << ea.getPenRotation() << ea.getPenTiltX() << ea.getPenTiltY() << osc::EndMessage; do_send = true; + _oscStream << osc::EndBundle; break; case osgGA::GUIEventAdapter::PEN_PROXIMITY_ENTER: + beginBundle(msg_id); _oscStream << osc::BeginMessage("/osgga/pen/proximity/enter") << ea.getTabletPointerType() @@ -88,29 +113,31 @@ void OscSendingDevice::sendEvent(const osgGA::GUIEventAdapter &ea) break; case osgGA::GUIEventAdapter::PEN_PROXIMITY_LEAVE: + beginBundle(msg_id); _oscStream << osc::BeginMessage("/osgga/pen/proximity/leave") << ea.getTabletPointerType() << osc::EndMessage; + _oscStream << osc::EndBundle; do_send = true; break; case osgGA::GUIEventAdapter::PUSH: - beginSendInputRange(ea); + beginSendInputRange(ea, msg_id); _oscStream << osc::BeginMessage("/osgga/mouse/press") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage; _oscStream << osc::EndBundle; do_send = true; break; case osgGA::GUIEventAdapter::RELEASE: - beginSendInputRange(ea); + beginSendInputRange(ea, msg_id); _oscStream << osc::BeginMessage("/osgga/mouse/release") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage; _oscStream << osc::EndBundle; do_send = true; break; case osgGA::GUIEventAdapter::DOUBLECLICK: - beginSendInputRange(ea); + beginSendInputRange(ea, msg_id); _oscStream << osc::BeginMessage("/osgga/mouse/doublepress") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage; _oscStream << osc::EndBundle; do_send = true; @@ -118,19 +145,23 @@ void OscSendingDevice::sendEvent(const osgGA::GUIEventAdapter &ea) case osgGA::GUIEventAdapter::MOVE: case osgGA::GUIEventAdapter::DRAG: - beginSendInputRange(ea); + beginSendInputRange(ea, msg_id); _oscStream << osc::BeginMessage("/osgga/mouse/motion") << ea.getX() << ea.getY() << osc::EndMessage; _oscStream << osc::EndBundle; do_send = true; break; case osgGA::GUIEventAdapter::KEYDOWN: + beginBundle(msg_id); _oscStream << osc::BeginMessage("/osgga/key/press") << ea.getKey() << osc::EndMessage; + _oscStream << osc::EndBundle; do_send = true; break; case osgGA::GUIEventAdapter::KEYUP: + beginBundle(msg_id); _oscStream << osc::BeginMessage("/osgga/key/release") << ea.getKey() << osc::EndMessage; + _oscStream << osc::EndBundle; do_send = true; break; @@ -141,7 +172,7 @@ void OscSendingDevice::sendEvent(const osgGA::GUIEventAdapter &ea) if (key.empty()) key = ea.getName(); if (key.empty()) key = "user_data"; - sendUserDataContainer(transliterateKey(key), ea.getUserDataContainer(), true); + sendUserDataContainer(transliterateKey(key), ea.getUserDataContainer(), true, msg_id); do_send = true; } @@ -158,6 +189,8 @@ void OscSendingDevice::sendEvent(const osgGA::GUIEventAdapter &ea) _transmitSocket.Send( _oscStream.Data(), _oscStream.Size() ); _oscStream.Clear(); } + + return do_send; } int OscSendingDevice::getButtonNum(const osgGA::GUIEventAdapter& ea) @@ -179,9 +212,15 @@ int OscSendingDevice::getButtonNum(const osgGA::GUIEventAdapter& ea) return -1; } -void OscSendingDevice::beginSendInputRange(const osgGA::GUIEventAdapter &ea) +void OscSendingDevice::beginBundle(MsgIdType msg_id) { _oscStream << osc::BeginBundle(); + _oscStream << osc::BeginMessage("/osc/msg_id") << msg_id << osc::EndMessage; +} + +void OscSendingDevice::beginSendInputRange(const osgGA::GUIEventAdapter &ea, MsgIdType msg_id) +{ + beginBundle(msg_id); _oscStream << osc::BeginMessage("/osgga/mouse/set_input_range") << ea.getXmin() << ea.getYmin() << ea.getXmax() << ea.getYmax() << osc::EndMessage; _oscStream << osc::BeginMessage("/osgga/mouse/y_orientation_increasing_upwards") << (bool)(ea.getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS) << osc::EndMessage; } @@ -239,10 +278,11 @@ std::string OscSendingDevice::transliterateKey(const std::string& key) const return result; } -void OscSendingDevice::sendUserDataContainer(const std::string& key, const osg::UserDataContainer* udc, bool asBundle) +void OscSendingDevice::sendUserDataContainer(const std::string& key, const osg::UserDataContainer* udc, bool asBundle, MsgIdType msg_id) { - if (asBundle) - _oscStream << osc::BeginBundle(); + if (asBundle) { + beginBundle(msg_id); + } OscSendingDeviceGetValueVisitor gvv(_oscStream); @@ -254,7 +294,7 @@ void OscSendingDevice::sendUserDataContainer(const std::string& key, const osg:: if (child_udc) { std::string new_key = key + "/" + (child_udc->getName().empty() ? "user_data" : child_udc->getName()); - sendUserDataContainer(transliterateKey(key), child_udc, false); + sendUserDataContainer(transliterateKey(key), child_udc, false, msg_id); } else if (const osg::ValueObject* vo = dynamic_cast(o)) { diff --git a/src/osgPlugins/osc/OscSendingDevice.hpp b/src/osgPlugins/osc/OscSendingDevice.hpp index fccf62d27..ea28c8a7b 100755 --- a/src/osgPlugins/osc/OscSendingDevice.hpp +++ b/src/osgPlugins/osc/OscSendingDevice.hpp @@ -22,17 +22,22 @@ class OscSendingDevice : public osgGA::Device { public: - OscSendingDevice(const std::string& address, int port); + typedef osc::int64 MsgIdType; + OscSendingDevice(const std::string& address, int port, unsigned int numMessagesPerEvent = 1, unsigned int delay_between_sends_in_millisecs = 0); ~OscSendingDevice(); virtual void sendEvent(const osgGA::GUIEventAdapter &ea); + virtual const char* className() const { return "OSC sending device"; } private: - void beginSendInputRange(const osgGA::GUIEventAdapter& ea); + bool sendEventImpl(const osgGA::GUIEventAdapter &ea,MsgIdType msg_id); + void beginBundle(MsgIdType msg_id); + void beginSendInputRange(const osgGA::GUIEventAdapter& ea, MsgIdType msg_id); int getButtonNum(const osgGA::GUIEventAdapter& ea); - void sendUserDataContainer(const std::string& key, const osg::UserDataContainer* udc, bool asBundle); + void sendUserDataContainer(const std::string& key, const osg::UserDataContainer* udc, bool asBundle, MsgIdType msg_id); std::string transliterateKey(const std::string& key) const; UdpTransmitSocket _transmitSocket; char* _buffer; osc::OutboundPacketStream _oscStream; + unsigned int _numMessagesPerEvent, _delayBetweenSendsInMilliSecs; }; diff --git a/src/osgPlugins/osc/ReaderWriterOscDevice.cpp b/src/osgPlugins/osc/ReaderWriterOscDevice.cpp index 8a67ca248..dcdd9993b 100755 --- a/src/osgPlugins/osc/ReaderWriterOscDevice.cpp +++ b/src/osgPlugins/osc/ReaderWriterOscDevice.cpp @@ -72,6 +72,8 @@ class ReaderWriterOsc : public osgDB::ReaderWriter { supportsExtension("osc", "Virtual Device Integration via a OSC_receiver"); supportsOption("documentRegisteredHandlers", "dump a documentation of all registered REST-handler to the console"); + supportsOption("numMessagesPerEvent", "set the number of osc-messages to send for one event (sender-only)"); + } @@ -90,7 +92,19 @@ class ReaderWriterOsc : public osgDB::ReaderWriter std::string server_address = file_name.substr(0,file_name.find(':')); std::string server_port = file_name.substr(file_name.find(':') + 1); - return new OscSendingDevice(server_address, atoi(server_port.c_str())); + unsigned int num_messages_per_event = 1; + if (options && !options->getPluginStringData("numMessagesPerEvent").empty()) { + std::string num_messages_per_event_str = options->getPluginStringData("numMessagesPerEvent"); + num_messages_per_event = osg::maximum(1, atoi(num_messages_per_event_str.c_str())); + } + + unsigned int delay_between_sends_in_millisecs = 0; + if (options && !options->getPluginStringData("delayBetweenSendsInMillisecs").empty()) { + std::string delay_between_sends_in_millisecs_str = options->getPluginStringData("delayBetweenSendsInMillisecs"); + delay_between_sends_in_millisecs = atoi(delay_between_sends_in_millisecs_str.c_str()); + } + + return new OscSendingDevice(server_address, atoi(server_port.c_str()), num_messages_per_event, delay_between_sends_in_millisecs); } else {