Frm Stephan Huber, osc plugin that supports send and recieving events via UDP packets.
This commit is contained in:
parent
c005e6997c
commit
e2ee774705
@ -255,6 +255,7 @@ IF(LIBVNCSERVER_FOUND)
|
||||
ENDIF()
|
||||
|
||||
ADD_SUBDIRECTORY(pvr)
|
||||
ADD_SUBDIRECTORY(osc)
|
||||
|
||||
####################################################
|
||||
#
|
||||
|
49
src/osgPlugins/osc/CMakeLists.txt
Executable file
49
src/osgPlugins/osc/CMakeLists.txt
Executable file
@ -0,0 +1,49 @@
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
SET(TARGET_SRC
|
||||
ip/IpEndpointName.cpp
|
||||
osc/OscOutboundPacketStream.cpp
|
||||
osc/OscPrintReceivedElements.cpp
|
||||
osc/OscReceivedElements.cpp
|
||||
osc/OscTypes.cpp
|
||||
OscDevice.cpp
|
||||
OscProxyEventHandler.cpp
|
||||
ReaderWriterOscDevice.cpp
|
||||
)
|
||||
|
||||
SET(TARGET_H
|
||||
ip/IpEndpointName.h
|
||||
ip/NetworkingUtils.h
|
||||
ip/PacketListener.h
|
||||
ip/TimerListener.h
|
||||
ip/UdpSocket.h
|
||||
osc/MessageMappingOscPacketListener.h
|
||||
osc/OscException.h
|
||||
osc/OscHostEndianness.h
|
||||
osc/OscOutboundPacketStream.h
|
||||
osc/OscPacketListener.h
|
||||
osc/OscPrintReceivedElements.h
|
||||
osc/OscReceivedElements.h
|
||||
osc/OscTypes.h
|
||||
OscProxyEventHandler.hpp
|
||||
OscDevice.hpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
SET(TARGET_SRC
|
||||
${TARGET_SRC}
|
||||
ip/win32/NetworkingUtils.cpp
|
||||
ip/win32/UdpSocket.cpp
|
||||
)
|
||||
ELSE()
|
||||
SET(TARGET_SRC
|
||||
${TARGET_SRC}
|
||||
ip/posix/NetworkingUtils.cpp
|
||||
ip/posix/UdpSocket.cpp
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
SET(TARGET_ADDED_LIBRARIES osgPresentation )
|
||||
|
||||
#### end var setup ###
|
||||
SETUP_PLUGIN(osc)
|
422
src/osgPlugins/osc/OscDevice.cpp
Executable file
422
src/osgPlugins/osc/OscDevice.cpp
Executable file
@ -0,0 +1,422 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include "OscDevice.hpp"
|
||||
#include <OpenThreads/Thread>
|
||||
#include <osgDB/FileUtils>
|
||||
#include "osc/OscPrintReceivedElements.h"
|
||||
|
||||
|
||||
class StandardRequestHandler : public OscDevice::RequestHandler {
|
||||
public:
|
||||
StandardRequestHandler() : OscDevice::RequestHandler("") {}
|
||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
||||
{
|
||||
OSG_NOTICE << "OscDevice :: unhandled request: " << full_request_path << std::endl;
|
||||
|
||||
for(osc::ReceivedMessageArgumentIterator itr = m.ArgumentsBegin(); itr != m.ArgumentsEnd(); ++itr)
|
||||
{
|
||||
OSG_NOTICE << " " << (*itr) << std::endl;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void describeTo(std::ostream& out) const
|
||||
{
|
||||
out << getRequestPath() << ": fall-through request-handler, catches all requests w/o registered handler and report them to the console";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SetMouseInputRangeRequestHandler : public OscDevice::RequestHandler {
|
||||
public:
|
||||
SetMouseInputRangeRequestHandler()
|
||||
: OscDevice::RequestHandler("/osgga/mouse/set_input_range")
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
||||
{
|
||||
try {
|
||||
float x_min(-1.0f), y_min(-1.0f), x_max(1.0f), y_max(1.0f);
|
||||
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
||||
args >> x_min >> y_min >> x_max >> y_max >> osc::EndMessage;
|
||||
|
||||
getDevice()->getEventQueue()->setMouseInputRange(x_min, y_min, x_max, y_max);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(osc::Exception e) {
|
||||
handleException(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void describeTo(std::ostream& out) const
|
||||
{
|
||||
out << getRequestPath() << "(float x_min, float y_min, float x_max, float y_max): sets the mouse-input-range" << std::dec;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SetMouseOrientationRequestHandler : public OscDevice::RequestHandler {
|
||||
public:
|
||||
SetMouseOrientationRequestHandler()
|
||||
: OscDevice::RequestHandler("/osgga/mouse/y_orientation_increasing_upwards")
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
||||
{
|
||||
try {
|
||||
bool increasing_upwards(false);
|
||||
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
||||
args >>increasing_upwards >> osc::EndMessage;
|
||||
|
||||
getDevice()->getEventQueue()->getCurrentEventState()->setMouseYOrientation(
|
||||
increasing_upwards ? osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS : osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(osc::Exception e) {
|
||||
handleException(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void describeTo(std::ostream& out) const
|
||||
{
|
||||
out << getRequestPath() << "(float x_min, float y_min, float x_max, float y_max): sets the mouse-input-range" << std::dec;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class KeyCodeRequestHandler : public OscDevice::RequestHandler {
|
||||
public:
|
||||
KeyCodeRequestHandler(bool handle_key_press)
|
||||
: OscDevice::RequestHandler(std::string("/osgga/key/") + ((handle_key_press) ? "press" : "release"))
|
||||
, _handleKeyPress(handle_key_press)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
||||
{
|
||||
try {
|
||||
osc::int32 keycode(0);
|
||||
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
||||
args >> keycode >> osc::EndMessage;
|
||||
|
||||
if (_handleKeyPress)
|
||||
getDevice()->getEventQueue()->keyPress(keycode, getLocalTime());
|
||||
else
|
||||
getDevice()->getEventQueue()->keyRelease(keycode, getLocalTime());
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(osc::Exception e) {
|
||||
handleException(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void describeTo(std::ostream& out) const
|
||||
{
|
||||
out << getRequestPath() << "(int keycode): send KEY_" << (_handleKeyPress ? "DOWN" : "UP");
|
||||
}
|
||||
private:
|
||||
bool _handleKeyPress;
|
||||
};
|
||||
|
||||
|
||||
class KeyPressAndReleaseRequestHandler : public OscDevice::RequestHandler {
|
||||
public:
|
||||
KeyPressAndReleaseRequestHandler()
|
||||
: OscDevice::RequestHandler("/osgga/key/press_and_release")
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
||||
{
|
||||
try {
|
||||
osc::int32 keycode(0);
|
||||
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
||||
args >> keycode >> osc::EndMessage;
|
||||
|
||||
getDevice()->getEventQueue()->keyPress(keycode, getLocalTime());
|
||||
getDevice()->getEventQueue()->keyRelease(keycode, getLocalTime());
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(osc::Exception e) {
|
||||
handleException(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void describeTo(std::ostream& out) const
|
||||
{
|
||||
out << getRequestPath() << "(int keycode): send KEY_DOWN and KEY_UP";
|
||||
}
|
||||
private:
|
||||
bool _handleKeyPress;
|
||||
};
|
||||
|
||||
|
||||
class MouseMotionRequestHandler : public OscDevice::RequestHandler {
|
||||
public:
|
||||
MouseMotionRequestHandler()
|
||||
: OscDevice::RequestHandler("/osgga/mouse/motion")
|
||||
, _lastX(0.0f)
|
||||
, _lastY(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
||||
{
|
||||
|
||||
try {
|
||||
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
||||
args >> _lastX >> _lastY >> osc::EndMessage;
|
||||
|
||||
getDevice()->getEventQueue()->mouseMotion(_lastX, _lastY, getLocalTime());
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (osc::Exception e) {
|
||||
handleException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void describeTo(std::ostream& out) const
|
||||
{
|
||||
out << getRequestPath() << "(float x, float y): send mouse motion";
|
||||
}
|
||||
float getLastX() const { return _lastX; }
|
||||
float getLastY() const { return _lastY; }
|
||||
private:
|
||||
float _lastX, _lastY;
|
||||
};
|
||||
|
||||
class MouseButtonToggleRequestHandler : public OscDevice::RequestHandler {
|
||||
public:
|
||||
MouseButtonToggleRequestHandler(const std::string& btn_name, MouseMotionRequestHandler* mm_handler)
|
||||
: OscDevice::RequestHandler("/osgga/mouse/toggle/"+btn_name)
|
||||
, _mmHandler(mm_handler)
|
||||
, _btnNum(atoi(btn_name.c_str()))
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
||||
{
|
||||
float down(0.0f);
|
||||
|
||||
try {
|
||||
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
||||
args >> down >> osc::EndMessage;
|
||||
|
||||
if (down > 0)
|
||||
getDevice()->getEventQueue()->mouseButtonPress(_mmHandler->getLastX(), _mmHandler->getLastY(), _btnNum, getLocalTime());
|
||||
else
|
||||
getDevice()->getEventQueue()->mouseButtonRelease(_mmHandler->getLastX(), _mmHandler->getLastY(), _btnNum, getLocalTime());
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (osc::Exception e) {
|
||||
handleException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void describeTo(std::ostream& out) const
|
||||
{
|
||||
out << getRequestPath() << "(float down): toggle mouse button";
|
||||
}
|
||||
private:
|
||||
osg::observer_ptr<MouseMotionRequestHandler> _mmHandler;
|
||||
int _btnNum;
|
||||
};
|
||||
|
||||
|
||||
class MouseButtonRequestHandler : public OscDevice::RequestHandler {
|
||||
public:
|
||||
enum Mode { PRESS, RELEASE, DOUBLE_PRESS};
|
||||
|
||||
MouseButtonRequestHandler(Mode mode)
|
||||
: OscDevice::RequestHandler("")
|
||||
, _mode(mode)
|
||||
{
|
||||
switch(mode) {
|
||||
case PRESS:
|
||||
setRequestPath("/osgga/mouse/press");
|
||||
break;
|
||||
case RELEASE:
|
||||
setRequestPath("/osgga/mouse/release");
|
||||
break;
|
||||
case DOUBLE_PRESS:
|
||||
setRequestPath("/osgga/mouse/doublepress");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
||||
{
|
||||
float x(0.0f), y(0.0f);
|
||||
osc::int32 btn(0);
|
||||
|
||||
try {
|
||||
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
||||
args >> x >> y >> btn >> osc::EndMessage;
|
||||
switch (_mode) {
|
||||
case PRESS:
|
||||
getDevice()->getEventQueue()->mouseButtonPress(x,y, btn, getLocalTime());
|
||||
break;
|
||||
case RELEASE:
|
||||
getDevice()->getEventQueue()->mouseButtonRelease(x,y, btn, getLocalTime());
|
||||
break;
|
||||
case DOUBLE_PRESS:
|
||||
getDevice()->getEventQueue()->mouseDoubleButtonPress(x,y, btn, getLocalTime());
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (osc::Exception e) {
|
||||
handleException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void describeTo(std::ostream& out) const
|
||||
{
|
||||
out << getRequestPath() << "(float x, float y, int btn): send mouse ";
|
||||
switch (_mode) {
|
||||
case PRESS:
|
||||
out << "press"; break;
|
||||
case RELEASE:
|
||||
out << "release"; break;
|
||||
case DOUBLE_PRESS:
|
||||
out << "double press"; break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Mode _mode;
|
||||
};
|
||||
|
||||
|
||||
|
||||
OscDevice::OscDevice(const std::string& server_address, int listening_port)
|
||||
: osgGA::Device()
|
||||
, OpenThreads::Thread()
|
||||
, osc::OscPacketListener()
|
||||
, _listeningAddress(server_address)
|
||||
, _listeningPort(listening_port)
|
||||
, _socket(NULL)
|
||||
, _map()
|
||||
{
|
||||
_socket = new UdpListeningReceiveSocket(IpEndpointName( server_address.c_str(), listening_port ), this);
|
||||
|
||||
addRequestHandler(new KeyCodeRequestHandler(false));
|
||||
addRequestHandler(new KeyCodeRequestHandler(true));
|
||||
addRequestHandler(new KeyPressAndReleaseRequestHandler());
|
||||
|
||||
addRequestHandler(new SetMouseInputRangeRequestHandler());
|
||||
addRequestHandler(new SetMouseOrientationRequestHandler());
|
||||
|
||||
MouseMotionRequestHandler* mm_handler = new MouseMotionRequestHandler();
|
||||
addRequestHandler(mm_handler);
|
||||
addRequestHandler(new MouseButtonRequestHandler(MouseButtonRequestHandler::PRESS));
|
||||
addRequestHandler(new MouseButtonRequestHandler(MouseButtonRequestHandler::RELEASE));
|
||||
addRequestHandler(new MouseButtonRequestHandler(MouseButtonRequestHandler::DOUBLE_PRESS));
|
||||
|
||||
addRequestHandler(new MouseButtonToggleRequestHandler("1", mm_handler));
|
||||
addRequestHandler(new MouseButtonToggleRequestHandler("2", mm_handler));
|
||||
addRequestHandler(new MouseButtonToggleRequestHandler("3", mm_handler));
|
||||
|
||||
addRequestHandler(new StandardRequestHandler());
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
OscDevice::~OscDevice()
|
||||
{
|
||||
_socket->AsynchronousBreak();
|
||||
join();
|
||||
delete _socket;
|
||||
}
|
||||
|
||||
void OscDevice::run()
|
||||
{
|
||||
_socket->Run();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void OscDevice::ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint )
|
||||
{
|
||||
std::string in_request_path(m.AddressPattern());
|
||||
std::string request_path = in_request_path + "/";
|
||||
|
||||
std::size_t pos(std::string::npos);
|
||||
bool handled(false);
|
||||
do {
|
||||
pos = request_path.find_last_of('/', pos-1);
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string mangled_path = request_path.substr(0, pos);
|
||||
|
||||
std::pair<RequestHandlerMap::iterator,RequestHandlerMap::iterator> range = _map.equal_range(mangled_path);
|
||||
|
||||
for(RequestHandlerMap::iterator i = range.first; i != range.second; ++i)
|
||||
{
|
||||
OSG_INFO << "OscDevice :: handling " << mangled_path << " with " << i->second << std::endl;
|
||||
|
||||
if (i->second->operator()(mangled_path, in_request_path, m) && !handled)
|
||||
handled = true;
|
||||
}
|
||||
|
||||
}
|
||||
} while ((pos != std::string::npos) && (pos > 0) && !handled);
|
||||
|
||||
}
|
||||
|
||||
void OscDevice::addRequestHandler(RequestHandler* handler)
|
||||
{
|
||||
if (handler)
|
||||
{
|
||||
_map.insert(std::make_pair(handler->getRequestPath(), handler));
|
||||
handler->setDevice(this);
|
||||
}
|
||||
}
|
||||
|
||||
void OscDevice::describeTo(std::ostream& out) const
|
||||
{
|
||||
out << "OscDevice :: listening on " << _listeningAddress << ":" << _listeningPort << std::endl;
|
||||
out << std::endl;
|
||||
|
||||
for(RequestHandlerMap::const_iterator i = _map.begin(); i != _map.end(); ++i)
|
||||
{
|
||||
const RequestHandler* handler(i->second.get());
|
||||
out << "OscDevice :: ";
|
||||
handler->describeTo(out);
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
}
|
111
src/osgPlugins/osc/OscDevice.hpp
Executable file
111
src/osgPlugins/osc/OscDevice.hpp
Executable file
@ -0,0 +1,111 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osg/Referenced>
|
||||
#include <OpenThreads/Thread>
|
||||
#include <osgGA/Device>
|
||||
#include <osc/OscPacketListener.h>
|
||||
#include <ip/UdpSocket.h>
|
||||
|
||||
|
||||
class OscDevice : public osgGA::Device, OpenThreads::Thread, osc::OscPacketListener {
|
||||
|
||||
public:
|
||||
class RequestHandler : public osg::Referenced {
|
||||
public:
|
||||
RequestHandler(const std::string& request_path)
|
||||
: osg::Referenced()
|
||||
, _requestPath(request_path)
|
||||
, _device(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m) = 0;
|
||||
|
||||
const std::string& getRequestPath() const { return _requestPath; }
|
||||
|
||||
virtual void describeTo(std::ostream& out) const
|
||||
{
|
||||
out << getRequestPath() << ": no description available";
|
||||
}
|
||||
|
||||
protected:
|
||||
void setDevice(OscDevice* device) { _device = device; }
|
||||
OscDevice* getDevice() const { return _device; }
|
||||
|
||||
/// set the request-path, works only from the constructor
|
||||
void setRequestPath(const std::string& request_path) { _requestPath = request_path; }
|
||||
|
||||
void handleException(const osc::Exception& e)
|
||||
{
|
||||
OSG_WARN << "OscDevice :: error while handling " << getRequestPath() << ": " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
double getLocalTime() const { return getDevice()->getEventQueue()->getTime(); }
|
||||
private:
|
||||
std::string _requestPath;
|
||||
OscDevice* _device;
|
||||
friend class OscDevice;
|
||||
};
|
||||
|
||||
typedef std::multimap<std::string, osg::ref_ptr<RequestHandler> > RequestHandlerMap;
|
||||
|
||||
OscDevice(const std::string& server_address, int listening_port);
|
||||
~OscDevice();
|
||||
|
||||
virtual void checkEvents() {}
|
||||
virtual void run();
|
||||
|
||||
virtual void ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint );
|
||||
|
||||
void addRequestHandler(RequestHandler* handler);
|
||||
|
||||
void describeTo(std::ostream& out) const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, const OscDevice& device)
|
||||
{
|
||||
device.describeTo(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _listeningAddress;
|
||||
unsigned int _listeningPort;
|
||||
UdpListeningReceiveSocket* _socket;
|
||||
RequestHandlerMap _map;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class SendKeystrokeRequestHandler : public OscDevice::RequestHandler {
|
||||
public:
|
||||
SendKeystrokeRequestHandler(const std::string& request_path, int key) : OscDevice::RequestHandler(request_path), _key(key) {}
|
||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& arguments)
|
||||
{
|
||||
getDevice()->getEventQueue()->keyPress(_key);
|
||||
getDevice()->getEventQueue()->keyRelease(_key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void describeTo(std::ostream& out) const
|
||||
{
|
||||
out << getRequestPath() << ": send KEY_DOWN + KEY_UP, code: 0x" << std::hex << _key << std::dec;
|
||||
}
|
||||
private:
|
||||
int _key;
|
||||
};
|
||||
|
107
src/osgPlugins/osc/OscProxyEventHandler.cpp
Executable file
107
src/osgPlugins/osc/OscProxyEventHandler.cpp
Executable file
@ -0,0 +1,107 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "OscProxyEventHandler.hpp"
|
||||
|
||||
static const unsigned long BUFFER_SIZE = 2048;
|
||||
|
||||
OscProxyEventHandler::OscProxyEventHandler(const std::string& address, int port)
|
||||
: osgGA::GUIEventHandler()
|
||||
, _transmitSocket(IpEndpointName(address.c_str(), port))
|
||||
, _buffer(new char[BUFFER_SIZE])
|
||||
, _oscStream(_buffer, BUFFER_SIZE)
|
||||
, _firstRun(true)
|
||||
{
|
||||
OSG_INFO << "OscDevice :: sending events to " << address << ":" << port << std::endl;
|
||||
}
|
||||
|
||||
|
||||
OscProxyEventHandler::~OscProxyEventHandler()
|
||||
{
|
||||
delete[] (_buffer);
|
||||
}
|
||||
|
||||
bool OscProxyEventHandler::handle (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa, osg::Object *, osg::NodeVisitor *)
|
||||
{
|
||||
bool do_send(false);
|
||||
switch(ea.getEventType())
|
||||
{
|
||||
case osgGA::GUIEventAdapter::FRAME:
|
||||
if (_firstRun)
|
||||
{
|
||||
_firstRun = false;
|
||||
sendInit(ea);
|
||||
do_send = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case osgGA::GUIEventAdapter::RESIZE:
|
||||
sendInit(ea);
|
||||
do_send = true;
|
||||
|
||||
break;
|
||||
case osgGA::GUIEventAdapter::PUSH:
|
||||
_oscStream << osc::BeginMessage("/osgga/mouse/press") << ea.getX() << ea.getY() << ea.getButton() << osc::EndMessage;
|
||||
do_send = true;
|
||||
break;
|
||||
|
||||
case osgGA::GUIEventAdapter::RELEASE:
|
||||
_oscStream << osc::BeginMessage("/osgga/mouse/release") << ea.getX() << ea.getY() << ea.getButton() << osc::EndMessage;
|
||||
do_send = true;
|
||||
break;
|
||||
|
||||
case osgGA::GUIEventAdapter::DOUBLECLICK:
|
||||
_oscStream << osc::BeginMessage("/osgga/mouse/doublepress") << ea.getX() << ea.getY() << ea.getButton() << osc::EndMessage;
|
||||
do_send = true;
|
||||
break;
|
||||
|
||||
case osgGA::GUIEventAdapter::MOVE:
|
||||
case osgGA::GUIEventAdapter::DRAG:
|
||||
_oscStream << osc::BeginMessage("/osgga/mouse/motion") << ea.getX() << ea.getY() << osc::EndMessage;
|
||||
do_send = true;
|
||||
break;
|
||||
|
||||
case osgGA::GUIEventAdapter::KEYDOWN:
|
||||
_oscStream << osc::BeginMessage("/osgga/key/press") << ea.getKey() << osc::EndMessage;
|
||||
do_send = true;
|
||||
break;
|
||||
|
||||
case osgGA::GUIEventAdapter::KEYUP:
|
||||
_oscStream << osc::BeginMessage("/osgga/key/release") << ea.getKey() << osc::EndMessage;
|
||||
do_send = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
if (do_send)
|
||||
{
|
||||
OSG_INFO << "OscDevice :: sending event per OSC " << std::endl;
|
||||
|
||||
_transmitSocket.Send( _oscStream.Data(), _oscStream.Size() );
|
||||
_oscStream.Clear();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void OscProxyEventHandler::sendInit(const osgGA::GUIEventAdapter &ea)
|
||||
{
|
||||
_oscStream << osc::BeginBundle();
|
||||
_oscStream << osc::BeginMessage("/osgga/resize") << ea.getWindowX() << ea.getWindowY() << ea.getWindowWidth() << ea.getWindowHeight() << osc::EndMessage;
|
||||
_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;
|
||||
_oscStream << osc::EndBundle;
|
||||
}
|
37
src/osgPlugins/osc/OscProxyEventHandler.hpp
Executable file
37
src/osgPlugins/osc/OscProxyEventHandler.hpp
Executable file
@ -0,0 +1,37 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include <osgGA/GUIEventHandler>
|
||||
#include <ip/UdpSocket.h>
|
||||
#include <osc/OscOutboundPacketStream.h>
|
||||
|
||||
class OscProxyEventHandler : public osgGA::GUIEventHandler {
|
||||
public:
|
||||
OscProxyEventHandler(const std::string& address, int port);
|
||||
~OscProxyEventHandler();
|
||||
virtual bool handle (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa, osg::Object *, osg::NodeVisitor *);
|
||||
|
||||
private:
|
||||
void sendInit(const osgGA::GUIEventAdapter& ea);
|
||||
UdpTransmitSocket _transmitSocket;
|
||||
char* _buffer;
|
||||
osc::OutboundPacketStream _oscStream;
|
||||
bool _firstRun;
|
||||
|
||||
};
|
||||
|
160
src/osgPlugins/osc/ReaderWriterOscDevice.cpp
Executable file
160
src/osgPlugins/osc/ReaderWriterOscDevice.cpp
Executable file
@ -0,0 +1,160 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* ReadMe
|
||||
*
|
||||
* the osc-plugin can return an osgGA::Device which handles various osc-messages
|
||||
* and puts them into the event-queue of the app
|
||||
* To open the osc-device for receiving do something like this:
|
||||
*
|
||||
* std::string filename = "<your-port-number-to-listen-on>.receiver.osc";
|
||||
* osgGA::Device* device = dynamic_cast<osgGA::Device*>(osgDB::readObjectFile(filename));
|
||||
*
|
||||
* and add that device to your viewer
|
||||
* The plugin supports the following option: documentRegisteredHandlers, which will
|
||||
* dump all registered handlers to the console. The device registers some convenient
|
||||
* handlers to remote control a p3d-presentation.
|
||||
*
|
||||
*
|
||||
* The plugin supports forwarding most of the events per osc to another host.
|
||||
* It uses a special event-handler, which forwards the events. To get this
|
||||
* event-handler, do something like this:
|
||||
*
|
||||
* std::string filename = "<target-address>:<target-port>.sender.osc";
|
||||
* osgGA::GUIEventHandler* event_handler = dynamic_cast<osgGA::GUIEventHandler*>(osgDB::readObjectFile(filename));
|
||||
*
|
||||
* and add that event handler as the first event handler to your viewer/app
|
||||
*
|
||||
*
|
||||
* TODO:
|
||||
* - add multitouch support, preferably using the TUIO-protocol
|
||||
* - be more tolerant with given filenames
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <osgDB/Registry>
|
||||
#include <osgDB/FileNameUtils>
|
||||
#include <osgDB/FileUtils>
|
||||
#include "OscDevice.hpp"
|
||||
#include "OscProxyEventHandler.hpp"
|
||||
|
||||
|
||||
|
||||
|
||||
class ReaderWriterOsc : public osgDB::ReaderWriter
|
||||
{
|
||||
public:
|
||||
|
||||
ReaderWriterOsc()
|
||||
{
|
||||
supportsExtension("osc", "Virtual Device Integration via a OSC_receiver");
|
||||
supportsOption("documentRegisteredHandlers", "dump a documentation of all registered REST-handler to the console");
|
||||
|
||||
}
|
||||
|
||||
virtual const char* className() const { return "OSC Virtual Device Integration plugin"; }
|
||||
|
||||
virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const
|
||||
{
|
||||
if (osgDB::getFileExtension(file) == "osc")
|
||||
{
|
||||
std::string file_name = osgDB::getNameLessExtension(file);
|
||||
|
||||
if (osgDB::getFileExtension(file_name) == "sender")
|
||||
{
|
||||
file_name = osgDB::getNameLessExtension(file_name);
|
||||
|
||||
std::string server_address = file_name.substr(0,file_name.find(':'));
|
||||
std::string server_port = file_name.substr(file_name.find(':') + 1);
|
||||
|
||||
return new OscProxyEventHandler(server_address, atoi(server_port.c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// defaults to receiver
|
||||
file_name = osgDB::getNameLessExtension(file_name);
|
||||
if (file_name.find(':') == std::string::npos) {
|
||||
file_name = "0.0.0.0:" + file_name;
|
||||
}
|
||||
std::string server_address = file_name.substr(0,file_name.find(':'));
|
||||
std::string server_port = file_name.substr(file_name.find(':') + 1);
|
||||
int port = atoi(server_port.c_str());
|
||||
if (port <= 0)
|
||||
{
|
||||
OSG_WARN << "ReaderWriterOsc :: can't get valid port from " << osgDB::getNameLessAllExtensions(file) << std::endl;
|
||||
port = 8000;
|
||||
}
|
||||
try {
|
||||
|
||||
osg::ref_ptr<OscDevice> device = new OscDevice(server_address, port);
|
||||
|
||||
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/p3d/slide/first", osgGA::GUIEventAdapter::KEY_Home));
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/p3d/slide/last", osgGA::GUIEventAdapter::KEY_End));
|
||||
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/p3d/slide/next", osgGA::GUIEventAdapter::KEY_Right));
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/p3d/slide/previous", osgGA::GUIEventAdapter::KEY_Left));
|
||||
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/p3d/layer/next", osgGA::GUIEventAdapter::KEY_Down));
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/p3d/layer/previous", osgGA::GUIEventAdapter::KEY_Up));
|
||||
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/p3d/slideorlayer/next", osgGA::GUIEventAdapter::KEY_Page_Down));
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/p3d/slideorlayer/previous", osgGA::GUIEventAdapter::KEY_Page_Up));
|
||||
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/p3d/unpause", 'o'));
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/p3d/pause", 'p'));
|
||||
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/osgviewer/home", ' '));
|
||||
device->addRequestHandler(new SendKeystrokeRequestHandler("/osgviewer/stats", 's'));
|
||||
|
||||
|
||||
|
||||
if ((options && (options->getPluginStringData("documentRegisteredHandlers") == "true")))
|
||||
{
|
||||
std::cout << *device << std::endl;
|
||||
}
|
||||
|
||||
|
||||
return device.release();
|
||||
}
|
||||
catch(const osc::Exception& e)
|
||||
{
|
||||
OSG_WARN << "OscDevice :: could not register UDP listener : " << e.what() << std::endl;
|
||||
return ReadResult::ERROR_IN_READING_FILE;
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
OSG_WARN << "OscDevice :: could not register UDP listener : " << e.what() << std::endl;
|
||||
return ReadResult::ERROR_IN_READING_FILE;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
OSG_WARN << "OscDevice :: could not register UDP listener" << std::endl;
|
||||
return ReadResult::ERROR_IN_READING_FILE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ReadResult::FILE_NOT_HANDLED;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// now register with Registry to instantiate the above
|
||||
// reader/writer.
|
||||
REGISTER_OSGPLUGIN(osc, ReaderWriterOsc)
|
81
src/osgPlugins/osc/ip/IpEndpointName.cpp
Normal file
81
src/osgPlugins/osc/ip/IpEndpointName.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "IpEndpointName.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "NetworkingUtils.h"
|
||||
|
||||
|
||||
unsigned long IpEndpointName::GetHostByName( const char *s )
|
||||
{
|
||||
return ::GetHostByName(s);
|
||||
}
|
||||
|
||||
|
||||
void IpEndpointName::AddressAsString( char *s ) const
|
||||
{
|
||||
if( address == ANY_ADDRESS ){
|
||||
sprintf( s, "<any>" );
|
||||
}else{
|
||||
sprintf( s, "%d.%d.%d.%d",
|
||||
(int)((address >> 24) & 0xFF),
|
||||
(int)((address >> 16) & 0xFF),
|
||||
(int)((address >> 8) & 0xFF),
|
||||
(int)(address & 0xFF) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IpEndpointName::AddressAndPortAsString( char *s ) const
|
||||
{
|
||||
if( port == ANY_PORT ){
|
||||
if( address == ANY_ADDRESS ){
|
||||
sprintf( s, "<any>:<any>" );
|
||||
}else{
|
||||
sprintf( s, "%d.%d.%d.%d:<any>",
|
||||
(int)((address >> 24) & 0xFF),
|
||||
(int)((address >> 16) & 0xFF),
|
||||
(int)((address >> 8) & 0xFF),
|
||||
(int)(address & 0xFF) );
|
||||
}
|
||||
}else{
|
||||
if( address == ANY_ADDRESS ){
|
||||
sprintf( s, "<any>:%d", port );
|
||||
}else{
|
||||
sprintf( s, "%d.%d.%d.%d:%d",
|
||||
(int)((address >> 24) & 0xFF),
|
||||
(int)((address >> 16) & 0xFF),
|
||||
(int)((address >> 8) & 0xFF),
|
||||
(int)(address & 0xFF),
|
||||
(int)port );
|
||||
}
|
||||
}
|
||||
}
|
76
src/osgPlugins/osc/ip/IpEndpointName.h
Normal file
76
src/osgPlugins/osc/ip/IpEndpointName.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_IPENDPOINTNAME_H
|
||||
#define INCLUDED_IPENDPOINTNAME_H
|
||||
|
||||
|
||||
class IpEndpointName{
|
||||
static unsigned long GetHostByName( const char *s );
|
||||
public:
|
||||
static const unsigned long ANY_ADDRESS = 0xFFFFFFFF;
|
||||
static const int ANY_PORT = -1;
|
||||
|
||||
IpEndpointName()
|
||||
: address( ANY_ADDRESS ), port( ANY_PORT ) {}
|
||||
IpEndpointName( int port_ )
|
||||
: address( ANY_ADDRESS ), port( port_ ) {}
|
||||
IpEndpointName( unsigned long ipAddress_, int port_ )
|
||||
: address( ipAddress_ ), port( port_ ) {}
|
||||
IpEndpointName( const char *addressName, int port_=ANY_PORT )
|
||||
: address( GetHostByName( addressName ) )
|
||||
, port( port_ ) {}
|
||||
IpEndpointName( int addressA, int addressB, int addressC, int addressD, int port_=ANY_PORT )
|
||||
: address( ( (addressA << 24) | (addressB << 16) | (addressC << 8) | addressD ) )
|
||||
, port( port_ ) {}
|
||||
|
||||
// address and port are maintained in host byte order here
|
||||
unsigned long address;
|
||||
int port;
|
||||
|
||||
bool IsMulticastAddress() const { return ((address >> 24) & 0xFF) >= 224 && ((address >> 24) & 0xFF) <= 239; }
|
||||
|
||||
enum { ADDRESS_STRING_LENGTH=17 };
|
||||
void AddressAsString( char *s ) const;
|
||||
|
||||
enum { ADDRESS_AND_PORT_STRING_LENGTH=23};
|
||||
void AddressAndPortAsString( char *s ) const;
|
||||
};
|
||||
|
||||
inline bool operator==( const IpEndpointName& lhs, const IpEndpointName& rhs )
|
||||
{
|
||||
return (lhs.address == rhs.address && lhs.port == rhs.port );
|
||||
}
|
||||
|
||||
inline bool operator!=( const IpEndpointName& lhs, const IpEndpointName& rhs )
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
#endif /* INCLUDED_IPENDPOINTNAME_H */
|
49
src/osgPlugins/osc/ip/NetworkingUtils.h
Normal file
49
src/osgPlugins/osc/ip/NetworkingUtils.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_NETWORKINGUTILS_H
|
||||
#define INCLUDED_NETWORKINGUTILS_H
|
||||
|
||||
|
||||
// in general NetworkInitializer is only used internally, but if you're
|
||||
// application creates multiple sockets from different threads at runtime you
|
||||
// should instantiate one of these in main just to make sure the networking
|
||||
// layer is initialized.
|
||||
class NetworkInitializer{
|
||||
public:
|
||||
NetworkInitializer();
|
||||
~NetworkInitializer();
|
||||
};
|
||||
|
||||
|
||||
// return ip address of host name in host byte order
|
||||
unsigned long GetHostByName( const char *name );
|
||||
|
||||
|
||||
#endif /* INCLUDED_NETWORKINGUTILS_H */
|
43
src/osgPlugins/osc/ip/PacketListener.h
Normal file
43
src/osgPlugins/osc/ip/PacketListener.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_PACKETLISTENER_H
|
||||
#define INCLUDED_PACKETLISTENER_H
|
||||
|
||||
|
||||
class IpEndpointName;
|
||||
|
||||
class PacketListener{
|
||||
public:
|
||||
virtual ~PacketListener() {}
|
||||
virtual void ProcessPacket( const char *data, int size,
|
||||
const IpEndpointName& remoteEndpoint ) = 0;
|
||||
};
|
||||
|
||||
#endif /* INCLUDED_PACKETLISTENER_H */
|
40
src/osgPlugins/osc/ip/TimerListener.h
Normal file
40
src/osgPlugins/osc/ip/TimerListener.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_TIMERLISTENER_H
|
||||
#define INCLUDED_TIMERLISTENER_H
|
||||
|
||||
|
||||
class TimerListener{
|
||||
public:
|
||||
virtual ~TimerListener() {}
|
||||
virtual void TimerExpired() = 0;
|
||||
};
|
||||
|
||||
#endif /* INCLUDED_TIMERLISTENER_H */
|
158
src/osgPlugins/osc/ip/UdpSocket.h
Normal file
158
src/osgPlugins/osc/ip/UdpSocket.h
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_UDPSOCKET_H
|
||||
#define INCLUDED_UDPSOCKET_H
|
||||
|
||||
#ifndef INCLUDED_NETWORKINGUTILITIES_H
|
||||
#include "NetworkingUtils.h"
|
||||
#endif /* INCLUDED_NETWORKINGUTILITIES_H */
|
||||
|
||||
#ifndef INCLUDED_IPENDPOINTNAME_H
|
||||
#include "IpEndpointName.h"
|
||||
#endif /* INCLUDED_IPENDPOINTNAME_H */
|
||||
|
||||
|
||||
class PacketListener;
|
||||
class TimerListener;
|
||||
|
||||
class UdpSocket;
|
||||
|
||||
class SocketReceiveMultiplexer{
|
||||
class Implementation;
|
||||
Implementation *impl_;
|
||||
|
||||
friend class UdpSocket;
|
||||
|
||||
public:
|
||||
SocketReceiveMultiplexer();
|
||||
~SocketReceiveMultiplexer();
|
||||
|
||||
// only call the attach/detach methods _before_ calling Run
|
||||
|
||||
// only one listener per socket, each socket at most once
|
||||
void AttachSocketListener( UdpSocket *socket, PacketListener *listener );
|
||||
void DetachSocketListener( UdpSocket *socket, PacketListener *listener );
|
||||
|
||||
void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener );
|
||||
void AttachPeriodicTimerListener(
|
||||
int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener );
|
||||
void DetachPeriodicTimerListener( TimerListener *listener );
|
||||
|
||||
void Run(); // loop and block processing messages indefinitely
|
||||
void RunUntilSigInt();
|
||||
void Break(); // call this from a listener to exit once the listener returns
|
||||
void AsynchronousBreak(); // call this from another thread or signal handler to exit the Run() state
|
||||
};
|
||||
|
||||
|
||||
class UdpSocket{
|
||||
class Implementation;
|
||||
Implementation *impl_;
|
||||
|
||||
friend class SocketReceiveMultiplexer::Implementation;
|
||||
|
||||
public:
|
||||
|
||||
// ctor throws std::runtime_error if there's a problem
|
||||
// initializing the socket.
|
||||
UdpSocket();
|
||||
virtual ~UdpSocket();
|
||||
|
||||
// the socket is created in an unbound, unconnected state
|
||||
// such a socket can only be used to send to an arbitrary
|
||||
// address using SendTo(). To use Send() you need to first
|
||||
// connect to a remote endpoint using Connect(). To use
|
||||
// ReceiveFrom you need to first bind to a local endpoint
|
||||
// using Bind().
|
||||
|
||||
// retrieve the local endpoint name when sending to 'to'
|
||||
IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const;
|
||||
|
||||
// Connect to a remote endpoint which is used as the target
|
||||
// for calls to Send()
|
||||
void Connect( const IpEndpointName& remoteEndpoint );
|
||||
void Send( const char *data, int size );
|
||||
void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size );
|
||||
|
||||
|
||||
// Bind a local endpoint to receive incoming data. Endpoint
|
||||
// can be 'any' for the system to choose an endpoint
|
||||
void Bind( const IpEndpointName& localEndpoint );
|
||||
bool IsBound() const;
|
||||
|
||||
int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size );
|
||||
};
|
||||
|
||||
|
||||
// convenience classes for transmitting and receiving
|
||||
// they just call Connect and/or Bind in the ctor.
|
||||
// note that you can still use a receive socket
|
||||
// for transmitting etc
|
||||
|
||||
class UdpTransmitSocket : public UdpSocket{
|
||||
public:
|
||||
UdpTransmitSocket( const IpEndpointName& remoteEndpoint )
|
||||
{ Connect( remoteEndpoint ); }
|
||||
};
|
||||
|
||||
|
||||
class UdpReceiveSocket : public UdpSocket{
|
||||
public:
|
||||
UdpReceiveSocket( const IpEndpointName& localEndpoint )
|
||||
{ Bind( localEndpoint ); }
|
||||
};
|
||||
|
||||
|
||||
// UdpListeningReceiveSocket provides a simple way to bind one listener
|
||||
// to a single socket without having to manually set up a SocketReceiveMultiplexer
|
||||
|
||||
class UdpListeningReceiveSocket : public UdpSocket{
|
||||
SocketReceiveMultiplexer mux_;
|
||||
PacketListener *listener_;
|
||||
public:
|
||||
UdpListeningReceiveSocket( const IpEndpointName& localEndpoint, PacketListener *listener )
|
||||
: listener_( listener )
|
||||
{
|
||||
Bind( localEndpoint );
|
||||
mux_.AttachSocketListener( this, listener_ );
|
||||
}
|
||||
|
||||
~UdpListeningReceiveSocket()
|
||||
{ mux_.DetachSocketListener( this, listener_ ); }
|
||||
|
||||
// see SocketReceiveMultiplexer above for the behaviour of these methods...
|
||||
void Run() { mux_.Run(); }
|
||||
void RunUntilSigInt() { mux_.RunUntilSigInt(); }
|
||||
void Break() { mux_.Break(); }
|
||||
void AsynchronousBreak() { mux_.AsynchronousBreak(); }
|
||||
};
|
||||
|
||||
|
||||
#endif /* INCLUDED_UDPSOCKET_H */
|
57
src/osgPlugins/osc/ip/posix/NetworkingUtils.cpp
Normal file
57
src/osgPlugins/osc/ip/posix/NetworkingUtils.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "ip/NetworkingUtils.h"
|
||||
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
NetworkInitializer::NetworkInitializer() {}
|
||||
|
||||
NetworkInitializer::~NetworkInitializer() {}
|
||||
|
||||
|
||||
unsigned long GetHostByName( const char *name )
|
||||
{
|
||||
unsigned long result = 0;
|
||||
|
||||
struct hostent *h = gethostbyname( name );
|
||||
if( h ){
|
||||
struct in_addr a;
|
||||
memcpy( &a, h->h_addr_list[0], h->h_length );
|
||||
result = ntohl(a.s_addr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
546
src/osgPlugins/osc/ip/posix/UdpSocket.cpp
Normal file
546
src/osgPlugins/osc/ip/posix/UdpSocket.cpp
Normal file
@ -0,0 +1,546 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "ip/UdpSocket.h"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <string.h> // for memset
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h> // for sockaddr_in
|
||||
|
||||
#include "ip/PacketListener.h"
|
||||
#include "ip/TimerListener.h"
|
||||
|
||||
|
||||
#if defined(__APPLE__) && !defined(_SOCKLEN_T)
|
||||
// pre system 10.3 didn have socklen_t
|
||||
typedef ssize_t socklen_t;
|
||||
#endif
|
||||
|
||||
|
||||
static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint )
|
||||
{
|
||||
memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
|
||||
sockAddr.sin_family = AF_INET;
|
||||
|
||||
sockAddr.sin_addr.s_addr =
|
||||
(endpoint.address == IpEndpointName::ANY_ADDRESS)
|
||||
? INADDR_ANY
|
||||
: htonl( endpoint.address );
|
||||
|
||||
sockAddr.sin_port =
|
||||
(endpoint.port == IpEndpointName::ANY_PORT)
|
||||
? 0
|
||||
: htons( endpoint.port );
|
||||
}
|
||||
|
||||
|
||||
static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr )
|
||||
{
|
||||
return IpEndpointName(
|
||||
(sockAddr.sin_addr.s_addr == INADDR_ANY)
|
||||
? IpEndpointName::ANY_ADDRESS
|
||||
: ntohl( sockAddr.sin_addr.s_addr ),
|
||||
(sockAddr.sin_port == 0)
|
||||
? IpEndpointName::ANY_PORT
|
||||
: ntohs( sockAddr.sin_port )
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
class UdpSocket::Implementation{
|
||||
bool isBound_;
|
||||
bool isConnected_;
|
||||
|
||||
int socket_;
|
||||
struct sockaddr_in connectedAddr_;
|
||||
struct sockaddr_in sendToAddr_;
|
||||
|
||||
public:
|
||||
|
||||
Implementation()
|
||||
: isBound_( false )
|
||||
, isConnected_( false )
|
||||
, socket_( -1 )
|
||||
{
|
||||
if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == -1 ){
|
||||
throw std::runtime_error("unable to create udp socket\n");
|
||||
}
|
||||
|
||||
memset( &sendToAddr_, 0, sizeof(sendToAddr_) );
|
||||
sendToAddr_.sin_family = AF_INET;
|
||||
}
|
||||
|
||||
~Implementation()
|
||||
{
|
||||
if (socket_ != -1) close(socket_);
|
||||
}
|
||||
|
||||
IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
|
||||
{
|
||||
assert( isBound_ );
|
||||
|
||||
// first connect the socket to the remote server
|
||||
|
||||
struct sockaddr_in connectSockAddr;
|
||||
SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint );
|
||||
|
||||
if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) {
|
||||
throw std::runtime_error("unable to connect udp socket\n");
|
||||
}
|
||||
|
||||
// get the address
|
||||
|
||||
struct sockaddr_in sockAddr;
|
||||
memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
|
||||
socklen_t length = sizeof(sockAddr);
|
||||
if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) {
|
||||
throw std::runtime_error("unable to getsockname\n");
|
||||
}
|
||||
|
||||
if( isConnected_ ){
|
||||
// reconnect to the connected address
|
||||
|
||||
if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
|
||||
throw std::runtime_error("unable to connect udp socket\n");
|
||||
}
|
||||
|
||||
}else{
|
||||
// unconnect from the remote address
|
||||
|
||||
struct sockaddr_in unconnectSockAddr;
|
||||
memset( (char *)&unconnectSockAddr, 0, sizeof(unconnectSockAddr ) );
|
||||
unconnectSockAddr.sin_family = AF_UNSPEC;
|
||||
// address fields are zero
|
||||
int connectResult = connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr));
|
||||
if ( connectResult < 0 && errno != EAFNOSUPPORT ) {
|
||||
throw std::runtime_error("unable to un-connect udp socket\n");
|
||||
}
|
||||
}
|
||||
|
||||
return IpEndpointNameFromSockaddr( sockAddr );
|
||||
}
|
||||
|
||||
void Connect( const IpEndpointName& remoteEndpoint )
|
||||
{
|
||||
SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint );
|
||||
|
||||
if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
|
||||
throw std::runtime_error("unable to connect udp socket\n");
|
||||
}
|
||||
|
||||
isConnected_ = true;
|
||||
}
|
||||
|
||||
void Send( const char *data, int size )
|
||||
{
|
||||
assert( isConnected_ );
|
||||
|
||||
send( socket_, data, size, 0 );
|
||||
}
|
||||
|
||||
void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size )
|
||||
{
|
||||
sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address );
|
||||
sendToAddr_.sin_port = htons( remoteEndpoint.port );
|
||||
|
||||
sendto( socket_, data, size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) );
|
||||
}
|
||||
|
||||
void Bind( const IpEndpointName& localEndpoint )
|
||||
{
|
||||
struct sockaddr_in bindSockAddr;
|
||||
SockaddrFromIpEndpointName( bindSockAddr, localEndpoint );
|
||||
|
||||
if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) {
|
||||
throw std::runtime_error("unable to bind udp socket\n");
|
||||
}
|
||||
|
||||
isBound_ = true;
|
||||
}
|
||||
|
||||
bool IsBound() const { return isBound_; }
|
||||
|
||||
int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size )
|
||||
{
|
||||
assert( isBound_ );
|
||||
|
||||
struct sockaddr_in fromAddr;
|
||||
socklen_t fromAddrLen = sizeof(fromAddr);
|
||||
|
||||
int result = recvfrom(socket_, data, size, 0,
|
||||
(struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen);
|
||||
if( result < 0 )
|
||||
return 0;
|
||||
|
||||
remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr);
|
||||
remoteEndpoint.port = ntohs(fromAddr.sin_port);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int Socket() { return socket_; }
|
||||
};
|
||||
|
||||
UdpSocket::UdpSocket()
|
||||
{
|
||||
impl_ = new Implementation();
|
||||
}
|
||||
|
||||
UdpSocket::~UdpSocket()
|
||||
{
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
|
||||
{
|
||||
return impl_->LocalEndpointFor( remoteEndpoint );
|
||||
}
|
||||
|
||||
void UdpSocket::Connect( const IpEndpointName& remoteEndpoint )
|
||||
{
|
||||
impl_->Connect( remoteEndpoint );
|
||||
}
|
||||
|
||||
void UdpSocket::Send( const char *data, int size )
|
||||
{
|
||||
impl_->Send( data, size );
|
||||
}
|
||||
|
||||
void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size )
|
||||
{
|
||||
impl_->SendTo( remoteEndpoint, data, size );
|
||||
}
|
||||
|
||||
void UdpSocket::Bind( const IpEndpointName& localEndpoint )
|
||||
{
|
||||
impl_->Bind( localEndpoint );
|
||||
}
|
||||
|
||||
bool UdpSocket::IsBound() const
|
||||
{
|
||||
return impl_->IsBound();
|
||||
}
|
||||
|
||||
int UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size )
|
||||
{
|
||||
return impl_->ReceiveFrom( remoteEndpoint, data, size );
|
||||
}
|
||||
|
||||
|
||||
struct AttachedTimerListener{
|
||||
AttachedTimerListener( int id, int p, TimerListener *tl )
|
||||
: initialDelayMs( id )
|
||||
, periodMs( p )
|
||||
, listener( tl ) {}
|
||||
int initialDelayMs;
|
||||
int periodMs;
|
||||
TimerListener *listener;
|
||||
};
|
||||
|
||||
|
||||
static bool CompareScheduledTimerCalls(
|
||||
const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs )
|
||||
{
|
||||
return lhs.first < rhs.first;
|
||||
}
|
||||
|
||||
|
||||
SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0;
|
||||
|
||||
extern "C" /*static*/ void InterruptSignalHandler( int );
|
||||
/*static*/ void InterruptSignalHandler( int )
|
||||
{
|
||||
multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak();
|
||||
signal( SIGINT, SIG_DFL );
|
||||
}
|
||||
|
||||
|
||||
class SocketReceiveMultiplexer::Implementation{
|
||||
std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_;
|
||||
std::vector< AttachedTimerListener > timerListeners_;
|
||||
|
||||
volatile bool break_;
|
||||
int breakPipe_[2]; // [0] is the reader descriptor and [1] the writer
|
||||
|
||||
double GetCurrentTimeMs() const
|
||||
{
|
||||
struct timeval t;
|
||||
|
||||
gettimeofday( &t, 0 );
|
||||
|
||||
return ((double)t.tv_sec*1000.) + ((double)t.tv_usec / 1000.);
|
||||
}
|
||||
|
||||
public:
|
||||
Implementation()
|
||||
{
|
||||
if( pipe(breakPipe_) != 0 )
|
||||
throw std::runtime_error( "creation of asynchronous break pipes failed\n" );
|
||||
}
|
||||
|
||||
~Implementation()
|
||||
{
|
||||
close( breakPipe_[0] );
|
||||
close( breakPipe_[1] );
|
||||
}
|
||||
|
||||
void AttachSocketListener( UdpSocket *socket, PacketListener *listener )
|
||||
{
|
||||
assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() );
|
||||
// we don't check that the same socket has been added multiple times, even though this is an error
|
||||
socketListeners_.push_back( std::make_pair( listener, socket ) );
|
||||
}
|
||||
|
||||
void DetachSocketListener( UdpSocket *socket, PacketListener *listener )
|
||||
{
|
||||
std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i =
|
||||
std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) );
|
||||
assert( i != socketListeners_.end() );
|
||||
|
||||
socketListeners_.erase( i );
|
||||
}
|
||||
|
||||
void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
|
||||
{
|
||||
timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) );
|
||||
}
|
||||
|
||||
void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
|
||||
{
|
||||
timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) );
|
||||
}
|
||||
|
||||
void DetachPeriodicTimerListener( TimerListener *listener )
|
||||
{
|
||||
std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
|
||||
while( i != timerListeners_.end() ){
|
||||
if( i->listener == listener )
|
||||
break;
|
||||
++i;
|
||||
}
|
||||
|
||||
assert( i != timerListeners_.end() );
|
||||
|
||||
timerListeners_.erase( i );
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
break_ = false;
|
||||
|
||||
// configure the master fd_set for select()
|
||||
|
||||
fd_set masterfds, tempfds;
|
||||
FD_ZERO( &masterfds );
|
||||
FD_ZERO( &tempfds );
|
||||
|
||||
// in addition to listening to the inbound sockets we
|
||||
// also listen to the asynchronous break pipe, so that AsynchronousBreak()
|
||||
// can break us out of select() from another thread.
|
||||
FD_SET( breakPipe_[0], &masterfds );
|
||||
int fdmax = breakPipe_[0];
|
||||
|
||||
for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
|
||||
i != socketListeners_.end(); ++i ){
|
||||
|
||||
if( fdmax < i->second->impl_->Socket() )
|
||||
fdmax = i->second->impl_->Socket();
|
||||
FD_SET( i->second->impl_->Socket(), &masterfds );
|
||||
}
|
||||
|
||||
|
||||
// configure the timer queue
|
||||
double currentTimeMs = GetCurrentTimeMs();
|
||||
|
||||
// expiry time ms, listener
|
||||
std::vector< std::pair< double, AttachedTimerListener > > timerQueue_;
|
||||
for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
|
||||
i != timerListeners_.end(); ++i )
|
||||
timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) );
|
||||
std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
|
||||
|
||||
const int MAX_BUFFER_SIZE = 4098;
|
||||
char *data = new char[ MAX_BUFFER_SIZE ];
|
||||
IpEndpointName remoteEndpoint;
|
||||
|
||||
struct timeval timeout;
|
||||
|
||||
while( !break_ ){
|
||||
tempfds = masterfds;
|
||||
|
||||
struct timeval *timeoutPtr = 0;
|
||||
if( !timerQueue_.empty() ){
|
||||
double timeoutMs = timerQueue_.front().first - GetCurrentTimeMs();
|
||||
if( timeoutMs < 0 )
|
||||
timeoutMs = 0;
|
||||
|
||||
// 1000000 microseconds in a second
|
||||
timeout.tv_sec = (long)(timeoutMs * .001);
|
||||
timeout.tv_usec = (long)((timeoutMs - (timeout.tv_sec * 1000)) * 1000);
|
||||
timeoutPtr = &timeout;
|
||||
}
|
||||
|
||||
if( select( fdmax + 1, &tempfds, 0, 0, timeoutPtr ) < 0 && errno != EINTR ){
|
||||
throw std::runtime_error("select failed\n");
|
||||
}
|
||||
|
||||
if ( FD_ISSET( breakPipe_[0], &tempfds ) ){
|
||||
// clear pending data from the asynchronous break pipe
|
||||
char c;
|
||||
read( breakPipe_[0], &c, 1 );
|
||||
}
|
||||
|
||||
if( break_ )
|
||||
break;
|
||||
|
||||
for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
|
||||
i != socketListeners_.end(); ++i ){
|
||||
|
||||
if( FD_ISSET( i->second->impl_->Socket(), &tempfds ) ){
|
||||
|
||||
int size = i->second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE );
|
||||
if( size > 0 ){
|
||||
i->first->ProcessPacket( data, size, remoteEndpoint );
|
||||
if( break_ )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// execute any expired timers
|
||||
currentTimeMs = GetCurrentTimeMs();
|
||||
bool resort = false;
|
||||
for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin();
|
||||
i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){
|
||||
|
||||
i->second.listener->TimerExpired();
|
||||
if( break_ )
|
||||
break;
|
||||
|
||||
i->first += i->second.periodMs;
|
||||
resort = true;
|
||||
}
|
||||
if( resort )
|
||||
std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
|
||||
}
|
||||
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
void Break()
|
||||
{
|
||||
break_ = true;
|
||||
}
|
||||
|
||||
void AsynchronousBreak()
|
||||
{
|
||||
break_ = true;
|
||||
|
||||
// Send a termination message to the asynchronous break pipe, so select() will return
|
||||
write( breakPipe_[1], "!", 1 );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
SocketReceiveMultiplexer::SocketReceiveMultiplexer()
|
||||
{
|
||||
impl_ = new Implementation();
|
||||
}
|
||||
|
||||
SocketReceiveMultiplexer::~SocketReceiveMultiplexer()
|
||||
{
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener )
|
||||
{
|
||||
impl_->AttachSocketListener( socket, listener );
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener )
|
||||
{
|
||||
impl_->DetachSocketListener( socket, listener );
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
|
||||
{
|
||||
impl_->AttachPeriodicTimerListener( periodMilliseconds, listener );
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
|
||||
{
|
||||
impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener );
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener )
|
||||
{
|
||||
impl_->DetachPeriodicTimerListener( listener );
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::Run()
|
||||
{
|
||||
impl_->Run();
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::RunUntilSigInt()
|
||||
{
|
||||
assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */
|
||||
multiplexerInstanceToAbortWithSigInt_ = this;
|
||||
signal( SIGINT, InterruptSignalHandler );
|
||||
impl_->Run();
|
||||
signal( SIGINT, SIG_DFL );
|
||||
multiplexerInstanceToAbortWithSigInt_ = 0;
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::Break()
|
||||
{
|
||||
impl_->Break();
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::AsynchronousBreak()
|
||||
{
|
||||
impl_->AsynchronousBreak();
|
||||
}
|
||||
|
88
src/osgPlugins/osc/ip/win32/NetworkingUtils.cpp
Normal file
88
src/osgPlugins/osc/ip/win32/NetworkingUtils.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "ip/NetworkingUtils.h"
|
||||
|
||||
#include <winsock2.h> // this must come first to prevent errors with MSVC7
|
||||
#include <windows.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
static LONG initCount_ = 0;
|
||||
static bool winsockInitialized_ = false;
|
||||
|
||||
NetworkInitializer::NetworkInitializer()
|
||||
{
|
||||
if( InterlockedIncrement( &initCount_ ) == 1 ){
|
||||
// there is a race condition here if one thread tries to access
|
||||
// the library while another is still initializing it.
|
||||
// i can't think of an easy way to fix it so i'm telling you here
|
||||
// incase you need to init the library from two threads at once.
|
||||
// this is why the header file advises to instantiate one of these
|
||||
// in main() so that the initialization happens globally
|
||||
|
||||
// initialize winsock
|
||||
WSAData wsaData;
|
||||
int nCode = WSAStartup(MAKEWORD(1, 1), &wsaData);
|
||||
if( nCode != 0 ){
|
||||
//std::cout << "WSAStartup() failed with error code " << nCode << "\n";
|
||||
}else{
|
||||
winsockInitialized_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NetworkInitializer::~NetworkInitializer()
|
||||
{
|
||||
if( InterlockedDecrement( &initCount_ ) == 0 ){
|
||||
if( winsockInitialized_ ){
|
||||
WSACleanup();
|
||||
winsockInitialized_ = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned long GetHostByName( const char *name )
|
||||
{
|
||||
NetworkInitializer networkInitializer;
|
||||
|
||||
unsigned long result = 0;
|
||||
|
||||
struct hostent *h = gethostbyname( name );
|
||||
if( h ){
|
||||
struct in_addr a;
|
||||
memcpy( &a, h->h_addr_list[0], h->h_length );
|
||||
result = ntohl(a.s_addr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
534
src/osgPlugins/osc/ip/win32/UdpSocket.cpp
Normal file
534
src/osgPlugins/osc/ip/win32/UdpSocket.cpp
Normal file
@ -0,0 +1,534 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "ip/UdpSocket.h"
|
||||
|
||||
#include <winsock2.h> // this must come first to prevent errors with MSVC7
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h> // for timeGetTime()
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef WINCE
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include "ip/NetworkingUtils.h"
|
||||
#include "ip/PacketListener.h"
|
||||
#include "ip/TimerListener.h"
|
||||
|
||||
|
||||
typedef int socklen_t;
|
||||
|
||||
|
||||
static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint )
|
||||
{
|
||||
memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
|
||||
sockAddr.sin_family = AF_INET;
|
||||
|
||||
sockAddr.sin_addr.s_addr =
|
||||
(endpoint.address == IpEndpointName::ANY_ADDRESS)
|
||||
? INADDR_ANY
|
||||
: htonl( endpoint.address );
|
||||
|
||||
sockAddr.sin_port =
|
||||
(endpoint.port == IpEndpointName::ANY_PORT)
|
||||
? (short)0
|
||||
: htons( (short)endpoint.port );
|
||||
}
|
||||
|
||||
|
||||
static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr )
|
||||
{
|
||||
return IpEndpointName(
|
||||
(sockAddr.sin_addr.s_addr == INADDR_ANY)
|
||||
? IpEndpointName::ANY_ADDRESS
|
||||
: ntohl( sockAddr.sin_addr.s_addr ),
|
||||
(sockAddr.sin_port == 0)
|
||||
? IpEndpointName::ANY_PORT
|
||||
: ntohs( sockAddr.sin_port )
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
class UdpSocket::Implementation{
|
||||
NetworkInitializer networkInitializer_;
|
||||
|
||||
bool isBound_;
|
||||
bool isConnected_;
|
||||
|
||||
SOCKET socket_;
|
||||
struct sockaddr_in connectedAddr_;
|
||||
struct sockaddr_in sendToAddr_;
|
||||
|
||||
public:
|
||||
|
||||
Implementation()
|
||||
: isBound_( false )
|
||||
, isConnected_( false )
|
||||
, socket_( INVALID_SOCKET )
|
||||
{
|
||||
if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == INVALID_SOCKET ){
|
||||
throw std::runtime_error("unable to create udp socket\n");
|
||||
}
|
||||
|
||||
memset( &sendToAddr_, 0, sizeof(sendToAddr_) );
|
||||
sendToAddr_.sin_family = AF_INET;
|
||||
}
|
||||
|
||||
~Implementation()
|
||||
{
|
||||
if (socket_ != INVALID_SOCKET) closesocket(socket_);
|
||||
}
|
||||
|
||||
IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
|
||||
{
|
||||
assert( isBound_ );
|
||||
|
||||
// first connect the socket to the remote server
|
||||
|
||||
struct sockaddr_in connectSockAddr;
|
||||
SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint );
|
||||
|
||||
if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) {
|
||||
throw std::runtime_error("unable to connect udp socket\n");
|
||||
}
|
||||
|
||||
// get the address
|
||||
|
||||
struct sockaddr_in sockAddr;
|
||||
memset( (char *)&sockAddr, 0, sizeof(sockAddr ) );
|
||||
socklen_t length = sizeof(sockAddr);
|
||||
if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) {
|
||||
throw std::runtime_error("unable to getsockname\n");
|
||||
}
|
||||
|
||||
if( isConnected_ ){
|
||||
// reconnect to the connected address
|
||||
|
||||
if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
|
||||
throw std::runtime_error("unable to connect udp socket\n");
|
||||
}
|
||||
|
||||
}else{
|
||||
// unconnect from the remote address
|
||||
|
||||
struct sockaddr_in unconnectSockAddr;
|
||||
SockaddrFromIpEndpointName( unconnectSockAddr, IpEndpointName() );
|
||||
|
||||
if( connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr)) < 0
|
||||
&& WSAGetLastError() != WSAEADDRNOTAVAIL ){
|
||||
throw std::runtime_error("unable to un-connect udp socket\n");
|
||||
}
|
||||
}
|
||||
|
||||
return IpEndpointNameFromSockaddr( sockAddr );
|
||||
}
|
||||
|
||||
void Connect( const IpEndpointName& remoteEndpoint )
|
||||
{
|
||||
SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint );
|
||||
|
||||
if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) {
|
||||
throw std::runtime_error("unable to connect udp socket\n");
|
||||
}
|
||||
|
||||
isConnected_ = true;
|
||||
}
|
||||
|
||||
void Send( const char *data, int size )
|
||||
{
|
||||
assert( isConnected_ );
|
||||
|
||||
send( socket_, data, size, 0 );
|
||||
}
|
||||
|
||||
void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size )
|
||||
{
|
||||
sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address );
|
||||
sendToAddr_.sin_port = htons( (short)remoteEndpoint.port );
|
||||
|
||||
sendto( socket_, data, size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) );
|
||||
}
|
||||
|
||||
void Bind( const IpEndpointName& localEndpoint )
|
||||
{
|
||||
struct sockaddr_in bindSockAddr;
|
||||
SockaddrFromIpEndpointName( bindSockAddr, localEndpoint );
|
||||
|
||||
if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) {
|
||||
throw std::runtime_error("unable to bind udp socket\n");
|
||||
}
|
||||
|
||||
isBound_ = true;
|
||||
}
|
||||
|
||||
bool IsBound() const { return isBound_; }
|
||||
|
||||
int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size )
|
||||
{
|
||||
assert( isBound_ );
|
||||
|
||||
struct sockaddr_in fromAddr;
|
||||
socklen_t fromAddrLen = sizeof(fromAddr);
|
||||
|
||||
int result = recvfrom(socket_, data, size, 0,
|
||||
(struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen);
|
||||
if( result < 0 )
|
||||
return 0;
|
||||
|
||||
remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr);
|
||||
remoteEndpoint.port = ntohs(fromAddr.sin_port);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SOCKET& Socket() { return socket_; }
|
||||
};
|
||||
|
||||
UdpSocket::UdpSocket()
|
||||
{
|
||||
impl_ = new Implementation();
|
||||
}
|
||||
|
||||
UdpSocket::~UdpSocket()
|
||||
{
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const
|
||||
{
|
||||
return impl_->LocalEndpointFor( remoteEndpoint );
|
||||
}
|
||||
|
||||
void UdpSocket::Connect( const IpEndpointName& remoteEndpoint )
|
||||
{
|
||||
impl_->Connect( remoteEndpoint );
|
||||
}
|
||||
|
||||
void UdpSocket::Send( const char *data, int size )
|
||||
{
|
||||
impl_->Send( data, size );
|
||||
}
|
||||
|
||||
void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size )
|
||||
{
|
||||
impl_->SendTo( remoteEndpoint, data, size );
|
||||
}
|
||||
|
||||
void UdpSocket::Bind( const IpEndpointName& localEndpoint )
|
||||
{
|
||||
impl_->Bind( localEndpoint );
|
||||
}
|
||||
|
||||
bool UdpSocket::IsBound() const
|
||||
{
|
||||
return impl_->IsBound();
|
||||
}
|
||||
|
||||
int UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size )
|
||||
{
|
||||
return impl_->ReceiveFrom( remoteEndpoint, data, size );
|
||||
}
|
||||
|
||||
|
||||
struct AttachedTimerListener{
|
||||
AttachedTimerListener( int id, int p, TimerListener *tl )
|
||||
: initialDelayMs( id )
|
||||
, periodMs( p )
|
||||
, listener( tl ) {}
|
||||
int initialDelayMs;
|
||||
int periodMs;
|
||||
TimerListener *listener;
|
||||
};
|
||||
|
||||
|
||||
static bool CompareScheduledTimerCalls(
|
||||
const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs )
|
||||
{
|
||||
return lhs.first < rhs.first;
|
||||
}
|
||||
|
||||
|
||||
SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0;
|
||||
|
||||
extern "C" /*static*/ void InterruptSignalHandler( int );
|
||||
/*static*/ void InterruptSignalHandler( int )
|
||||
{
|
||||
multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak();
|
||||
#ifndef WINCE
|
||||
signal( SIGINT, SIG_DFL );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
class SocketReceiveMultiplexer::Implementation{
|
||||
NetworkInitializer networkInitializer_;
|
||||
|
||||
std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_;
|
||||
std::vector< AttachedTimerListener > timerListeners_;
|
||||
|
||||
volatile bool break_;
|
||||
HANDLE breakEvent_;
|
||||
|
||||
double GetCurrentTimeMs() const
|
||||
{
|
||||
#ifndef WINCE
|
||||
return timeGetTime(); // FIXME: bad choice if you want to run for more than 40 days
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
Implementation()
|
||||
{
|
||||
breakEvent_ = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||||
}
|
||||
|
||||
~Implementation()
|
||||
{
|
||||
CloseHandle( breakEvent_ );
|
||||
}
|
||||
|
||||
void AttachSocketListener( UdpSocket *socket, PacketListener *listener )
|
||||
{
|
||||
assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() );
|
||||
// we don't check that the same socket has been added multiple times, even though this is an error
|
||||
socketListeners_.push_back( std::make_pair( listener, socket ) );
|
||||
}
|
||||
|
||||
void DetachSocketListener( UdpSocket *socket, PacketListener *listener )
|
||||
{
|
||||
std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i =
|
||||
std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) );
|
||||
assert( i != socketListeners_.end() );
|
||||
|
||||
socketListeners_.erase( i );
|
||||
}
|
||||
|
||||
void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
|
||||
{
|
||||
timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) );
|
||||
}
|
||||
|
||||
void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
|
||||
{
|
||||
timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) );
|
||||
}
|
||||
|
||||
void DetachPeriodicTimerListener( TimerListener *listener )
|
||||
{
|
||||
std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
|
||||
while( i != timerListeners_.end() ){
|
||||
if( i->listener == listener )
|
||||
break;
|
||||
++i;
|
||||
}
|
||||
|
||||
assert( i != timerListeners_.end() );
|
||||
|
||||
timerListeners_.erase( i );
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
break_ = false;
|
||||
|
||||
// prepare the window events which we use to wake up on incoming data
|
||||
// we use this instead of select() primarily to support the AsyncBreak()
|
||||
// mechanism.
|
||||
|
||||
std::vector<HANDLE> events( socketListeners_.size() + 1, 0 );
|
||||
int j=0;
|
||||
for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
|
||||
i != socketListeners_.end(); ++i, ++j ){
|
||||
|
||||
HANDLE event = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||||
WSAEventSelect( i->second->impl_->Socket(), event, FD_READ ); // note that this makes the socket non-blocking which is why we can safely call RecieveFrom() on all sockets below
|
||||
events[j] = event;
|
||||
}
|
||||
|
||||
|
||||
events[ socketListeners_.size() ] = breakEvent_; // last event in the collection is the break event
|
||||
|
||||
|
||||
// configure the timer queue
|
||||
double currentTimeMs = GetCurrentTimeMs();
|
||||
|
||||
// expiry time ms, listener
|
||||
std::vector< std::pair< double, AttachedTimerListener > > timerQueue_;
|
||||
for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
|
||||
i != timerListeners_.end(); ++i )
|
||||
timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) );
|
||||
std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
|
||||
|
||||
const int MAX_BUFFER_SIZE = 4098;
|
||||
char *data = new char[ MAX_BUFFER_SIZE ];
|
||||
IpEndpointName remoteEndpoint;
|
||||
|
||||
while( !break_ ){
|
||||
|
||||
double currentTimeMs = GetCurrentTimeMs();
|
||||
|
||||
DWORD waitTime = INFINITE;
|
||||
if( !timerQueue_.empty() ){
|
||||
|
||||
waitTime = (DWORD)( timerQueue_.front().first >= currentTimeMs
|
||||
? timerQueue_.front().first - currentTimeMs
|
||||
: 0 );
|
||||
}
|
||||
|
||||
DWORD waitResult = WaitForMultipleObjects( (DWORD)socketListeners_.size() + 1, &events[0], FALSE, waitTime );
|
||||
if( break_ )
|
||||
break;
|
||||
|
||||
if( waitResult != WAIT_TIMEOUT ){
|
||||
for( int i = waitResult - WAIT_OBJECT_0; i < (int)socketListeners_.size(); ++i ){
|
||||
int size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE );
|
||||
if( size > 0 ){
|
||||
socketListeners_[i].first->ProcessPacket( data, size, remoteEndpoint );
|
||||
if( break_ )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// execute any expired timers
|
||||
currentTimeMs = GetCurrentTimeMs();
|
||||
bool resort = false;
|
||||
for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin();
|
||||
i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){
|
||||
|
||||
i->second.listener->TimerExpired();
|
||||
if( break_ )
|
||||
break;
|
||||
|
||||
i->first += i->second.periodMs;
|
||||
resort = true;
|
||||
}
|
||||
if( resort )
|
||||
std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
|
||||
}
|
||||
|
||||
delete [] data;
|
||||
|
||||
// free events
|
||||
j = 0;
|
||||
for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
|
||||
i != socketListeners_.end(); ++i, ++j ){
|
||||
|
||||
WSAEventSelect( i->second->impl_->Socket(), events[j], 0 ); // remove association between socket and event
|
||||
CloseHandle( events[j] );
|
||||
unsigned long enableNonblocking = 0;
|
||||
ioctlsocket( i->second->impl_->Socket(), FIONBIO, &enableNonblocking ); // make the socket blocking again
|
||||
}
|
||||
}
|
||||
|
||||
void Break()
|
||||
{
|
||||
break_ = true;
|
||||
}
|
||||
|
||||
void AsynchronousBreak()
|
||||
{
|
||||
break_ = true;
|
||||
SetEvent( breakEvent_ );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
SocketReceiveMultiplexer::SocketReceiveMultiplexer()
|
||||
{
|
||||
impl_ = new Implementation();
|
||||
}
|
||||
|
||||
SocketReceiveMultiplexer::~SocketReceiveMultiplexer()
|
||||
{
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener )
|
||||
{
|
||||
impl_->AttachSocketListener( socket, listener );
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener )
|
||||
{
|
||||
impl_->DetachSocketListener( socket, listener );
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
|
||||
{
|
||||
impl_->AttachPeriodicTimerListener( periodMilliseconds, listener );
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
|
||||
{
|
||||
impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener );
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener )
|
||||
{
|
||||
impl_->DetachPeriodicTimerListener( listener );
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::Run()
|
||||
{
|
||||
impl_->Run();
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::RunUntilSigInt()
|
||||
{
|
||||
assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */
|
||||
multiplexerInstanceToAbortWithSigInt_ = this;
|
||||
#ifndef WINCE
|
||||
signal( SIGINT, InterruptSignalHandler );
|
||||
#endif
|
||||
impl_->Run();
|
||||
#ifndef WINCE
|
||||
signal( SIGINT, SIG_DFL );
|
||||
#endif
|
||||
multiplexerInstanceToAbortWithSigInt_ = 0;
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::Break()
|
||||
{
|
||||
impl_->Break();
|
||||
}
|
||||
|
||||
void SocketReceiveMultiplexer::AsynchronousBreak()
|
||||
{
|
||||
impl_->AsynchronousBreak();
|
||||
}
|
||||
|
73
src/osgPlugins/osc/osc/MessageMappingOscPacketListener.h
Normal file
73
src/osgPlugins/osc/osc/MessageMappingOscPacketListener.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
|
||||
#define INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
|
||||
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
|
||||
#include "OscPacketListener.h"
|
||||
|
||||
|
||||
|
||||
namespace osc{
|
||||
|
||||
template< class T >
|
||||
class MessageMappingOscPacketListener : public OscPacketListener{
|
||||
public:
|
||||
typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&);
|
||||
|
||||
protected:
|
||||
void RegisterMessageFunction( const char *addressPattern, function_type f )
|
||||
{
|
||||
functions_.insert( std::make_pair( addressPattern, f ) );
|
||||
}
|
||||
|
||||
virtual void ProcessMessage( const osc::ReceivedMessage& m,
|
||||
const IpEndpointName& remoteEndpoint )
|
||||
{
|
||||
typename function_map_type::iterator i = functions_.find( m.AddressPattern() );
|
||||
if( i != functions_.end() )
|
||||
(dynamic_cast<T*>(this)->*(i->second))( m, remoteEndpoint );
|
||||
}
|
||||
|
||||
private:
|
||||
struct cstr_compare{
|
||||
bool operator()( const char *lhs, const char *rhs ) const
|
||||
{ return strcmp( lhs, rhs ) < 0; }
|
||||
};
|
||||
|
||||
typedef std::map<const char*, function_type, cstr_compare> function_map_type;
|
||||
function_map_type functions_;
|
||||
};
|
||||
|
||||
} // namespace osc
|
||||
|
||||
#endif /* INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H */
|
54
src/osgPlugins/osc/osc/OscException.h
Normal file
54
src/osgPlugins/osc/osc/OscException.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_OSC_EXCEPTION_H
|
||||
#define INCLUDED_OSC_EXCEPTION_H
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace osc{
|
||||
|
||||
class Exception : public std::exception {
|
||||
const char *what_;
|
||||
|
||||
public:
|
||||
Exception() throw() {}
|
||||
Exception( const Exception& src ) throw()
|
||||
: what_( src.what_ ) {}
|
||||
Exception( const char *w ) throw()
|
||||
: what_( w ) {}
|
||||
Exception& operator=( const Exception& src ) throw()
|
||||
{ what_ = src.what_; return *this; }
|
||||
virtual ~Exception() throw() {}
|
||||
virtual const char* what() const throw() { return what_; }
|
||||
};
|
||||
|
||||
} // namespace osc
|
||||
|
||||
#endif /* INCLUDED_OSC_EXCEPTION_H */
|
85
src/osgPlugins/osc/osc/OscHostEndianness.h
Normal file
85
src/osgPlugins/osc/osc/OscHostEndianness.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef OSC_HOSTENDIANNESS_H
|
||||
#define OSC_HOSTENDIANNESS_H
|
||||
|
||||
/*
|
||||
Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined
|
||||
|
||||
If you know a way to enhance the detection below for Linux and/or MacOSX
|
||||
please let me know! I've tried a few things which don't work.
|
||||
*/
|
||||
|
||||
#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN)
|
||||
|
||||
// you can define one of the above symbols from the command line
|
||||
// then you don't have to edit this file.
|
||||
|
||||
#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE)
|
||||
|
||||
// assume that __WIN32__ is only defined on little endian systems
|
||||
|
||||
#define OSC_HOST_LITTLE_ENDIAN 1
|
||||
#undef OSC_HOST_BIG_ENDIAN
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
#include <endian.h>
|
||||
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
#define __LITTLE_ENDIAN__
|
||||
#elif (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
#define __BIG_ENDIAN__
|
||||
#else
|
||||
#error Unknown machine endianness detected.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__LITTLE_ENDIAN__)
|
||||
|
||||
#define OSC_HOST_LITTLE_ENDIAN 1
|
||||
#undef OSC_HOST_BIG_ENDIAN
|
||||
|
||||
#elif defined(__BIG_ENDIAN__)
|
||||
|
||||
#define OSC_HOST_BIG_ENDIAN 1
|
||||
#undef OSC_HOST_LITTLE_ENDIAN
|
||||
|
||||
#else
|
||||
|
||||
#error please edit OSCHostEndianness.h to configure endianness
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* OSC_HOSTENDIANNESS_H */
|
||||
|
639
src/osgPlugins/osc/osc/OscOutboundPacketStream.cpp
Normal file
639
src/osgPlugins/osc/osc/OscOutboundPacketStream.cpp
Normal file
@ -0,0 +1,639 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "OscOutboundPacketStream.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(__WIN32__) || defined(WIN32)
|
||||
#include <malloc.h> // for alloca
|
||||
#endif
|
||||
|
||||
#include "OscHostEndianness.h"
|
||||
|
||||
|
||||
namespace osc{
|
||||
|
||||
static void FromInt32( char *p, int32 x )
|
||||
{
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
osc::int32 i;
|
||||
char c[4];
|
||||
} u;
|
||||
|
||||
u.i = x;
|
||||
|
||||
p[3] = u.c[0];
|
||||
p[2] = u.c[1];
|
||||
p[1] = u.c[2];
|
||||
p[0] = u.c[3];
|
||||
#else
|
||||
*reinterpret_cast<int32*>(p) = x;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void FromUInt32( char *p, uint32 x )
|
||||
{
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
osc::uint32 i;
|
||||
char c[4];
|
||||
} u;
|
||||
|
||||
u.i = x;
|
||||
|
||||
p[3] = u.c[0];
|
||||
p[2] = u.c[1];
|
||||
p[1] = u.c[2];
|
||||
p[0] = u.c[3];
|
||||
#else
|
||||
*reinterpret_cast<uint32*>(p) = x;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void FromInt64( char *p, int64 x )
|
||||
{
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
osc::int64 i;
|
||||
char c[8];
|
||||
} u;
|
||||
|
||||
u.i = x;
|
||||
|
||||
p[7] = u.c[0];
|
||||
p[6] = u.c[1];
|
||||
p[5] = u.c[2];
|
||||
p[4] = u.c[3];
|
||||
p[3] = u.c[4];
|
||||
p[2] = u.c[5];
|
||||
p[1] = u.c[6];
|
||||
p[0] = u.c[7];
|
||||
#else
|
||||
*reinterpret_cast<int64*>(p) = x;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void FromUInt64( char *p, uint64 x )
|
||||
{
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
osc::uint64 i;
|
||||
char c[8];
|
||||
} u;
|
||||
|
||||
u.i = x;
|
||||
|
||||
p[7] = u.c[0];
|
||||
p[6] = u.c[1];
|
||||
p[5] = u.c[2];
|
||||
p[4] = u.c[3];
|
||||
p[3] = u.c[4];
|
||||
p[2] = u.c[5];
|
||||
p[1] = u.c[6];
|
||||
p[0] = u.c[7];
|
||||
#else
|
||||
*reinterpret_cast<uint64*>(p) = x;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline long RoundUp4( long x )
|
||||
{
|
||||
return ((x-1) & (~0x03L)) + 4;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream::OutboundPacketStream( char *buffer, unsigned long capacity )
|
||||
: data_( buffer )
|
||||
, end_( data_ + capacity )
|
||||
, typeTagsCurrent_( end_ )
|
||||
, messageCursor_( data_ )
|
||||
, argumentCurrent_( data_ )
|
||||
, elementSizePtr_( 0 )
|
||||
, messageIsInProgress_( false )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream::~OutboundPacketStream()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *OutboundPacketStream::BeginElement( char *beginPtr )
|
||||
{
|
||||
if( elementSizePtr_ == 0 ){
|
||||
|
||||
elementSizePtr_ = reinterpret_cast<uint32*>(data_);
|
||||
|
||||
return beginPtr;
|
||||
|
||||
}else{
|
||||
// store an offset to the old element size ptr in the element size slot
|
||||
// we store an offset rather than the actual pointer to be 64 bit clean.
|
||||
*reinterpret_cast<uint32*>(beginPtr) =
|
||||
(uint32)(reinterpret_cast<char*>(elementSizePtr_) - data_);
|
||||
|
||||
elementSizePtr_ = reinterpret_cast<uint32*>(beginPtr);
|
||||
|
||||
return beginPtr + 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OutboundPacketStream::EndElement( char *endPtr )
|
||||
{
|
||||
assert( elementSizePtr_ != 0 );
|
||||
|
||||
if( elementSizePtr_ == reinterpret_cast<uint32*>(data_) ){
|
||||
|
||||
elementSizePtr_ = 0;
|
||||
|
||||
}else{
|
||||
// while building an element, an offset to the containing element's
|
||||
// size slot is stored in the elements size slot (or a ptr to data_
|
||||
// if there is no containing element). We retrieve that here
|
||||
uint32 *previousElementSizePtr =
|
||||
(uint32*)(data_ + *reinterpret_cast<uint32*>(elementSizePtr_));
|
||||
|
||||
// then we store the element size in the slot, note that the element
|
||||
// size does not include the size slot, hence the - 4 below.
|
||||
uint32 elementSize =
|
||||
(endPtr - reinterpret_cast<char*>(elementSizePtr_)) - 4;
|
||||
FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );
|
||||
|
||||
// finally, we reset the element size ptr to the containing element
|
||||
elementSizePtr_ = previousElementSizePtr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool OutboundPacketStream::ElementSizeSlotRequired() const
|
||||
{
|
||||
return (elementSizePtr_ != 0);
|
||||
}
|
||||
|
||||
|
||||
void OutboundPacketStream::CheckForAvailableBundleSpace()
|
||||
{
|
||||
unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;
|
||||
|
||||
if( required > Capacity() )
|
||||
throw OutOfBufferMemoryException();
|
||||
}
|
||||
|
||||
|
||||
void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern )
|
||||
{
|
||||
// plus 4 for at least four bytes of type tag
|
||||
unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0)
|
||||
+ RoundUp4(strlen(addressPattern) + 1) + 4;
|
||||
|
||||
if( required > Capacity() )
|
||||
throw OutOfBufferMemoryException();
|
||||
}
|
||||
|
||||
|
||||
void OutboundPacketStream::CheckForAvailableArgumentSpace( long argumentLength )
|
||||
{
|
||||
// plus three for extra type tag, comma and null terminator
|
||||
unsigned long required = (argumentCurrent_ - data_) + argumentLength
|
||||
+ RoundUp4( (end_ - typeTagsCurrent_) + 3 );
|
||||
|
||||
if( required > Capacity() )
|
||||
throw OutOfBufferMemoryException();
|
||||
}
|
||||
|
||||
|
||||
void OutboundPacketStream::Clear()
|
||||
{
|
||||
typeTagsCurrent_ = end_;
|
||||
messageCursor_ = data_;
|
||||
argumentCurrent_ = data_;
|
||||
elementSizePtr_ = 0;
|
||||
messageIsInProgress_ = false;
|
||||
}
|
||||
|
||||
|
||||
unsigned int OutboundPacketStream::Capacity() const
|
||||
{
|
||||
return end_ - data_;
|
||||
}
|
||||
|
||||
|
||||
unsigned int OutboundPacketStream::Size() const
|
||||
{
|
||||
unsigned int result = argumentCurrent_ - data_;
|
||||
if( IsMessageInProgress() ){
|
||||
// account for the length of the type tag string. the total type tag
|
||||
// includes an initial comma, plus at least one terminating \0
|
||||
result += RoundUp4( (end_ - typeTagsCurrent_) + 2 );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const char *OutboundPacketStream::Data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
|
||||
bool OutboundPacketStream::IsReady() const
|
||||
{
|
||||
return (!IsMessageInProgress() && !IsBundleInProgress());
|
||||
}
|
||||
|
||||
|
||||
bool OutboundPacketStream::IsMessageInProgress() const
|
||||
{
|
||||
return messageIsInProgress_;
|
||||
}
|
||||
|
||||
|
||||
bool OutboundPacketStream::IsBundleInProgress() const
|
||||
{
|
||||
return (elementSizePtr_ != 0);
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs )
|
||||
{
|
||||
if( IsMessageInProgress() )
|
||||
throw MessageInProgressException();
|
||||
|
||||
CheckForAvailableBundleSpace();
|
||||
|
||||
messageCursor_ = BeginElement( messageCursor_ );
|
||||
|
||||
memcpy( messageCursor_, "#bundle\0", 8 );
|
||||
FromUInt64( messageCursor_ + 8, rhs.timeTag );
|
||||
|
||||
messageCursor_ += 16;
|
||||
argumentCurrent_ = messageCursor_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs )
|
||||
{
|
||||
(void) rhs;
|
||||
|
||||
if( !IsBundleInProgress() )
|
||||
throw BundleNotInProgressException();
|
||||
if( IsMessageInProgress() )
|
||||
throw MessageInProgressException();
|
||||
|
||||
EndElement( messageCursor_ );
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs )
|
||||
{
|
||||
if( IsMessageInProgress() )
|
||||
throw MessageInProgressException();
|
||||
|
||||
CheckForAvailableMessageSpace( rhs.addressPattern );
|
||||
|
||||
messageCursor_ = BeginElement( messageCursor_ );
|
||||
|
||||
strcpy( messageCursor_, rhs.addressPattern );
|
||||
unsigned long rhsLength = strlen(rhs.addressPattern);
|
||||
messageCursor_ += rhsLength + 1;
|
||||
|
||||
// zero pad to 4-byte boundary
|
||||
unsigned long i = rhsLength + 1;
|
||||
while( i & 0x3 ){
|
||||
*messageCursor_++ = '\0';
|
||||
++i;
|
||||
}
|
||||
|
||||
argumentCurrent_ = messageCursor_;
|
||||
typeTagsCurrent_ = end_;
|
||||
|
||||
messageIsInProgress_ = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs )
|
||||
{
|
||||
(void) rhs;
|
||||
|
||||
if( !IsMessageInProgress() )
|
||||
throw MessageNotInProgressException();
|
||||
|
||||
int typeTagsCount = end_ - typeTagsCurrent_;
|
||||
|
||||
if( typeTagsCount ){
|
||||
|
||||
char *tempTypeTags = (char*)alloca(typeTagsCount);
|
||||
memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );
|
||||
|
||||
// slot size includes comma and null terminator
|
||||
int typeTagSlotSize = RoundUp4( typeTagsCount + 2 );
|
||||
|
||||
uint32 argumentsSize = argumentCurrent_ - messageCursor_;
|
||||
|
||||
memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );
|
||||
|
||||
messageCursor_[0] = ',';
|
||||
// copy type tags in reverse (really forward) order
|
||||
for( int i=0; i < typeTagsCount; ++i )
|
||||
messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];
|
||||
|
||||
char *p = messageCursor_ + 1 + typeTagsCount;
|
||||
for( int i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i )
|
||||
*p++ = '\0';
|
||||
|
||||
typeTagsCurrent_ = end_;
|
||||
|
||||
// advance messageCursor_ for next message
|
||||
messageCursor_ += typeTagSlotSize + argumentsSize;
|
||||
|
||||
}else{
|
||||
// send an empty type tags string
|
||||
memcpy( messageCursor_, ",\0\0\0", 4 );
|
||||
|
||||
// advance messageCursor_ for next message
|
||||
messageCursor_ += 4;
|
||||
}
|
||||
|
||||
argumentCurrent_ = messageCursor_;
|
||||
|
||||
EndElement( messageCursor_ );
|
||||
|
||||
messageIsInProgress_ = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace(0);
|
||||
|
||||
*(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs )
|
||||
{
|
||||
(void) rhs;
|
||||
CheckForAvailableArgumentSpace(0);
|
||||
|
||||
*(--typeTagsCurrent_) = NIL_TYPE_TAG;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs )
|
||||
{
|
||||
(void) rhs;
|
||||
CheckForAvailableArgumentSpace(0);
|
||||
|
||||
*(--typeTagsCurrent_) = INFINITUM_TYPE_TAG;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace(4);
|
||||
|
||||
*(--typeTagsCurrent_) = INT32_TYPE_TAG;
|
||||
FromInt32( argumentCurrent_, rhs );
|
||||
argumentCurrent_ += 4;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace(4);
|
||||
|
||||
*(--typeTagsCurrent_) = FLOAT_TYPE_TAG;
|
||||
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
float f;
|
||||
char c[4];
|
||||
} u;
|
||||
|
||||
u.f = rhs;
|
||||
|
||||
argumentCurrent_[3] = u.c[0];
|
||||
argumentCurrent_[2] = u.c[1];
|
||||
argumentCurrent_[1] = u.c[2];
|
||||
argumentCurrent_[0] = u.c[3];
|
||||
#else
|
||||
*reinterpret_cast<float*>(argumentCurrent_) = rhs;
|
||||
#endif
|
||||
|
||||
argumentCurrent_ += 4;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( char rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace(4);
|
||||
|
||||
*(--typeTagsCurrent_) = CHAR_TYPE_TAG;
|
||||
FromInt32( argumentCurrent_, rhs );
|
||||
argumentCurrent_ += 4;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace(4);
|
||||
|
||||
*(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG;
|
||||
FromUInt32( argumentCurrent_, rhs );
|
||||
argumentCurrent_ += 4;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace(4);
|
||||
|
||||
*(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG;
|
||||
FromUInt32( argumentCurrent_, rhs );
|
||||
argumentCurrent_ += 4;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace(8);
|
||||
|
||||
*(--typeTagsCurrent_) = INT64_TYPE_TAG;
|
||||
FromInt64( argumentCurrent_, rhs );
|
||||
argumentCurrent_ += 8;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace(8);
|
||||
|
||||
*(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG;
|
||||
FromUInt64( argumentCurrent_, rhs );
|
||||
argumentCurrent_ += 8;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace(8);
|
||||
|
||||
*(--typeTagsCurrent_) = DOUBLE_TYPE_TAG;
|
||||
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
double f;
|
||||
char c[8];
|
||||
} u;
|
||||
|
||||
u.f = rhs;
|
||||
|
||||
argumentCurrent_[7] = u.c[0];
|
||||
argumentCurrent_[6] = u.c[1];
|
||||
argumentCurrent_[5] = u.c[2];
|
||||
argumentCurrent_[4] = u.c[3];
|
||||
argumentCurrent_[3] = u.c[4];
|
||||
argumentCurrent_[2] = u.c[5];
|
||||
argumentCurrent_[1] = u.c[6];
|
||||
argumentCurrent_[0] = u.c[7];
|
||||
#else
|
||||
*reinterpret_cast<double*>(argumentCurrent_) = rhs;
|
||||
#endif
|
||||
|
||||
argumentCurrent_ += 8;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) );
|
||||
|
||||
*(--typeTagsCurrent_) = STRING_TYPE_TAG;
|
||||
strcpy( argumentCurrent_, rhs );
|
||||
unsigned long rhsLength = strlen(rhs);
|
||||
argumentCurrent_ += rhsLength + 1;
|
||||
|
||||
// zero pad to 4-byte boundary
|
||||
unsigned long i = rhsLength + 1;
|
||||
while( i & 0x3 ){
|
||||
*argumentCurrent_++ = '\0';
|
||||
++i;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) );
|
||||
|
||||
*(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;
|
||||
strcpy( argumentCurrent_, rhs );
|
||||
unsigned long rhsLength = strlen(rhs);
|
||||
argumentCurrent_ += rhsLength + 1;
|
||||
|
||||
// zero pad to 4-byte boundary
|
||||
unsigned long i = rhsLength + 1;
|
||||
while( i & 0x3 ){
|
||||
*argumentCurrent_++ = '\0';
|
||||
++i;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
|
||||
{
|
||||
CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) );
|
||||
|
||||
*(--typeTagsCurrent_) = BLOB_TYPE_TAG;
|
||||
FromUInt32( argumentCurrent_, rhs.size );
|
||||
argumentCurrent_ += 4;
|
||||
|
||||
memcpy( argumentCurrent_, rhs.data, rhs.size );
|
||||
argumentCurrent_ += rhs.size;
|
||||
|
||||
// zero pad to 4-byte boundary
|
||||
unsigned long i = rhs.size;
|
||||
while( i & 0x3 ){
|
||||
*argumentCurrent_++ = '\0';
|
||||
++i;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace osc
|
||||
|
||||
|
142
src/osgPlugins/osc/osc/OscOutboundPacketStream.h
Normal file
142
src/osgPlugins/osc/osc/OscOutboundPacketStream.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_OSCOUTBOUNDPACKET_H
|
||||
#define INCLUDED_OSCOUTBOUNDPACKET_H
|
||||
|
||||
#include "OscTypes.h"
|
||||
#include "OscException.h"
|
||||
|
||||
|
||||
namespace osc{
|
||||
|
||||
class OutOfBufferMemoryException : public Exception{
|
||||
public:
|
||||
OutOfBufferMemoryException( const char *w="out of buffer memory" )
|
||||
: Exception( w ) {}
|
||||
};
|
||||
|
||||
class BundleNotInProgressException : public Exception{
|
||||
public:
|
||||
BundleNotInProgressException(
|
||||
const char *w="call to EndBundle when bundle is not in progress" )
|
||||
: Exception( w ) {}
|
||||
};
|
||||
|
||||
class MessageInProgressException : public Exception{
|
||||
public:
|
||||
MessageInProgressException(
|
||||
const char *w="opening or closing bundle or message while message is in progress" )
|
||||
: Exception( w ) {}
|
||||
};
|
||||
|
||||
class MessageNotInProgressException : public Exception{
|
||||
public:
|
||||
MessageNotInProgressException(
|
||||
const char *w="call to EndMessage when message is not in progress" )
|
||||
: Exception( w ) {}
|
||||
};
|
||||
|
||||
|
||||
class OutboundPacketStream{
|
||||
public:
|
||||
OutboundPacketStream( char *buffer, unsigned long capacity );
|
||||
~OutboundPacketStream();
|
||||
|
||||
void Clear();
|
||||
|
||||
unsigned int Capacity() const;
|
||||
|
||||
// invariant: size() is valid even while building a message.
|
||||
unsigned int Size() const;
|
||||
|
||||
const char *Data() const;
|
||||
|
||||
// indicates that all messages have been closed with a matching EndMessage
|
||||
// and all bundles have been closed with a matching EndBundle
|
||||
bool IsReady() const;
|
||||
|
||||
bool IsMessageInProgress() const;
|
||||
bool IsBundleInProgress() const;
|
||||
|
||||
OutboundPacketStream& operator<<( const BundleInitiator& rhs );
|
||||
OutboundPacketStream& operator<<( const BundleTerminator& rhs );
|
||||
|
||||
OutboundPacketStream& operator<<( const BeginMessage& rhs );
|
||||
OutboundPacketStream& operator<<( const MessageTerminator& rhs );
|
||||
|
||||
OutboundPacketStream& operator<<( bool rhs );
|
||||
OutboundPacketStream& operator<<( const NilType& rhs );
|
||||
OutboundPacketStream& operator<<( const InfinitumType& rhs );
|
||||
OutboundPacketStream& operator<<( int32 rhs );
|
||||
|
||||
#ifndef __x86_64__
|
||||
OutboundPacketStream& operator<<( int rhs )
|
||||
{ *this << (int32)rhs; return *this; }
|
||||
#endif
|
||||
|
||||
OutboundPacketStream& operator<<( float rhs );
|
||||
OutboundPacketStream& operator<<( char rhs );
|
||||
OutboundPacketStream& operator<<( const RgbaColor& rhs );
|
||||
OutboundPacketStream& operator<<( const MidiMessage& rhs );
|
||||
OutboundPacketStream& operator<<( int64 rhs );
|
||||
OutboundPacketStream& operator<<( const TimeTag& rhs );
|
||||
OutboundPacketStream& operator<<( double rhs );
|
||||
OutboundPacketStream& operator<<( const char* rhs );
|
||||
OutboundPacketStream& operator<<( const Symbol& rhs );
|
||||
OutboundPacketStream& operator<<( const Blob& rhs );
|
||||
|
||||
private:
|
||||
|
||||
char *BeginElement( char *beginPtr );
|
||||
void EndElement( char *endPtr );
|
||||
|
||||
bool ElementSizeSlotRequired() const;
|
||||
void CheckForAvailableBundleSpace();
|
||||
void CheckForAvailableMessageSpace( const char *addressPattern );
|
||||
void CheckForAvailableArgumentSpace( long argumentLength );
|
||||
|
||||
char *data_;
|
||||
char *end_;
|
||||
|
||||
char *typeTagsCurrent_; // stored in reverse order
|
||||
char *messageCursor_;
|
||||
char *argumentCurrent_;
|
||||
|
||||
// elementSizePtr_ has two special values: 0 indicates that a bundle
|
||||
// isn't open, and elementSizePtr_==data_ indicates that a bundle is
|
||||
// open but that it doesn't have a size slot (ie the outermost bundle)
|
||||
uint32 *elementSizePtr_;
|
||||
|
||||
bool messageIsInProgress_;
|
||||
};
|
||||
|
||||
} // namespace osc
|
||||
|
||||
#endif /* INCLUDED_OSC_OUTBOUND_PACKET_H */
|
72
src/osgPlugins/osc/osc/OscPacketListener.h
Normal file
72
src/osgPlugins/osc/osc/OscPacketListener.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_OSCPACKETLISTENER_H
|
||||
#define INCLUDED_OSCPACKETLISTENER_H
|
||||
|
||||
#include "OscReceivedElements.h"
|
||||
#include "../ip/PacketListener.h"
|
||||
|
||||
|
||||
namespace osc{
|
||||
|
||||
class OscPacketListener : public PacketListener{
|
||||
protected:
|
||||
virtual void ProcessBundle( const osc::ReceivedBundle& b,
|
||||
const IpEndpointName& remoteEndpoint )
|
||||
{
|
||||
// ignore bundle time tag for now
|
||||
|
||||
for( ReceivedBundle::const_iterator i = b.ElementsBegin();
|
||||
i != b.ElementsEnd(); ++i ){
|
||||
if( i->IsBundle() )
|
||||
ProcessBundle( ReceivedBundle(*i), remoteEndpoint );
|
||||
else
|
||||
ProcessMessage( ReceivedMessage(*i), remoteEndpoint );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void ProcessMessage( const osc::ReceivedMessage& m,
|
||||
const IpEndpointName& remoteEndpoint ) = 0;
|
||||
|
||||
public:
|
||||
virtual void ProcessPacket( const char *data, int size,
|
||||
const IpEndpointName& remoteEndpoint )
|
||||
{
|
||||
osc::ReceivedPacket p( data, size );
|
||||
if( p.IsBundle() )
|
||||
ProcessBundle( ReceivedBundle(p), remoteEndpoint );
|
||||
else
|
||||
ProcessMessage( ReceivedMessage(p), remoteEndpoint );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace osc
|
||||
|
||||
#endif /* INCLUDED_OSCPACKETLISTENER_H */
|
244
src/osgPlugins/osc/osc/OscPrintReceivedElements.cpp
Normal file
244
src/osgPlugins/osc/osc/OscPrintReceivedElements.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "OscPrintReceivedElements.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <ctime>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace osc{
|
||||
|
||||
|
||||
std::ostream& operator<<( std::ostream & os,
|
||||
const ReceivedMessageArgument& arg )
|
||||
{
|
||||
switch( arg.TypeTag() ){
|
||||
case TRUE_TYPE_TAG:
|
||||
os << "bool:true";
|
||||
break;
|
||||
|
||||
case FALSE_TYPE_TAG:
|
||||
os << "bool:false";
|
||||
break;
|
||||
|
||||
case NIL_TYPE_TAG:
|
||||
os << "(Nil)";
|
||||
break;
|
||||
|
||||
case INFINITUM_TYPE_TAG:
|
||||
os << "(Infinitum)";
|
||||
break;
|
||||
|
||||
case INT32_TYPE_TAG:
|
||||
os << "int32:" << arg.AsInt32Unchecked();
|
||||
break;
|
||||
|
||||
case FLOAT_TYPE_TAG:
|
||||
os << "float32:" << arg.AsFloatUnchecked();
|
||||
break;
|
||||
|
||||
case CHAR_TYPE_TAG:
|
||||
{
|
||||
char s[2] = {0};
|
||||
s[0] = arg.AsCharUnchecked();
|
||||
os << "char:'" << s << "'";
|
||||
}
|
||||
break;
|
||||
|
||||
case RGBA_COLOR_TYPE_TAG:
|
||||
{
|
||||
uint32 color = arg.AsRgbaColorUnchecked();
|
||||
|
||||
os << "RGBA:0x"
|
||||
<< std::hex << std::setfill('0')
|
||||
<< std::setw(2) << (int)((color>>24) & 0xFF)
|
||||
<< std::setw(2) << (int)((color>>16) & 0xFF)
|
||||
<< std::setw(2) << (int)((color>>8) & 0xFF)
|
||||
<< std::setw(2) << (int)(color & 0xFF)
|
||||
<< std::setfill(' ');
|
||||
os.unsetf(std::ios::basefield);
|
||||
}
|
||||
break;
|
||||
|
||||
case MIDI_MESSAGE_TYPE_TAG:
|
||||
{
|
||||
uint32 m = arg.AsMidiMessageUnchecked();
|
||||
os << "midi (port, status, data1, data2):<<"
|
||||
<< std::hex << std::setfill('0')
|
||||
<< "0x" << std::setw(2) << (int)((m>>24) & 0xFF)
|
||||
<< " 0x" << std::setw(2) << (int)((m>>16) & 0xFF)
|
||||
<< " 0x" << std::setw(2) << (int)((m>>8) & 0xFF)
|
||||
<< " 0x" << std::setw(2) << (int)(m & 0xFF)
|
||||
<< std::setfill(' ') << ">>";
|
||||
os.unsetf(std::ios::basefield);
|
||||
}
|
||||
break;
|
||||
|
||||
case INT64_TYPE_TAG:
|
||||
os << "int64:" << arg.AsInt64Unchecked();
|
||||
break;
|
||||
|
||||
case TIME_TAG_TYPE_TAG:
|
||||
{
|
||||
os << "OSC-timetag:" << arg.AsTimeTagUnchecked();
|
||||
|
||||
std::time_t t =
|
||||
(unsigned long)( arg.AsTimeTagUnchecked() >> 32 );
|
||||
|
||||
// strip trailing newline from string returned by ctime
|
||||
const char *timeString = std::ctime( &t );
|
||||
size_t len = strlen( timeString );
|
||||
char *s = new char[ len + 1 ];
|
||||
strcpy( s, timeString );
|
||||
if( len )
|
||||
s[ len - 1 ] = '\0';
|
||||
|
||||
os << " " << s;
|
||||
}
|
||||
break;
|
||||
|
||||
case DOUBLE_TYPE_TAG:
|
||||
os << "double:" << arg.AsDoubleUnchecked();
|
||||
break;
|
||||
|
||||
case STRING_TYPE_TAG:
|
||||
os << "OSC-string:`" << arg.AsStringUnchecked() << "'";
|
||||
break;
|
||||
|
||||
case SYMBOL_TYPE_TAG:
|
||||
os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'";
|
||||
break;
|
||||
|
||||
case BLOB_TYPE_TAG:
|
||||
{
|
||||
unsigned long size;
|
||||
const void *data;
|
||||
arg.AsBlobUnchecked( data, size );
|
||||
os << "OSC-blob:<<" << std::hex << std::setfill('0');
|
||||
unsigned char *p = (unsigned char*)data;
|
||||
for( unsigned long i = 0; i < size; ++i ){
|
||||
os << "0x" << std::setw(2) << int(p[i]);
|
||||
if( i != size-1 )
|
||||
os << ' ';
|
||||
}
|
||||
os.unsetf(std::ios::basefield);
|
||||
os << ">>" << std::setfill(' ');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
os << "unknown";
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m )
|
||||
{
|
||||
os << "[";
|
||||
if( m.AddressPatternIsUInt32() )
|
||||
os << m.AddressPatternAsUInt32();
|
||||
else
|
||||
os << m.AddressPattern();
|
||||
|
||||
bool first = true;
|
||||
for( ReceivedMessage::const_iterator i = m.ArgumentsBegin();
|
||||
i != m.ArgumentsEnd(); ++i ){
|
||||
if( first ){
|
||||
os << " ";
|
||||
first = false;
|
||||
}else{
|
||||
os << ", ";
|
||||
}
|
||||
|
||||
os << *i;
|
||||
}
|
||||
|
||||
os << "]";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b )
|
||||
{
|
||||
static int indent = 0;
|
||||
|
||||
for( int j=0; j < indent; ++j )
|
||||
os << " ";
|
||||
os << "{ ( ";
|
||||
if( b.TimeTag() == 1 )
|
||||
os << "immediate";
|
||||
else
|
||||
os << b.TimeTag();
|
||||
os << " )\n";
|
||||
|
||||
++indent;
|
||||
|
||||
for( ReceivedBundle::const_iterator i = b.ElementsBegin();
|
||||
i != b.ElementsEnd(); ++i ){
|
||||
if( i->IsBundle() ){
|
||||
ReceivedBundle b(*i);
|
||||
os << b << "\n";
|
||||
}else{
|
||||
ReceivedMessage m(*i);
|
||||
for( int j=0; j < indent; ++j )
|
||||
os << " ";
|
||||
os << m << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
--indent;
|
||||
|
||||
for( int j=0; j < indent; ++j )
|
||||
os << " ";
|
||||
os << "}";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p )
|
||||
{
|
||||
if( p.IsBundle() ){
|
||||
ReceivedBundle b(p);
|
||||
os << b << "\n";
|
||||
}else{
|
||||
ReceivedMessage m(p);
|
||||
os << m << "\n";
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace osc
|
49
src/osgPlugins/osc/osc/OscPrintReceivedElements.h
Normal file
49
src/osgPlugins/osc/osc/OscPrintReceivedElements.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
|
||||
#define INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
|
||||
#include "OscReceivedElements.h"
|
||||
#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
|
||||
|
||||
|
||||
namespace osc{
|
||||
|
||||
std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p );
|
||||
std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg );
|
||||
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m );
|
||||
std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b );
|
||||
|
||||
} // namespace osc
|
||||
|
||||
#endif /* INCLUDED_OSCPRINTRECEIVEDELEMENTS_H */
|
722
src/osgPlugins/osc/osc/OscReceivedElements.cpp
Normal file
722
src/osgPlugins/osc/osc/OscReceivedElements.cpp
Normal file
@ -0,0 +1,722 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "OscReceivedElements.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "OscHostEndianness.h"
|
||||
|
||||
|
||||
namespace osc{
|
||||
|
||||
|
||||
// return the first 4 byte boundary after the end of a str4
|
||||
// be careful about calling this version if you don't know whether
|
||||
// the string is terminated correctly.
|
||||
static inline const char* FindStr4End( const char *p )
|
||||
{
|
||||
if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
|
||||
return p + 4;
|
||||
|
||||
p += 3;
|
||||
|
||||
while( *p )
|
||||
p += 4;
|
||||
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
|
||||
// return the first 4 byte boundary after the end of a str4
|
||||
// returns 0 if p == end or if the string is unterminated
|
||||
static inline const char* FindStr4End( const char *p, const char *end )
|
||||
{
|
||||
if( p >= end )
|
||||
return 0;
|
||||
|
||||
if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
|
||||
return p + 4;
|
||||
|
||||
p += 3;
|
||||
end -= 1;
|
||||
|
||||
while( p < end && *p )
|
||||
p += 4;
|
||||
|
||||
if( *p )
|
||||
return 0;
|
||||
else
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
|
||||
static inline unsigned long RoundUp4( unsigned long x )
|
||||
{
|
||||
unsigned long remainder = x & 0x3UL;
|
||||
if( remainder )
|
||||
return x + (4 - remainder);
|
||||
else
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
static inline int32 ToInt32( const char *p )
|
||||
{
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
osc::int32 i;
|
||||
char c[4];
|
||||
} u;
|
||||
|
||||
u.c[0] = p[3];
|
||||
u.c[1] = p[2];
|
||||
u.c[2] = p[1];
|
||||
u.c[3] = p[0];
|
||||
|
||||
return u.i;
|
||||
#else
|
||||
return *(int32*)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline uint32 ToUInt32( const char *p )
|
||||
{
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
osc::uint32 i;
|
||||
char c[4];
|
||||
} u;
|
||||
|
||||
u.c[0] = p[3];
|
||||
u.c[1] = p[2];
|
||||
u.c[2] = p[1];
|
||||
u.c[3] = p[0];
|
||||
|
||||
return u.i;
|
||||
#else
|
||||
return *(uint32*)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int64 ToInt64( const char *p )
|
||||
{
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
osc::int64 i;
|
||||
char c[8];
|
||||
} u;
|
||||
|
||||
u.c[0] = p[7];
|
||||
u.c[1] = p[6];
|
||||
u.c[2] = p[5];
|
||||
u.c[3] = p[4];
|
||||
u.c[4] = p[3];
|
||||
u.c[5] = p[2];
|
||||
u.c[6] = p[1];
|
||||
u.c[7] = p[0];
|
||||
|
||||
return u.i;
|
||||
#else
|
||||
return *(int64*)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint64 ToUInt64( const char *p )
|
||||
{
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
osc::uint64 i;
|
||||
char c[8];
|
||||
} u;
|
||||
|
||||
u.c[0] = p[7];
|
||||
u.c[1] = p[6];
|
||||
u.c[2] = p[5];
|
||||
u.c[3] = p[4];
|
||||
u.c[4] = p[3];
|
||||
u.c[5] = p[2];
|
||||
u.c[6] = p[1];
|
||||
u.c[7] = p[0];
|
||||
|
||||
return u.i;
|
||||
#else
|
||||
return *(uint64*)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool ReceivedPacket::IsBundle() const
|
||||
{
|
||||
return (Size() > 0 && Contents()[0] == '#');
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool ReceivedBundleElement::IsBundle() const
|
||||
{
|
||||
return (Size() > 0 && Contents()[0] == '#');
|
||||
}
|
||||
|
||||
|
||||
int32 ReceivedBundleElement::Size() const
|
||||
{
|
||||
return ToUInt32( size_ );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool ReceivedMessageArgument::AsBool() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == TRUE_TYPE_TAG )
|
||||
return true;
|
||||
else if( *typeTag_ == FALSE_TYPE_TAG )
|
||||
return false;
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
bool ReceivedMessageArgument::AsBoolUnchecked() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == TRUE_TYPE_TAG )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int32 ReceivedMessageArgument::AsInt32() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == INT32_TYPE_TAG )
|
||||
return AsInt32Unchecked();
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
int32 ReceivedMessageArgument::AsInt32Unchecked() const
|
||||
{
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
osc::int32 i;
|
||||
char c[4];
|
||||
} u;
|
||||
|
||||
u.c[0] = argument_[3];
|
||||
u.c[1] = argument_[2];
|
||||
u.c[2] = argument_[1];
|
||||
u.c[3] = argument_[0];
|
||||
|
||||
return u.i;
|
||||
#else
|
||||
return *(int32*)argument_;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
float ReceivedMessageArgument::AsFloat() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == FLOAT_TYPE_TAG )
|
||||
return AsFloatUnchecked();
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
float ReceivedMessageArgument::AsFloatUnchecked() const
|
||||
{
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
float f;
|
||||
char c[4];
|
||||
} u;
|
||||
|
||||
u.c[0] = argument_[3];
|
||||
u.c[1] = argument_[2];
|
||||
u.c[2] = argument_[1];
|
||||
u.c[3] = argument_[0];
|
||||
|
||||
return u.f;
|
||||
#else
|
||||
return *(float*)argument_;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
char ReceivedMessageArgument::AsChar() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == CHAR_TYPE_TAG )
|
||||
return AsCharUnchecked();
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
char ReceivedMessageArgument::AsCharUnchecked() const
|
||||
{
|
||||
return (char)ToInt32( argument_ );
|
||||
}
|
||||
|
||||
|
||||
uint32 ReceivedMessageArgument::AsRgbaColor() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == RGBA_COLOR_TYPE_TAG )
|
||||
return AsRgbaColorUnchecked();
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
|
||||
{
|
||||
return ToUInt32( argument_ );
|
||||
}
|
||||
|
||||
|
||||
uint32 ReceivedMessageArgument::AsMidiMessage() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG )
|
||||
return AsMidiMessageUnchecked();
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
|
||||
{
|
||||
return ToUInt32( argument_ );
|
||||
}
|
||||
|
||||
|
||||
int64 ReceivedMessageArgument::AsInt64() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == INT64_TYPE_TAG )
|
||||
return AsInt64Unchecked();
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
int64 ReceivedMessageArgument::AsInt64Unchecked() const
|
||||
{
|
||||
return ToInt64( argument_ );
|
||||
}
|
||||
|
||||
|
||||
uint64 ReceivedMessageArgument::AsTimeTag() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == TIME_TAG_TYPE_TAG )
|
||||
return AsTimeTagUnchecked();
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
|
||||
{
|
||||
return ToUInt64( argument_ );
|
||||
}
|
||||
|
||||
|
||||
double ReceivedMessageArgument::AsDouble() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == DOUBLE_TYPE_TAG )
|
||||
return AsDoubleUnchecked();
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
double ReceivedMessageArgument::AsDoubleUnchecked() const
|
||||
{
|
||||
#ifdef OSC_HOST_LITTLE_ENDIAN
|
||||
union{
|
||||
double d;
|
||||
char c[8];
|
||||
} u;
|
||||
|
||||
u.c[0] = argument_[7];
|
||||
u.c[1] = argument_[6];
|
||||
u.c[2] = argument_[5];
|
||||
u.c[3] = argument_[4];
|
||||
u.c[4] = argument_[3];
|
||||
u.c[5] = argument_[2];
|
||||
u.c[6] = argument_[1];
|
||||
u.c[7] = argument_[0];
|
||||
|
||||
return u.d;
|
||||
#else
|
||||
return *(double*)argument_;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const char* ReceivedMessageArgument::AsString() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == STRING_TYPE_TAG )
|
||||
return argument_;
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
const char* ReceivedMessageArgument::AsSymbol() const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == SYMBOL_TYPE_TAG )
|
||||
return argument_;
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const
|
||||
{
|
||||
if( !typeTag_ )
|
||||
throw MissingArgumentException();
|
||||
else if( *typeTag_ == BLOB_TYPE_TAG )
|
||||
AsBlobUnchecked( data, size );
|
||||
else
|
||||
throw WrongArgumentTypeException();
|
||||
}
|
||||
|
||||
|
||||
void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const
|
||||
{
|
||||
size = ToUInt32( argument_ );
|
||||
data = (void*)(argument_+4);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void ReceivedMessageArgumentIterator::Advance()
|
||||
{
|
||||
if( !value_.typeTag_ )
|
||||
return;
|
||||
|
||||
switch( *value_.typeTag_++ ){
|
||||
case '\0':
|
||||
// don't advance past end
|
||||
--value_.typeTag_;
|
||||
break;
|
||||
|
||||
case TRUE_TYPE_TAG:
|
||||
case FALSE_TYPE_TAG:
|
||||
case NIL_TYPE_TAG:
|
||||
case INFINITUM_TYPE_TAG:
|
||||
|
||||
// zero length
|
||||
break;
|
||||
|
||||
case INT32_TYPE_TAG:
|
||||
case FLOAT_TYPE_TAG:
|
||||
case CHAR_TYPE_TAG:
|
||||
case RGBA_COLOR_TYPE_TAG:
|
||||
case MIDI_MESSAGE_TYPE_TAG:
|
||||
|
||||
value_.argument_ += 4;
|
||||
break;
|
||||
|
||||
case INT64_TYPE_TAG:
|
||||
case TIME_TAG_TYPE_TAG:
|
||||
case DOUBLE_TYPE_TAG:
|
||||
|
||||
value_.argument_ += 8;
|
||||
break;
|
||||
|
||||
case STRING_TYPE_TAG:
|
||||
case SYMBOL_TYPE_TAG:
|
||||
|
||||
// we use the unsafe function FindStr4End(char*) here because all of
|
||||
// the arguments have already been validated in
|
||||
// ReceivedMessage::Init() below.
|
||||
|
||||
value_.argument_ = FindStr4End( value_.argument_ );
|
||||
break;
|
||||
|
||||
case BLOB_TYPE_TAG:
|
||||
{
|
||||
uint32 blobSize = ToUInt32( value_.argument_ );
|
||||
value_.argument_ = value_.argument_ + 4 + RoundUp4( (unsigned long)blobSize );
|
||||
}
|
||||
break;
|
||||
|
||||
default: // unknown type tag
|
||||
// don't advance
|
||||
--value_.typeTag_;
|
||||
break;
|
||||
|
||||
|
||||
// not handled:
|
||||
// [ Indicates the beginning of an array. The tags following are for
|
||||
// data in the Array until a close brace tag is reached.
|
||||
// ] Indicates the end of an array.
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet )
|
||||
: addressPattern_( packet.Contents() )
|
||||
{
|
||||
Init( packet.Contents(), packet.Size() );
|
||||
}
|
||||
|
||||
|
||||
ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )
|
||||
: addressPattern_( bundleElement.Contents() )
|
||||
{
|
||||
Init( bundleElement.Contents(), bundleElement.Size() );
|
||||
}
|
||||
|
||||
|
||||
bool ReceivedMessage::AddressPatternIsUInt32() const
|
||||
{
|
||||
return (addressPattern_[0] == '\0');
|
||||
}
|
||||
|
||||
|
||||
uint32 ReceivedMessage::AddressPatternAsUInt32() const
|
||||
{
|
||||
return ToUInt32( addressPattern_ );
|
||||
}
|
||||
|
||||
|
||||
void ReceivedMessage::Init( const char *message, unsigned long size )
|
||||
{
|
||||
if( size == 0 )
|
||||
throw MalformedMessageException( "zero length messages not permitted" );
|
||||
|
||||
if( (size & 0x03L) != 0 )
|
||||
throw MalformedMessageException( "message size must be multiple of four" );
|
||||
|
||||
const char *end = message + size;
|
||||
|
||||
typeTagsBegin_ = FindStr4End( addressPattern_, end );
|
||||
if( typeTagsBegin_ == 0 ){
|
||||
// address pattern was not terminated before end
|
||||
throw MalformedMessageException( "unterminated address pattern" );
|
||||
}
|
||||
|
||||
if( typeTagsBegin_ == end ){
|
||||
// message consists of only the address pattern - no arguments or type tags.
|
||||
typeTagsBegin_ = 0;
|
||||
typeTagsEnd_ = 0;
|
||||
arguments_ = 0;
|
||||
|
||||
}else{
|
||||
if( *typeTagsBegin_ != ',' )
|
||||
throw MalformedMessageException( "type tags not present" );
|
||||
|
||||
if( *(typeTagsBegin_ + 1) == '\0' ){
|
||||
// zero length type tags
|
||||
typeTagsBegin_ = 0;
|
||||
typeTagsEnd_ = 0;
|
||||
arguments_ = 0;
|
||||
|
||||
}else{
|
||||
// check that all arguments are present and well formed
|
||||
|
||||
arguments_ = FindStr4End( typeTagsBegin_, end );
|
||||
if( arguments_ == 0 ){
|
||||
throw MalformedMessageException( "type tags were not terminated before end of message" );
|
||||
}
|
||||
|
||||
++typeTagsBegin_; // advance past initial ','
|
||||
|
||||
const char *typeTag = typeTagsBegin_;
|
||||
const char *argument = arguments_;
|
||||
|
||||
do{
|
||||
switch( *typeTag ){
|
||||
case TRUE_TYPE_TAG:
|
||||
case FALSE_TYPE_TAG:
|
||||
case NIL_TYPE_TAG:
|
||||
case INFINITUM_TYPE_TAG:
|
||||
|
||||
// zero length
|
||||
break;
|
||||
|
||||
case INT32_TYPE_TAG:
|
||||
case FLOAT_TYPE_TAG:
|
||||
case CHAR_TYPE_TAG:
|
||||
case RGBA_COLOR_TYPE_TAG:
|
||||
case MIDI_MESSAGE_TYPE_TAG:
|
||||
|
||||
if( argument == end )
|
||||
throw MalformedMessageException( "arguments exceed message size" );
|
||||
argument += 4;
|
||||
if( argument > end )
|
||||
throw MalformedMessageException( "arguments exceed message size" );
|
||||
break;
|
||||
|
||||
case INT64_TYPE_TAG:
|
||||
case TIME_TAG_TYPE_TAG:
|
||||
case DOUBLE_TYPE_TAG:
|
||||
|
||||
if( argument == end )
|
||||
throw MalformedMessageException( "arguments exceed message size" );
|
||||
argument += 8;
|
||||
if( argument > end )
|
||||
throw MalformedMessageException( "arguments exceed message size" );
|
||||
break;
|
||||
|
||||
case STRING_TYPE_TAG:
|
||||
case SYMBOL_TYPE_TAG:
|
||||
|
||||
if( argument == end )
|
||||
throw MalformedMessageException( "arguments exceed message size" );
|
||||
argument = FindStr4End( argument, end );
|
||||
if( argument == 0 )
|
||||
throw MalformedMessageException( "unterminated string argument" );
|
||||
break;
|
||||
|
||||
case BLOB_TYPE_TAG:
|
||||
{
|
||||
if( argument + 4 > end )
|
||||
MalformedMessageException( "arguments exceed message size" );
|
||||
|
||||
uint32 blobSize = ToUInt32( argument );
|
||||
argument = argument + 4 + RoundUp4( (unsigned long)blobSize );
|
||||
if( argument > end )
|
||||
MalformedMessageException( "arguments exceed message size" );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw MalformedMessageException( "unknown type tag" );
|
||||
|
||||
// not handled:
|
||||
// [ Indicates the beginning of an array. The tags following are for
|
||||
// data in the Array until a close brace tag is reached.
|
||||
// ] Indicates the end of an array.
|
||||
}
|
||||
|
||||
}while( *++typeTag != '\0' );
|
||||
typeTagsEnd_ = typeTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet )
|
||||
: elementCount_( 0 )
|
||||
{
|
||||
Init( packet.Contents(), packet.Size() );
|
||||
}
|
||||
|
||||
|
||||
ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )
|
||||
: elementCount_( 0 )
|
||||
{
|
||||
Init( bundleElement.Contents(), bundleElement.Size() );
|
||||
}
|
||||
|
||||
|
||||
void ReceivedBundle::Init( const char *bundle, unsigned long size )
|
||||
{
|
||||
if( size < 16 )
|
||||
throw MalformedBundleException( "packet too short for bundle" );
|
||||
|
||||
if( (size & 0x03L) != 0 )
|
||||
throw MalformedBundleException( "bundle size must be multiple of four" );
|
||||
|
||||
if( bundle[0] != '#'
|
||||
|| bundle[1] != 'b'
|
||||
|| bundle[2] != 'u'
|
||||
|| bundle[3] != 'n'
|
||||
|| bundle[4] != 'd'
|
||||
|| bundle[5] != 'l'
|
||||
|| bundle[6] != 'e'
|
||||
|| bundle[7] != '\0' )
|
||||
throw MalformedBundleException( "bad bundle address pattern" );
|
||||
|
||||
end_ = bundle + size;
|
||||
|
||||
timeTag_ = bundle + 8;
|
||||
|
||||
const char *p = timeTag_ + 8;
|
||||
|
||||
while( p < end_ ){
|
||||
if( p + 4 > end_ )
|
||||
throw MalformedBundleException( "packet too short for elementSize" );
|
||||
|
||||
uint32 elementSize = ToUInt32( p );
|
||||
if( (elementSize & 0x03L) != 0 )
|
||||
throw MalformedBundleException( "bundle element size must be multiple of four" );
|
||||
|
||||
p += 4 + elementSize;
|
||||
if( p > end_ )
|
||||
throw MalformedBundleException( "packet too short for bundle element" );
|
||||
|
||||
++elementCount_;
|
||||
}
|
||||
|
||||
if( p != end_ )
|
||||
throw MalformedBundleException( "bundle contents " );
|
||||
}
|
||||
|
||||
|
||||
uint64 ReceivedBundle::TimeTag() const
|
||||
{
|
||||
return ToUInt64( timeTag_ );
|
||||
}
|
||||
|
||||
|
||||
} // namespace osc
|
||||
|
488
src/osgPlugins/osc/osc/OscReceivedElements.h
Normal file
488
src/osgPlugins/osc/osc/OscReceivedElements.h
Normal file
@ -0,0 +1,488 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
|
||||
#define INCLUDED_OSCRECEIVEDELEMENTS_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "OscTypes.h"
|
||||
#include "OscException.h"
|
||||
|
||||
|
||||
namespace osc{
|
||||
|
||||
|
||||
class MalformedMessageException : public Exception{
|
||||
public:
|
||||
MalformedMessageException( const char *w="malformed message" )
|
||||
: Exception( w ) {}
|
||||
};
|
||||
|
||||
class MalformedBundleException : public Exception{
|
||||
public:
|
||||
MalformedBundleException( const char *w="malformed bundle" )
|
||||
: Exception( w ) {}
|
||||
};
|
||||
|
||||
class WrongArgumentTypeException : public Exception{
|
||||
public:
|
||||
WrongArgumentTypeException( const char *w="wrong argument type" )
|
||||
: Exception( w ) {}
|
||||
};
|
||||
|
||||
class MissingArgumentException : public Exception{
|
||||
public:
|
||||
MissingArgumentException( const char *w="missing argument" )
|
||||
: Exception( w ) {}
|
||||
};
|
||||
|
||||
class ExcessArgumentException : public Exception{
|
||||
public:
|
||||
ExcessArgumentException( const char *w="too many arguments" )
|
||||
: Exception( w ) {}
|
||||
};
|
||||
|
||||
|
||||
class ReceivedPacket{
|
||||
public:
|
||||
ReceivedPacket( const char *contents, int32 size )
|
||||
: contents_( contents )
|
||||
, size_( size ) {}
|
||||
|
||||
bool IsMessage() const { return !IsBundle(); }
|
||||
bool IsBundle() const;
|
||||
|
||||
int32 Size() const { return size_; }
|
||||
const char *Contents() const { return contents_; }
|
||||
|
||||
private:
|
||||
const char *contents_;
|
||||
int32 size_;
|
||||
};
|
||||
|
||||
|
||||
class ReceivedBundleElement{
|
||||
public:
|
||||
ReceivedBundleElement( const char *size )
|
||||
: size_( size ) {}
|
||||
|
||||
friend class ReceivedBundleElementIterator;
|
||||
|
||||
bool IsMessage() const { return !IsBundle(); }
|
||||
bool IsBundle() const;
|
||||
|
||||
int32 Size() const;
|
||||
const char *Contents() const { return size_ + 4; }
|
||||
|
||||
private:
|
||||
const char *size_;
|
||||
};
|
||||
|
||||
|
||||
class ReceivedBundleElementIterator{
|
||||
public:
|
||||
ReceivedBundleElementIterator( const char *sizePtr )
|
||||
: value_( sizePtr ) {}
|
||||
|
||||
ReceivedBundleElementIterator operator++()
|
||||
{
|
||||
Advance();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedBundleElementIterator operator++(int)
|
||||
{
|
||||
ReceivedBundleElementIterator old( *this );
|
||||
Advance();
|
||||
return old;
|
||||
}
|
||||
|
||||
const ReceivedBundleElement& operator*() const { return value_; }
|
||||
|
||||
const ReceivedBundleElement* operator->() const { return &value_; }
|
||||
|
||||
friend bool operator==(const ReceivedBundleElementIterator& lhs,
|
||||
const ReceivedBundleElementIterator& rhs );
|
||||
|
||||
private:
|
||||
ReceivedBundleElement value_;
|
||||
|
||||
void Advance() { value_.size_ = value_.Contents() + value_.Size(); }
|
||||
|
||||
bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const
|
||||
{
|
||||
return value_.size_ == rhs.value_.size_;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const ReceivedBundleElementIterator& lhs,
|
||||
const ReceivedBundleElementIterator& rhs )
|
||||
{
|
||||
return lhs.IsEqualTo( rhs );
|
||||
}
|
||||
|
||||
inline bool operator!=(const ReceivedBundleElementIterator& lhs,
|
||||
const ReceivedBundleElementIterator& rhs )
|
||||
{
|
||||
return !( lhs == rhs );
|
||||
}
|
||||
|
||||
|
||||
class ReceivedMessageArgument{
|
||||
public:
|
||||
ReceivedMessageArgument( const char *typeTag, const char *argument )
|
||||
: typeTag_( typeTag )
|
||||
, argument_( argument ) {}
|
||||
|
||||
friend class ReceivedMessageArgumentIterator;
|
||||
|
||||
const char TypeTag() const { return *typeTag_; }
|
||||
|
||||
// the unchecked methods below don't check whether the argument actually
|
||||
// is of the specified type. they should only be used if you've already
|
||||
// checked the type tag or the associated IsType() method.
|
||||
|
||||
bool IsBool() const
|
||||
{ return *typeTag_ == TRUE_TYPE_TAG || *typeTag_ == FALSE_TYPE_TAG; }
|
||||
bool AsBool() const;
|
||||
bool AsBoolUnchecked() const;
|
||||
|
||||
bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; }
|
||||
bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; }
|
||||
|
||||
bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; }
|
||||
int32 AsInt32() const;
|
||||
int32 AsInt32Unchecked() const;
|
||||
|
||||
bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; }
|
||||
float AsFloat() const;
|
||||
float AsFloatUnchecked() const;
|
||||
|
||||
bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; }
|
||||
char AsChar() const;
|
||||
char AsCharUnchecked() const;
|
||||
|
||||
bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; }
|
||||
uint32 AsRgbaColor() const;
|
||||
uint32 AsRgbaColorUnchecked() const;
|
||||
|
||||
bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; }
|
||||
uint32 AsMidiMessage() const;
|
||||
uint32 AsMidiMessageUnchecked() const;
|
||||
|
||||
bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; }
|
||||
int64 AsInt64() const;
|
||||
int64 AsInt64Unchecked() const;
|
||||
|
||||
bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; }
|
||||
uint64 AsTimeTag() const;
|
||||
uint64 AsTimeTagUnchecked() const;
|
||||
|
||||
bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; }
|
||||
double AsDouble() const;
|
||||
double AsDoubleUnchecked() const;
|
||||
|
||||
bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; }
|
||||
const char* AsString() const;
|
||||
const char* AsStringUnchecked() const { return argument_; }
|
||||
|
||||
bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; }
|
||||
const char* AsSymbol() const;
|
||||
const char* AsSymbolUnchecked() const { return argument_; }
|
||||
|
||||
bool IsBlob() const { return *typeTag_ == BLOB_TYPE_TAG; }
|
||||
void AsBlob( const void*& data, unsigned long& size ) const;
|
||||
void AsBlobUnchecked( const void*& data, unsigned long& size ) const;
|
||||
|
||||
private:
|
||||
const char *typeTag_;
|
||||
const char *argument_;
|
||||
};
|
||||
|
||||
|
||||
class ReceivedMessageArgumentIterator{
|
||||
public:
|
||||
ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments )
|
||||
: value_( typeTags, arguments ) {}
|
||||
|
||||
ReceivedMessageArgumentIterator operator++()
|
||||
{
|
||||
Advance();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentIterator operator++(int)
|
||||
{
|
||||
ReceivedMessageArgumentIterator old( *this );
|
||||
Advance();
|
||||
return old;
|
||||
}
|
||||
|
||||
const ReceivedMessageArgument& operator*() const { return value_; }
|
||||
|
||||
const ReceivedMessageArgument* operator->() const { return &value_; }
|
||||
|
||||
friend bool operator==(const ReceivedMessageArgumentIterator& lhs,
|
||||
const ReceivedMessageArgumentIterator& rhs );
|
||||
|
||||
private:
|
||||
ReceivedMessageArgument value_;
|
||||
|
||||
void Advance();
|
||||
|
||||
bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const
|
||||
{
|
||||
return value_.typeTag_ == rhs.value_.typeTag_;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const ReceivedMessageArgumentIterator& lhs,
|
||||
const ReceivedMessageArgumentIterator& rhs )
|
||||
{
|
||||
return lhs.IsEqualTo( rhs );
|
||||
}
|
||||
|
||||
inline bool operator!=(const ReceivedMessageArgumentIterator& lhs,
|
||||
const ReceivedMessageArgumentIterator& rhs )
|
||||
{
|
||||
return !( lhs == rhs );
|
||||
}
|
||||
|
||||
|
||||
class ReceivedMessageArgumentStream{
|
||||
friend class ReceivedMessage;
|
||||
ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin,
|
||||
const ReceivedMessageArgumentIterator& end )
|
||||
: p_( begin )
|
||||
, end_( end ) {}
|
||||
|
||||
ReceivedMessageArgumentIterator p_, end_;
|
||||
|
||||
public:
|
||||
|
||||
// end of stream
|
||||
bool Eos() const { return p_ == end_; }
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( bool& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
rhs = (*p_++).AsBool();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// not sure if it would be useful to stream Nil and Infinitum
|
||||
// for now it's not possible
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( int32& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
rhs = (*p_++).AsInt32();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( float& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
rhs = (*p_++).AsFloat();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( char& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
rhs = (*p_++).AsChar();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
rhs.value = (*p_++).AsRgbaColor();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
rhs.value = (*p_++).AsMidiMessage();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( int64& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
rhs = (*p_++).AsInt64();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( TimeTag& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
rhs.value = (*p_++).AsTimeTag();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( double& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
rhs = (*p_++).AsDouble();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( Blob& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
(*p_++).AsBlob( rhs.data, rhs.size );
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( const char*& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
rhs = (*p_++).AsString();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( Symbol& rhs )
|
||||
{
|
||||
if( Eos() )
|
||||
throw MissingArgumentException();
|
||||
|
||||
rhs.value = (*p_++).AsSymbol();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs )
|
||||
{
|
||||
if( !Eos() )
|
||||
throw ExcessArgumentException();
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ReceivedMessage{
|
||||
void Init( const char *bundle, unsigned long size );
|
||||
public:
|
||||
explicit ReceivedMessage( const ReceivedPacket& packet );
|
||||
explicit ReceivedMessage( const ReceivedBundleElement& bundleElement );
|
||||
|
||||
const char *AddressPattern() const { return addressPattern_; }
|
||||
|
||||
// Support for non-standad SuperCollider integer address patterns:
|
||||
bool AddressPatternIsUInt32() const;
|
||||
uint32 AddressPatternAsUInt32() const;
|
||||
|
||||
unsigned long ArgumentCount() const { return static_cast<unsigned long>(typeTagsEnd_ - typeTagsBegin_); }
|
||||
|
||||
const char *TypeTags() const { return typeTagsBegin_; }
|
||||
|
||||
|
||||
typedef ReceivedMessageArgumentIterator const_iterator;
|
||||
|
||||
ReceivedMessageArgumentIterator ArgumentsBegin() const
|
||||
{
|
||||
return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ );
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentIterator ArgumentsEnd() const
|
||||
{
|
||||
return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 );
|
||||
}
|
||||
|
||||
ReceivedMessageArgumentStream ArgumentStream() const
|
||||
{
|
||||
return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() );
|
||||
}
|
||||
|
||||
private:
|
||||
const char *addressPattern_;
|
||||
const char *typeTagsBegin_;
|
||||
const char *typeTagsEnd_;
|
||||
const char *arguments_;
|
||||
};
|
||||
|
||||
|
||||
class ReceivedBundle{
|
||||
void Init( const char *message, unsigned long size );
|
||||
public:
|
||||
explicit ReceivedBundle( const ReceivedPacket& packet );
|
||||
explicit ReceivedBundle( const ReceivedBundleElement& bundleElement );
|
||||
|
||||
uint64 TimeTag() const;
|
||||
|
||||
unsigned long ElementCount() const { return elementCount_; }
|
||||
|
||||
typedef ReceivedBundleElementIterator const_iterator;
|
||||
|
||||
ReceivedBundleElementIterator ElementsBegin() const
|
||||
{
|
||||
return ReceivedBundleElementIterator( timeTag_ + 8 );
|
||||
}
|
||||
|
||||
ReceivedBundleElementIterator ElementsEnd() const
|
||||
{
|
||||
return ReceivedBundleElementIterator( end_ );
|
||||
}
|
||||
|
||||
private:
|
||||
const char *timeTag_;
|
||||
const char *end_;
|
||||
unsigned long elementCount_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace osc
|
||||
|
||||
|
||||
#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
|
40
src/osgPlugins/osc/osc/OscTypes.cpp
Normal file
40
src/osgPlugins/osc/osc/OscTypes.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "OscTypes.h"
|
||||
|
||||
namespace osc{
|
||||
|
||||
BundleInitiator BeginBundleImmediate(1);
|
||||
BundleTerminator EndBundle;
|
||||
MessageTerminator EndMessage;
|
||||
NilType Nil;
|
||||
InfinitumType Infinitum;
|
||||
|
||||
} // namespace osc
|
183
src/osgPlugins/osc/osc/OscTypes.h
Normal file
183
src/osgPlugins/osc/osc/OscTypes.h
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
oscpack -- Open Sound Control packet manipulation library
|
||||
http://www.audiomulch.com/~rossb/oscpack
|
||||
|
||||
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
requested to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDED_OSCTYPES_H
|
||||
#define INCLUDED_OSCTYPES_H
|
||||
|
||||
|
||||
namespace osc{
|
||||
|
||||
// basic types
|
||||
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
|
||||
typedef __int64 int64;
|
||||
typedef unsigned __int64 uint64;
|
||||
|
||||
#elif defined(__x86_64__) || defined(_M_X64)
|
||||
|
||||
typedef long int64;
|
||||
typedef unsigned long uint64;
|
||||
|
||||
#else
|
||||
|
||||
typedef long long int64;
|
||||
typedef unsigned long long uint64;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
|
||||
typedef signed int int32;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
#else
|
||||
|
||||
typedef signed long int32;
|
||||
typedef unsigned long uint32;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
enum TypeTagValues {
|
||||
TRUE_TYPE_TAG = 'T',
|
||||
FALSE_TYPE_TAG = 'F',
|
||||
NIL_TYPE_TAG = 'N',
|
||||
INFINITUM_TYPE_TAG = 'I',
|
||||
INT32_TYPE_TAG = 'i',
|
||||
FLOAT_TYPE_TAG = 'f',
|
||||
CHAR_TYPE_TAG = 'c',
|
||||
RGBA_COLOR_TYPE_TAG = 'r',
|
||||
MIDI_MESSAGE_TYPE_TAG = 'm',
|
||||
INT64_TYPE_TAG = 'h',
|
||||
TIME_TAG_TYPE_TAG = 't',
|
||||
DOUBLE_TYPE_TAG = 'd',
|
||||
STRING_TYPE_TAG = 's',
|
||||
SYMBOL_TYPE_TAG = 'S',
|
||||
BLOB_TYPE_TAG = 'b'
|
||||
};
|
||||
|
||||
|
||||
|
||||
// i/o manipulators used for streaming interfaces
|
||||
|
||||
struct BundleInitiator{
|
||||
explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {}
|
||||
uint64 timeTag;
|
||||
};
|
||||
|
||||
extern BundleInitiator BeginBundleImmediate;
|
||||
|
||||
inline BundleInitiator BeginBundle( uint64 timeTag=1 )
|
||||
{
|
||||
return BundleInitiator(timeTag);
|
||||
}
|
||||
|
||||
|
||||
struct BundleTerminator{
|
||||
};
|
||||
|
||||
extern BundleTerminator EndBundle;
|
||||
|
||||
struct BeginMessage{
|
||||
explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {}
|
||||
const char *addressPattern;
|
||||
};
|
||||
|
||||
struct MessageTerminator{
|
||||
};
|
||||
|
||||
extern MessageTerminator EndMessage;
|
||||
|
||||
|
||||
// osc specific types. they are defined as structs so they can be used
|
||||
// as separately identifiable types with the streaming operators.
|
||||
|
||||
struct NilType{
|
||||
};
|
||||
|
||||
extern NilType Nil;
|
||||
|
||||
|
||||
struct InfinitumType{
|
||||
};
|
||||
|
||||
extern InfinitumType Infinitum;
|
||||
|
||||
struct RgbaColor{
|
||||
RgbaColor() {}
|
||||
explicit RgbaColor( uint32 value_ ) : value( value_ ) {}
|
||||
uint32 value;
|
||||
|
||||
operator uint32() const { return value; }
|
||||
};
|
||||
|
||||
|
||||
struct MidiMessage{
|
||||
MidiMessage() {}
|
||||
explicit MidiMessage( uint32 value_ ) : value( value_ ) {}
|
||||
uint32 value;
|
||||
|
||||
operator uint32() const { return value; }
|
||||
};
|
||||
|
||||
|
||||
struct TimeTag{
|
||||
TimeTag() {}
|
||||
explicit TimeTag( uint64 value_ ) : value( value_ ) {}
|
||||
uint64 value;
|
||||
|
||||
operator uint64() const { return value; }
|
||||
};
|
||||
|
||||
|
||||
struct Symbol{
|
||||
Symbol() {}
|
||||
explicit Symbol( const char* value_ ) : value( value_ ) {}
|
||||
const char* value;
|
||||
|
||||
operator const char *() const { return value; }
|
||||
};
|
||||
|
||||
|
||||
struct Blob{
|
||||
Blob() {}
|
||||
explicit Blob( const void* data_, unsigned long size_ )
|
||||
: data( data_ ), size( size_ ) {}
|
||||
const void* data;
|
||||
unsigned long size;
|
||||
};
|
||||
|
||||
} // namespace osc
|
||||
|
||||
|
||||
#endif /* INCLUDED_OSCTYPES_H */
|
Loading…
Reference in New Issue
Block a user