From Stephan Huber, introduction of message id scheme were osc messages are sent with an unique id, and can be dispatched multiple times to workaround network packet losses.

This commit is contained in:
Robert Osfield 2013-01-31 11:09:03 +00:00
parent 5339864c17
commit 9bc3b3316a
6 changed files with 150 additions and 26 deletions

View File

@ -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<osg::GraphicsContext::Traits> 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<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
traits->x = 100;
traits->y = 100;

View File

@ -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);
}

View File

@ -19,13 +19,15 @@
#include <osgGA/Device>
#include <osc/OscPacketListener.h>
#include <ip/UdpSocket.h>
#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<osgGA::GUIEventAdapter> _userDataEvent;
MsgIdType _lastMsgId;
osg::Timer_t _lastMsgTimeStamp;
};

View File

@ -16,14 +16,17 @@
#include "osc/OscHostEndianness.h"
#include <osg/UserDataContainer>
#include <osg/ValueObject>
#include <osg/Math>
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<const osg::ValueObject*>(o))
{

View File

@ -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;
};

View File

@ -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
{