merge with develop

This commit is contained in:
Jonathan Bosson
2017-03-02 15:49:54 -07:00
82 changed files with 14699 additions and 14 deletions

2
.gitignore vendored
View File

@@ -119,3 +119,5 @@ data/spice/OsirisRexKernels
data/spice/plu055.bsp
data/spice/Rosetta
data/spice/sat375.bsp
data/scene/lodglobes/saturn/Launcher.config
data/scene/lodglobes/mars/test_stats

View File

@@ -41,7 +41,8 @@ return {
CommonFolder = "common",
Camera = {
Focus = "Earth",
Position = {1, 0, 0, 2},
Position = {1, 0, 0},
Rotation = {0.250635, -0.028751, 0.879269, 0.404030},
},
Modules = {
"sun",

View File

@@ -71,6 +71,10 @@ return {
},
Enabled = true,
},
{
FilePath = "map_service_configs/ESRI/ESRI_Imagery_World_2D.wms",
Name = "ESRI",
},
{
Type = "Temporal",
Name = "Temporal VIIRS SNPP",

View File

@@ -1,4 +1,4 @@
UseAccurateNewHorizonsKernels = true
UseAccurateNewHorizonsKernels = false
-- TextureResolution = "low"
TextureResolution = "med"
-- TextureResolution = "high"

View File

@@ -1,4 +1,4 @@
var levels = ['trace', 'debug', 'info', 'warning', 'error', 'fatal'];
var levels = ['debug', 'info', 'warning', 'error', 'fatal'];
var filterLevel = 0;
function insertAfter(newNode, referenceNode) {

View File

@@ -27,15 +27,6 @@ label {
margin-right: 0.5em;
}
.log-level-trace {
color: #eeeeee;
background-color: #aaaaaa;
border-bottom: 1px solid #eaeaea;
}
.log-level-trace td:first-child {
border-left: 10px solid #eaeaea;
}
.log-level-debug {
background-color: #bbdda9;
border-bottom: 1px solid #7bc142;

View File

@@ -0,0 +1,43 @@
#########################################################################################
# #
# OpenSpace #
# #
# Copyright (c) 2014-2017 #
# #
# 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. #
# #
# 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(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/include/TuioEar.h
)
source_group("Header Files" FILES ${HEADER_FILES})
set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/TuioEar.cpp
)
source_group("Source Files" FILES ${SOURCE_FILES})
create_new_module(
"Touch"
touch_module
${HEADER_FILES} ${SOURCE_FILES}
)
include_external_library(${touch_module} libTUIO ${CMAKE_CURRENT_SOURCE_DIR}/ext/libTUIO)

Binary file not shown.

View File

@@ -0,0 +1,67 @@
#########################################################################################
# #
# OpenSpace #
# #
# Copyright (c) 2014-2016 #
# #
# 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. #
# #
# 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. #
#########################################################################################
project(libTUIO)
message(STATUS "Generating libTUIO project")
add_library(libTUIO
${PROJECT_SOURCE_DIR}/TUIO/WebSockSender.cpp
${PROJECT_SOURCE_DIR}/TUIO/UdpSender.cpp
${PROJECT_SOURCE_DIR}/TUIO/UdpReceiver.cpp
#${PROJECT_SOURCE_DIR}/TUIO2/TuioToken.cpp
${PROJECT_SOURCE_DIR}/TUIO/TuioTime.cpp
#${PROJECT_SOURCE_DIR}/TUIO2/TuioSymbol.cpp
${PROJECT_SOURCE_DIR}/TUIO/TuioServer.cpp
#${PROJECT_SOURCE_DIR}/TUIO2/TuioPointer.cpp
${PROJECT_SOURCE_DIR}/TUIO/TuioPoint.cpp
${PROJECT_SOURCE_DIR}/TUIO/TuioObject.cpp
${PROJECT_SOURCE_DIR}/TUIO/TuioManager.cpp
${PROJECT_SOURCE_DIR}/TUIO/TuioDispatcher.cpp
#${PROJECT_SOURCE_DIR}/TUIO2/TuioComponent.cpp
${PROJECT_SOURCE_DIR}/TUIO/TuioCursor.cpp #
${PROJECT_SOURCE_DIR}/TUIO/TuioContainer.cpp #
${PROJECT_SOURCE_DIR}/TUIO/TuioClient.cpp
#${PROJECT_SOURCE_DIR}/TUIO2/TuioBounds.cpp
${PROJECT_SOURCE_DIR}/TUIO/TuioBlob.cpp #
${PROJECT_SOURCE_DIR}/TUIO/TcpSender.cpp
${PROJECT_SOURCE_DIR}/TUIO/TcpReceiver.cpp
${PROJECT_SOURCE_DIR}/TUIO/OscReceiver.cpp
${PROJECT_SOURCE_DIR}/TUIO/OneEuroFilter.cpp #
${PROJECT_SOURCE_DIR}/TUIO/FlashSender.cpp
${PROJECT_SOURCE_DIR}/oscpack/ip/IpEndpointName.cpp
#if (WIN32)
${PROJECT_SOURCE_DIR}/oscpack/ip/win32/NetworkingUtils.cpp
${PROJECT_SOURCE_DIR}/oscpack/ip/win32/UdpSocket.cpp
#else (WIN32)
#${PROJECT_SOURCE_DIR}/oscpack/ip/posix/NetworkingUtils.cpp
#${PROJECT_SOURCE_DIR}/oscpack/ip/posix/UdpSocket.cpp
#endif ()
${PROJECT_SOURCE_DIR}/oscpack/osc/OscTypes.cpp
${PROJECT_SOURCE_DIR}/oscpack/osc/OscReceivedElements.cpp
${PROJECT_SOURCE_DIR}/oscpack/osc/OscPrintReceivedElements.cpp
${PROJECT_SOURCE_DIR}/oscpack/osc/OscOutboundPacketStream.cpp
)
target_include_directories(libTUIO PUBLIC ${PROJECT_SOURCE_DIR})

View File

@@ -0,0 +1,15 @@
# Doxyfile 1.5.6
# Project related configuration options
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "TUIO C++ Developer API"
# Build related configuration options
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
# configuration options related to the HTML output
GENERATE_HTML = YES
HTML_OUTPUT = ../doc
HTML_FILE_EXTENSION = .html
GENERATE_TREEVIEW = YES
GENERATE_LATEX = NO

View File

@@ -0,0 +1,650 @@
#include "FlashSender.h"
// Copyright (C) 2009 Georg Kaindl
// This file is part of Touché.
//
// Touché is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// Touché 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
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Touché. If not, see <http://www.gnu.org/licenses/>.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(WIN32)
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <fcntl.h>
#if defined(__APPLE__)
#include <mach/mach.h>
#include <mach/mach_time.h>
#else
#include <utmpx.h>
#endif
#endif
#define FLASHLC_SHM_SIZE (64528) // This is what Flash always uses as size
#define FLASHLC_SHM_LISTENERS_OFFSET (40976) // Another "magic number"
#define MAX_LISTENER_NAME_LEN (64)
#define MAX_LISTENER_METHOD_NAME (64)
#define PROTOCOL_NAME ("localhost")
#define WIN32_SEMAPHORE_NAME TEXT("MacromediaMutexOmega")
#define WIN32_SHMEM_NAME TEXT("MacromediaFMOmega")
#define POSIX_SEMAPHORE_NAME ("MacromediaSemaphoreDig")
#define POSIX_SEMAPHORE_INITIAL_VALUE (10)
#define AMF_TYPE_STRING (0x02)
#define AMF_TYPE_AMF3OBJ (0x11)
#define AMF3_TYPE_BYTEARRAY (0x0C)
#define AMF_ENVELOPE_LEN (16)
#define AMF_ENVELOPE_TIMESTAMP_POS (8)
#define AMF_ENVELOPE_SIZE_POS (12)
void _TFLCSLockSemaphore(TFLCSLocalConnection_t* connection);
void _TFLCSUnlockSemaphore(TFLCSLocalConnection_t* connection);
// returns non-zero if the given connection is in a usable state, zero otherwise
int _TFLCSConnectionStructureIsValidForUse(TFLCSLocalConnection_t* connection);
// On WIN32, we cannot create the shared memory and semaphore ourselves, because
// we don't know the exact parameters. Therefore, if Flash is not running when we
// try to connect, we'll try again whenever we should send data, until we finally
// manage to connect.
int _TFLCSDelayedConnect(TFLCSLocalConnection_t* connection);
#define ENSURE_CONNECTION_UP(c, rv) do { if (!(c)->open && !_TFLCSDelayedConnect((c))) return (rv); } while (0)
u_int32_t _TFLCSKnownDarwinKeys[] = { 0x53414e44, 0 };
TFLCSError_t TFLCSErrno = TFLCSErrorSuccess;
TFLCSLocalConnection_t* TFLCSConnect(const char* listenerName,
const char* listenerMethod,
void* shmemKey,
void* semaphoreKey)
{
TFLCSLocalConnection_t* connection = NULL;
if (NULL == listenerName || NULL == listenerMethod ||
strlen(listenerName) > TFLCS_LISTENER_NAME_MAX_LEN ||
strlen(listenerMethod) > TFLCS_LISTENER_METHOD_MAX_LEN) {
TFLCSErrno = TFLCSErrorInvalidArgument;
return NULL;
}
connection = (TFLCSLocalConnection_t*)malloc(sizeof(TFLCSLocalConnection_t));
if (NULL == connection) {
TFLCSErrno = TFLCSErrorOutOfMemory;
goto errorReturn;
}
connection->open = 0;
#if defined(WIN32)
// initialize the structure
connection->semaphore = NULL;
connection->mapFile = NULL;
connection->mapAddress = NULL;
connection->data = NULL;
_TFLCSDelayedConnect(connection);
#else
// initialize the structure
connection->semaphore = (sem_t*)SEM_FAILED;
connection->shmid = -1;
connection->data = (char*)-1;
// we don't need a delayed connect on MacOS X, so let's just connect now!
key_t key;
char* semName;
if (NULL != shmemKey)
key = *(key_t*)shmemKey;
else {
key_t* guessedKey = (key_t*)TFLCSGuessShmemKey();
if (NULL != guessedKey)
key = *(key_t*)guessedKey;
else {
TFLCSErrno = TFLCSErrorShmemKeyNotFound;
goto errorReturn;
}
}
if (NULL != semaphoreKey)
semName = (char*)semaphoreKey;
else
semName = (char*)POSIX_SEMAPHORE_NAME;
connection->semaphore = sem_open(semName,
O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
POSIX_SEMAPHORE_INITIAL_VALUE);
if ((sem_t*)SEM_FAILED == connection->semaphore) {
TFLCSErrno = TFLCSErrorSemaphoreCreationFailed;
goto errorReturn;
}
if (-1 == (connection->shmid = shmget(key, FLASHLC_SHM_SIZE, 0666 | IPC_CREAT))) {
TFLCSErrno = TFLCSErrorShmemIDNotFound;
goto errorReturn;
}
connection->data = (char*)shmat(connection->shmid, NULL, 0);
if ((char*)-1 == connection->data) {
TFLCSErrno = TFLCSErrorShmemOpeningFailed;
goto errorReturn;
}
connection->open = 1;
// initialize the memory region the way Flash likes it :-)
connection->data[0] = 1;
connection->data[4] = 1;
#endif
strncpy(connection->listenerName, listenerName, TFLCS_LISTENER_NAME_MAX_LEN);
strncpy(connection->listenerMethod, listenerMethod, TFLCS_LISTENER_METHOD_MAX_LEN);
return connection;
errorReturn:
TFLCSDisconnect(connection);
return NULL;
}
void TFLCSDisconnect(TFLCSLocalConnection_t* connection)
{
if (NULL != connection) {
#if defined(WIN32)
if (NULL != connection->semaphore)
CloseHandle(connection->semaphore);
if (NULL != connection->mapAddress)
UnmapViewOfFile(connection->mapAddress);
if (NULL != connection->mapFile)
CloseHandle(connection->mapFile);
#else
if ((sem_t*)SEM_FAILED != connection->semaphore)
sem_close(connection->semaphore);
if ((char*)-1 != connection->data)
(void)shmdt(connection->data);
#endif
free(connection);
}
}
void TFLCSChangeListenerName(TFLCSLocalConnection_t* connection, const char* newListenerName)
{
if (NULL != connection && NULL != newListenerName)
strncpy(connection->listenerName, newListenerName, TFLCS_LISTENER_NAME_MAX_LEN);
}
void TFLCSChangeMethodName(TFLCSLocalConnection_t* connection, const char* newMethodName)
{
if (NULL != connection && NULL != newMethodName)
strncpy(connection->listenerMethod, newMethodName, TFLCS_LISTENER_METHOD_MAX_LEN);
}
int TFLCSConnectionHasConnectedClient(TFLCSLocalConnection_t* connection)
{
ENSURE_CONNECTION_UP(connection, 0);
int retval = 0;
if (_TFLCSConnectionStructureIsValidForUse(connection)) {
_TFLCSLockSemaphore(connection);
int c, l = strlen(connection->listenerName);
char* p = &connection->data[FLASHLC_SHM_LISTENERS_OFFSET];
while (!retval && (char)0 != *p) {
c = strlen(p) + 1;
if (0 == strncmp(p, connection->listenerName, l))
retval = 1;
p += c;
}
_TFLCSUnlockSemaphore(connection);
}
return retval;
}
int TFLCSGetConnectedConnectionNames(TFLCSLocalConnection_t* connection, char* dest, int destLen)
{
ENSURE_CONNECTION_UP(connection, 0);
int retval = 0;
if (NULL != dest && 0 < destLen && _TFLCSConnectionStructureIsValidForUse(connection)) {
_TFLCSLockSemaphore(connection);
int c, i=0;
char* p = &connection->data[FLASHLC_SHM_LISTENERS_OFFSET];
while ((char)0 != *p && destLen > 0) {
c = strlen(p) + 1;
if (0 == (i % 3)) {
strncpy(dest, p, destLen < c ? destLen : c);
destLen -= c;
dest += c;
}
p += c;
i++;
}
retval = i/3;
_TFLCSUnlockSemaphore(connection);
}
return retval;
}
void* TFLCSGuessShmemKey()
{
#if defined(WIN32)
return (void*)WIN32_SHMEM_NAME;
#else
static int found = 0;
static key_t key;
// first, try our known keys
int i = 0;
while(!found && _TFLCSKnownDarwinKeys[i]) {
if (-1 != shmget(_TFLCSKnownDarwinKeys[i], FLASHLC_SHM_SIZE, 0)) {
found = 1;
key = _TFLCSKnownDarwinKeys[i];
}
i++;
}
/* // magic numbers for MacOS X 10.5, probably later and earlier versions too, dunno...
int minid = 0xffff;
int maxid = 0x500000;
struct shmid_ds shm_info;
for (i=minid; !found && i<=maxid; i++) {
if (shmctl(i, IPC_STAT, &shm_info) < 0)
continue;
if (FLASHLC_SHM_SIZE == shm_info.shm_segsz) {
found = 1;
key = shm_info.shm_perm._key;
}
} */
// if we didn't find anything, set the key to a reasonable guess
// this is necessary because the shared segment might not exist yet.
if (!found) {
key = _TFLCSKnownDarwinKeys[0];
found = 1;
}
return &key;
#endif
}
u_int32_t TFLCSGetTickCount()
{
#if defined(WIN32)
return (u_int32_t)GetTickCount();
#elif defined(__APPLE__)
static mach_timebase_info_data_t timeBase;
u_int64_t nanos = mach_absolute_time();
if (0 == timeBase.denom) {
(void)mach_timebase_info(&timeBase);
}
return (u_int32_t)((nanos * (u_int64_t)timeBase.numer / (u_int64_t)timeBase.denom) / (u_int64_t)1000000);
#else
static struct timeval bt;
static int initialized = 0;
if (!initialized) {
struct utmpx* ut;
while (NULL != (ut = getutxent())) {
if (BOOT_TIME == ut->ut_type) {
memcpy(&bt, &ut->ut_tv, sizeof(struct timeval));
break;
}
}
initialized = 1;
}
struct timeval nt, btc;
(void)gettimeofday(&nt, NULL);
memcpy(&btc, &bt, sizeof(struct timeval));
if (nt.tv_usec < btc.tv_usec) {
u_int64_t n = (btc.tv_usec - nt.tv_usec) / 1000000 + 1;
btc.tv_usec -= 1000000 * n;
btc.tv_sec += n;
}
if (nt.tv_usec - btc.tv_usec > 1000000) {
u_int64_t n = (btc.tv_usec - nt.tv_usec) / 1000000;
btc.tv_usec += 1000000 * n;
btc.tv_sec -= n;
}
nt.tv_usec = nt.tv_usec - btc.tv_usec;
nt.tv_sec = nt.tv_sec - btc.tv_sec;
return (u_int32_t)((nt.tv_sec * 1000) + (nt.tv_usec / 1000));
#endif
}
int TFLCSWriteAMF3Integer(char* buffer, int value, int pos)
{
if (value < 0) {
buffer[pos++] = (0x80 | ((value >> 22) & 0xff));
buffer[pos++] = (0x80 | ((value >> 15) & 0x7f));
buffer[pos++] = (0x80 | ((value >> 8) & 0x7f));
buffer[pos++] = (value & 0xff);
} else if (value <= 0x7f) {
buffer[pos++] = value;
} else if (value <= 0x3fff) {
buffer[pos++] = (0x80 | ((value >> 7) & 0x7f));
buffer[pos++] = (value & 0x7f);
} else if (value <= 0x1fffff) {
buffer[pos++] = (0x80 | ((value >> 14) & 0x7f));
buffer[pos++] = (0x80 | ((value >> 7) & 0x7f));
buffer[pos++] = (value & 0x7f);
} else {
buffer[pos++] = (0x80 | ((value >> 22) & 0xff));
buffer[pos++] = (0x80 | ((value >> 15) & 0x7f));
buffer[pos++] = (0x80 | ((value >> 8) & 0x7f));
buffer[pos++] = (value & 0xff);
}
return pos;
}
int TFLCSWriteAMFString(char* buffer, const char * str, int pos)
{
int len = strlen(str);
buffer[pos++] = AMF_TYPE_STRING;
buffer[pos++] = 0; // TODO: string length is badly encoded here!
buffer[pos++] = (char)(len & 0xff);
strcpy((char*)&buffer[pos], str);
pos += len;
return pos;
}
int TFLCSWriteAMF3ByteArray(char* buffer, const char* bytes, int pos, int len)
{
// buffer[pos++] = AMF_TYPE_AMF3OBJ;
buffer[pos++] = AMF3_TYPE_BYTEARRAY; // AMF3_TYPE_BYTE_ARRAY
pos = TFLCSWriteAMF3Integer(buffer, ((len << 1) | 1), pos);
int i=0;
for(i=0; i<len; i++)
buffer[pos++] = bytes[i];
return pos;
}
int TFLCSWriteLCAMFEnvelopeHeader(TFLCSLocalConnection_t* connection)
{
if (NULL == connection)
return 0;
u_int32_t* timestamp = (u_int32_t*)&connection->data[AMF_ENVELOPE_TIMESTAMP_POS];
int pos = AMF_ENVELOPE_LEN;
// check timestamp and size
memset(connection->data, 0, AMF_ENVELOPE_LEN);
connection->data[0] = 1;
connection->data[4] = 1;
*timestamp = TFLCSGetTickCount();
// write connection name
pos = TFLCSWriteAMFString(connection->data, connection->listenerName, pos);
// write protocol
pos = TFLCSWriteAMFString(connection->data, PROTOCOL_NAME, pos);
// I have no idea what this is, but we apparently need it...
char weirdBytes[] = {
0x01, 0x01, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0x40, 0x24, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x08, 0, 0,
0, 0, 0, 0};
int i;
for (i=0; i<31; i++)
connection->data[pos++] = weirdBytes[i];
// write method name
pos = TFLCSWriteAMFString(connection->data, connection->listenerMethod, pos);
return pos;
}
int TFLCSWriteLCAMFEnvelopeTrailer(TFLCSLocalConnection_t* connection, int pos)
{
if (NULL == connection)
return pos;
u_int32_t* size = (u_int32_t*)&connection->data[AMF_ENVELOPE_SIZE_POS];
//pos = writeAMF3ByteArray(buffer, msg, pos, strlen(msg));
*size = pos-16;
return pos;
}
int TFLCSSendByteArray(TFLCSLocalConnection_t* connection, const char* bytes, int len)
{
ENSURE_CONNECTION_UP(connection, 0);
if (NULL == bytes || 0 == len || !_TFLCSConnectionStructureIsValidForUse(connection)) {
TFLCSErrno = TFLCSErrorInvalidArgument;
return 0;
}
_TFLCSLockSemaphore(connection);
int pos = TFLCSWriteLCAMFEnvelopeHeader(connection);
pos = TFLCSWriteAMF3ByteArray(connection->data, bytes, pos, len);
(void)TFLCSWriteLCAMFEnvelopeTrailer(connection, pos);
_TFLCSUnlockSemaphore(connection);
return 1;
}
void TFLCSDumpMemory(char* buffer, int offset, int size)
{
int i = 0;
int c = 0;
char b;
while (i < size) {
while ((c < 16) && (i+c < size)) {
b = buffer[offset+i+c];
printf("%X%X ", b/16 & 0x0f, b & 0x0f );
c++;
}
while (c++ < 16)
printf(" ");
c = 0;
while ((c < 16) && (i+c < size)) {
b = buffer[offset+i+c];
if (b > 31)
printf("%c", (char)b);
else
printf(".");
c++;
}
i += 16;
c = 0;
printf("\n");
}
}
void _TFLCSLockSemaphore(TFLCSLocalConnection_t* connection)
{
if (NULL != connection) {
#if defined(WIN32)
if (NULL != connection->semaphore)
WaitForSingleObject(connection->semaphore, INFINITE);
#else
if ((sem_t*)SEM_FAILED != connection->semaphore)
sem_wait(connection->semaphore);
#endif
}
}
void _TFLCSUnlockSemaphore(TFLCSLocalConnection_t* connection)
{
if (NULL != connection) {
#if defined(WIN32)
if (NULL != connection->semaphore)
ReleaseMutex(connection->semaphore);
#else
if ((sem_t*)SEM_FAILED != connection->semaphore)
sem_post(connection->semaphore);
#endif
}
}
int _TFLCSConnectionStructureIsValidForUse(TFLCSLocalConnection_t* connection)
{
return (NULL != connection
&& 0 != connection->open
#if defined(WIN32)
&& NULL != connection->semaphore
&& NULL != connection->mapFile
&& NULL != connection->mapAddress
&& NULL != connection->data
#else
&& (sem_t*)SEM_FAILED != connection->semaphore
&& (char*)-1 != connection->data
#endif
);
}
int _TFLCSDelayedConnect(TFLCSLocalConnection_t* connection)
{
#if defined(WIN32)
if (NULL == connection)
return 0;
if (connection->open)
return 1;
if (NULL == (connection->semaphore = OpenMutex(MUTEX_ALL_ACCESS,
FALSE,
WIN32_SEMAPHORE_NAME))) {
TFLCSErrno = TFLCSErrorSemaphoreCreationFailed;
goto errorReturn;
}
if (NULL == (connection->mapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS,
FALSE,
WIN32_SHMEM_NAME))) {
TFLCSErrno = TFLCSErrorShmemIDNotFound;
goto errorReturn;
}
if (NULL == (connection->mapAddress = MapViewOfFile(connection->mapFile,
FILE_MAP_ALL_ACCESS,
0,
0,
0))) {
TFLCSErrno = TFLCSErrorShmemOpeningFailed;
goto errorReturn;
}
connection->data = (char*)connection->mapAddress;
connection->open = 1;
errorReturn:
#endif
return connection->open;
}
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
using namespace TUIO;
FlashSender::FlashSender() {
local = true;
buffer_size = MAX_FLASH_SIZE;
lcConnection = TFLCSConnect(DEFAULT_LC_CONN_NAME,DEFAULT_LC_METH_NAME,NULL,NULL);
std::cout << "TUIO/FLC "<< DEFAULT_LC_METH_NAME << "@" << DEFAULT_LC_CONN_NAME << std::endl;
}
FlashSender::FlashSender(const char *conn_name, const char *meth_name) {
local = true;
buffer_size = MAX_FLASH_SIZE;
lcConnection = TFLCSConnect(conn_name,meth_name,NULL,NULL);
std::cout << "TUIO/FLC "<< meth_name << "@" << conn_name << std::endl;
}
FlashSender::~FlashSender() {
TFLCSDisconnect(lcConnection);
}
bool FlashSender::isConnected() {
if (TFLCSConnectionHasConnectedClient(lcConnection)) return true;
else return false;
}
bool FlashSender::sendOscPacket (osc::OutboundPacketStream *bundle) {
if (lcConnection==NULL) return false;
if (!TFLCSConnectionHasConnectedClient(lcConnection)) return false;
if ( bundle->Size() > buffer_size ) return false;
if ( bundle->Size() == 0 ) return false;
TFLCSSendByteArray(lcConnection, bundle->Data(), bundle->Size());
return true;
}

View File

@@ -0,0 +1,215 @@
//
// TFFlashLCSHMEM.h
// Touché
//
// Created by Georg Kaindl on 16/3/09.
//
// Copyright (C) 2009 Georg Kaindl
//
// This file is part of Touché.
//
// Touché is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// Touché 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
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with Touché. If not, see <http://www.gnu.org/licenses/>.
#if !defined(__TFFlashLCSHMEM_H__)
#define __TFFlashLCSHMEM_H__ 1
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#ifdef WIN32
#include <windows.h>
typedef DWORD u_int32_t;
#else
#include <sys/types.h>
#include <semaphore.h>
#endif
#define TFLCS_LISTENER_NAME_MAX_LEN (64)
#define TFLCS_LISTENER_METHOD_MAX_LEN (64)
typedef struct TFLCSLocalConnection_t {
#ifdef WIN32
HANDLE semaphore;
HANDLE mapFile;
LPVOID mapAddress;
#else
int shmid;
sem_t* semaphore;
#endif
int open;
char* data;
char listenerName[TFLCS_LISTENER_NAME_MAX_LEN];
char listenerMethod[TFLCS_LISTENER_METHOD_MAX_LEN];
} TFLCSLocalConnection_t;
typedef enum {
TFLCSErrorSuccess = 0,
TFLCSErrorInvalidArgument = 1,
TFLCSErrorShmemKeyNotFound = 2,
TFLCSErrorSemaphoreCreationFailed = 3,
TFLCSErrorShmemIDNotFound = 4,
TFLCSErrorShmemOpeningFailed = 5,
TFLCSErrorOutOfMemory = 6
} TFLCSError_t;
// much like errno, this will hold the last error that happened
extern TFLCSError_t TFLCSErrno;
// connect to a Flash LocalConnection
// returns pointer to structure on success, NULL otherwise
// if the connection could not be opened right away (because Flash is not yet running),
// a non-null pointer is returned, but the "open" member of the structure will be 0
// and TFLCSErrno will be set accordingly. the connection is truly open once "open" is
// non-zero.
TFLCSLocalConnection_t* TFLCSConnect(const char* listenerName,
const char* listenerMethod,
void* shmemKey,
void* semaphoreKey);
// disconnect a Flash LocalConnection
void TFLCSDisconnect(TFLCSLocalConnection_t* connection);
// changes the connection listener name
void TFLCSChangeListenerName(TFLCSLocalConnection_t* connection, const char* newListenerName);
// changes the connection method name
void TFLCSChangeMethodName(TFLCSLocalConnection_t* connection, const char* newMethodName);
// returns non-zero if the given connection's Flash client is connected, 0 otherwise
int TFLCSConnectionHasConnectedClient(TFLCSLocalConnection_t* connection);
// tries to determine the key for the shared memory region used by the Flash LocalConnection
// returns a pointer to static memory on success, NULL on error.
void* TFLCSGuessShmemKey();
// get the current tick count (milliseconds since the system was started)
u_int32_t TFLCSGetTickCount();
// write an AMF3-encoded integer into a buffer
// returns the updated buffer position
int TFLCSWriteAMF3Integer(char* buffer, int value, int pos);
// write an AMF-encoded string into a buffer
// returns the updated buffer position
int TFLCSWriteAMFString(char* buffer, const char * str, int pos);
// write an AMF3-encoded byte array into a buffer
// returns the updated buffer position
int TFLCSWriteAMF3ByteArray(char* buffer, const char* bytes, int pos, int len);
// writes the AMF envelope header for an LC method call
// returns the position in the buffer
int TFLCSWriteLCAMFEnvelopeHeader(TFLCSLocalConnection_t* connection);
// writes the AMF envelope trailer for an LC method call
// returns the updated buffer position
int TFLCSWriteLCAMFEnvelopeTrailer(TFLCSLocalConnection_t* connection, int pos);
// sends the given data of length len over the given connection as a ByteArray
// returns 1 on success, 0 otherwise
int TFLCSSendByteArray(TFLCSLocalConnection_t* connection, const char* bytes, int len);
// gets the (string) names of all connected LC connections
// returns the number of found strings.
int TFLCSGetConnectedConnectionNames(TFLCSLocalConnection_t* connection, char* dest, int destLen);
// dumps a given buffer (size bytes starting at offset) to stdout in a nice hex/ascii format.
// useful for debugging purposes.
void TFLCSDumpMemory(char* buffer, int offset, int size);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif //__TFFlashLCSHMEM_H__
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_FLASHSENDER_H
#define INCLUDED_FLASHSENDER_H
#include "OscSender.h"
#define MAX_FLASH_SIZE (40976)
#define DEFAULT_LC_CONN_NAME "_OscDataStream"
#define DEFAULT_LC_METH_NAME "receiveOscData"
namespace TUIO {
/**
* The FlashSender implements the Flash LocalConnection transport method for OSC
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL FlashSender : public OscSender {
public:
/**
* The default constructor creates a FlashSender using a Flash LocalConnection on localhost
*/
FlashSender();
/**
* The default constructor creates a FlashSender using a Flash LocalConnection on localhost
*/
FlashSender(const char *conn_name, const char *meth_name);
/**
* The destructor closes the connection.
*/
virtual ~FlashSender();
/**
* This method delivers the provided OSC data
*
* @param *bundle the OSC stream to deliver
* @return true if the data was delivered successfully
*/
bool sendOscPacket (osc::OutboundPacketStream *bundle);
/**
* This method returns the connection state
*
* @return true if the connection is alive
*/
bool isConnected ();
const char* tuio_type() { return "TUIO/FLC"; }
private:
TFLCSLocalConnection_t* lcConnection;
};
}
#endif /* INCLUDED_FLASHSENDER_H */

View File

@@ -0,0 +1,36 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_LIBEXPORT_H
#define INCLUDED_LIBEXPORT_H
#ifdef WIN32
#pragma warning(disable: 4251) // disable annoying template exporting warnings
#pragma warning(disable: 4275) // disable warning caused by not exported OSC classes
#ifdef LIB_EXPORT
#define LIBDECL __declspec(dllexport)
#else
// #define LIBDECL __declspec(dllimport)
#define LIBDECL
#endif
#else
#define LIBDECL
#endif
#endif

View File

@@ -0,0 +1,66 @@
/* reacTIVision tangible interaction framework
Copyright (C) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
Based on an example by Nicolas Roussel <nicolas.roussel@inria.fr>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "OneEuroFilter.h"
#define M_PI 3.14159265392
using namespace TUIO;
double LowPassFilter::filter(double value, double alpha) {
if (alpha<=0.0 || alpha>1.0)
throw std::range_error("alpha should be in (0.0., 1.0]");
double result;
if (initialized)
result = alpha*value + (1.0-alpha)*lastResult;
else {
result = value;
initialized = true;
}
lastRawValue = value;
lastResult = result;
return result;
}
// -----------------------------------------------------------------
double OneEuroFilter::alpha(double cutoff) {
double te = 1.0 / freq;
double tau = 1.0 / (2*M_PI*cutoff);
return 1.0 / (1.0 + tau/te);
}
double OneEuroFilter::filter(double value, TimeStamp timestamp) {
// update the sampling frequency based on timestamps
if (lasttime!=UndefinedTime && timestamp!=UndefinedTime)
freq = 1.0 / (timestamp-lasttime);
lasttime = timestamp;
// estimate the current variation per second
double dvalue = x->initialized ? (value - x->lastRawValue)*freq : value;
double edvalue;
try { edvalue = dx->filter(dvalue, alpha(dcutoff));
} catch (std::range_error e) { return value; }
// use it to update the cutoff frequency
double cutoff = mincutoff + beta*fabs(edvalue);
// filter the given value
return x->filter(value, alpha(cutoff));
}

View File

@@ -0,0 +1,90 @@
/* reacTIVision tangible interaction framework
Copyright (C) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
Based on an example by Nicolas Roussel <nicolas.roussel@inria.fr>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef ONEEUROFILTER
#define ONEEUROFILTER
#include <stdexcept>
#include <cmath>
typedef double TimeStamp; // in seconds
static const TimeStamp UndefinedTime = -1.0;
namespace TUIO {
class LowPassFilter {
public:
bool initialized;
double lastRawValue,lastResult;
LowPassFilter(double initval=0.0) {
lastRawValue = lastResult = initval;
initialized = false;
}
double filter(double value, double alpha);
};
// -----------------------------------------------------------------
class OneEuroFilter {
double freq;
double mincutoff;
double beta;
double dcutoff;
LowPassFilter *x;
LowPassFilter *dx;
TimeStamp lasttime;
double alpha(double cutoff);
public:
OneEuroFilter(double f, double mc=1.0, double b=0.0, double dc=1.0) {
if (f<=0) throw std::range_error("freq should be >0");
else freq = f;
if (mc<=0) throw std::range_error("mincutoff should be >0");
else mincutoff = mc;
if (b<=0) throw std::range_error("beta should be >0");
else beta = b;
if (dc<=0) throw std::range_error("dcutoff should be >0");
else dcutoff = dc;
x = new LowPassFilter(alpha(mincutoff));
dx = new LowPassFilter(alpha(dcutoff));
lasttime = UndefinedTime;
}
~OneEuroFilter(void) {
delete x;
delete dx;
}
double filter(double value, TimeStamp timestamp=UndefinedTime);
};
}
#endif

View File

@@ -0,0 +1,60 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "OscReceiver.h"
using namespace TUIO;
using namespace osc;
void OscReceiver::ProcessMessage( const ReceivedMessage& msg, const IpEndpointName& remoteEndpoint) {
for (std::list<TuioClient*>::iterator client=clientList.begin(); client!= clientList.end(); client++)
(*client)->processOSC(msg);
}
void OscReceiver::ProcessBundle( const ReceivedBundle& b, const IpEndpointName& remoteEndpoint) {
try {
for( ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i ){
if( i->IsBundle() )
ProcessBundle( ReceivedBundle(*i), remoteEndpoint);
else
ProcessMessage( ReceivedMessage(*i), remoteEndpoint);
}
} catch (MalformedBundleException& e) {
std::cerr << "malformed OSC bundle: " << e.what() << std::endl;
}
}
void OscReceiver::ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) {
try {
ReceivedPacket p( data, size );
if(p.IsBundle()) ProcessBundle( ReceivedBundle(p), remoteEndpoint);
else ProcessMessage( ReceivedMessage(p), remoteEndpoint);
} catch (MalformedBundleException& e) {
std::cerr << "malformed OSC bundle: " << e.what() << std::endl;
}
}
bool OscReceiver::isConnected() {
return connected;
}
void OscReceiver::addTuioClient(TuioClient *client) {
clientList.push_back(client);
}

View File

@@ -0,0 +1,97 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_OSCRECEIVER_H
#define INCLUDED_OSCRECEIVER_H
#include "LibExport.h"
#include "TuioClient.h"
#include "oscpack/osc/OscReceivedElements.h"
#include "oscpack/osc/OscHostEndianness.h"
#include "oscpack/ip/PacketListener.h"
#include "oscpack/ip/IpEndpointName.h"
namespace TUIO {
class TuioClient; // Forward declaration
/**
* The OscReceiver is the base class for the various OSC transport methods such as UDP, TCP ...
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL OscReceiver: public PacketListener {
public:
/**
* The constructor is doing nothing in particular.
*/
OscReceiver() : connected(false) {};
/**
* The destructor is doing nothing in particular.
*/
virtual ~OscReceiver() {};
/**
* The OscReceiver connects and starts receiving TUIO messages via OSC
*
* @param lock running in the background if set to false (default)
*/
virtual void connect(bool lock=false) = 0;
/**
* The OscReceiver disconnects and stops receiving TUIO messages via OSC
*/
virtual void disconnect() = 0;
/**
* Returns true if this OscReceiver is currently connected.
* @return true if this OscReceiver is currently connected
*/
bool isConnected();
/**
* Attaches the provided TuioClient to this OscReceiver
*
* @param client a pointer to the TuioClient to attach
*/
void addTuioClient(TuioClient *client);
/**
* The OSC callback method where the incoming OSC data is received
*
* @param data the received OSC data
* @param size the size of the received OSC data
* @param remoteEndpoint the origin of the received OSC data
*/
void ProcessPacket( const char *data, int size, const IpEndpointName &remoteEndpoint );
protected:
void ProcessBundle( const osc::ReceivedBundle& b, const IpEndpointName& remoteEndpoint);
void ProcessMessage( const osc::ReceivedMessage& message, const IpEndpointName& remoteEndpoint);
std::list<TuioClient*> clientList;
bool connected;
};
};
#endif /* INCLUDED_OSCRECEIVER_H */

View File

@@ -0,0 +1,90 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_OSCSENDER_H
#define INCLUDED_OSCSENDER_H
#include "LibExport.h"
#include "oscpack/osc/OscOutboundPacketStream.h"
#include "oscpack/osc/OscHostEndianness.h"
#include "oscpack/ip/NetworkingUtils.h"
#include <iostream>
#include <cstring>
namespace TUIO {
/**
* The OscSender class is the base class for the various OSC transport methods such as UDP, TCP ...
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL OscSender {
public:
/**
* The constructor is doing nothing in particular.
*/
OscSender (): local(true) {};
/**
* The destructor is doing nothing in particular.
*/
virtual ~OscSender() {}
/**
* This method delivers the provided OSC data
*
* @param *bundle the OSC stream to deliver
* @return true if the data was delivered successfully
*/
virtual bool sendOscPacket (osc::OutboundPacketStream *bundle) = 0;
/**
* This method returns the connection state
*
* @return true if the connection is alive
*/
virtual bool isConnected () = 0;
/**
* This method returns if this OscSender delivers locally
*
* @return true if this OscSender delivers locally
*/
bool isLocal () { return local; };
/**
* This method returns the maximum bundle size in bytes
*
* @return the maximum bundle size in bytes
*/
int getBufferSize () { return buffer_size; };
virtual const char* tuio_type() = 0;
protected:
unsigned int buffer_size;
bool local;
};
}
#endif /* INCLUDED_OSCSENDER_H */

View File

@@ -0,0 +1,265 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TcpReceiver.h"
using namespace TUIO;
using namespace osc;
// workaround for connect method name conflict
int tcp_connect(int socket, const struct sockaddr *address, socklen_t address_len) {
return connect(socket, address, address_len);
}
#if defined (WIN32) && not defined (int32_t)
typedef DWORD int32_t;
#endif
#ifdef WIN32
static DWORD WINAPI ClientThreadFunc( LPVOID obj )
#else
static void* ClientThreadFunc( void* obj )
#endif
{
TcpReceiver *sender = static_cast<TcpReceiver*>(obj);
char data_buffer[MAX_TCP_SIZE+4];
char data_size[4];
int32_t bundle_size;
#ifdef WIN32
SOCKET client = sender->tcp_client_list.back();
#else
int client = sender->tcp_client_list.back();
#endif
int bytes = 1;
while (bytes) {
bytes = recv(client, data_buffer, sizeof(data_buffer),0);
if (bytes>=4) {
memcpy(&data_size[0],&data_buffer[0], 4);
#ifdef OSC_HOST_LITTLE_ENDIAN
bundle_size = 0xFF & data_size[3];
bundle_size |= (0xFF & data_size[2]) << 8;
bundle_size |= (0xFF & data_size[1]) << 16;
bundle_size |= (int32_t)(0xFF & data_size[0]) << 24;
#else
bundle_size = (int32_t)(*data_size);
#endif
if (bundle_size+4==bytes) {
sender->ProcessPacket(&data_buffer[4],(int)bundle_size,IpEndpointName());
}
}
}
sender->tcp_client_list.remove(client);
std::cout << "closed TUIO/TCP connection" << std::endl;
//if (sender->tcp_client_list.size()==0) sender->connected=false;
//std::cout << sender->tcp_client_list.size() << " clients left"<< std::endl;
return 0;
};
#ifndef WIN32
static void* ServerThreadFunc( void* obj )
#else
static DWORD WINAPI ServerThreadFunc( LPVOID obj )
#endif
{
TcpReceiver *sender = static_cast<TcpReceiver*>(obj);
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
while ((int)sender->tcp_socket>0) {
#ifdef WIN32
SOCKET tcp_client = -1;
#else
int tcp_client = -1;
#endif
tcp_client = accept(sender->tcp_socket, (struct sockaddr*)&client_addr, &len);
if (tcp_client>0) {
std::cout << "listening to TUIO/TCP messages from " << inet_ntoa(client_addr.sin_addr) << "@" << client_addr.sin_port << std::endl;
sender->tcp_client_list.push_back(tcp_client);
//sender->connected=true;
//std::cout << sender->tcp_client_list.size() << " clients connected"<< std::endl;
#ifndef WIN32
pthread_t client_thread;
pthread_create(&client_thread , NULL, ClientThreadFunc,obj);
#else
DWORD ClientThreadId;
HANDLE client_thread = CreateThread( 0, 0, ClientThreadFunc, obj, 0, &ClientThreadId );
#endif
} else break;
}
return 0;
};
TcpReceiver::TcpReceiver(int port)
: tcp_socket (-1)
, locked (false)
{
tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (tcp_socket < 0) std::cerr << "could not create TUIO/TCP socket" << std::endl;
int optval = 1;
#ifdef WIN32
int ret = setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR, (const char *)&optval, sizeof(int));
#else
int ret = setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR, (const void *)&optval, sizeof(int));
#endif
if (ret < 0) {
std::cerr << "could not reuse TUIO/TCP socket address" << std::endl;
return;
}
struct sockaddr_in tcp_server;
memset( &tcp_server, 0, sizeof (tcp_server));
tcp_server.sin_family = AF_INET;
tcp_server.sin_addr.s_addr = htonl(INADDR_ANY);
tcp_server.sin_port = htons(port);
socklen_t len = sizeof(tcp_server);
ret = bind(tcp_socket,(struct sockaddr*)&tcp_server,len);
if (ret < 0) {
std::cerr << "could not bind to TUIO/TCP socket on port " << port << std::endl;
return;
}
ret = listen(tcp_socket, 1);
if (ret < 0) {
std::cerr << "could not start listening to TUIO/TCP socket" << std::endl;
#ifdef WIN32
closesocket(tcp_socket);
#else
close(tcp_socket);
#endif
tcp_socket=-1;
return;
}
std::cout << "TUIO/TCP socket created on port " << port << std::endl;
}
TcpReceiver::TcpReceiver(const char *host, int port)
: tcp_socket (-1)
, locked (false)
{
tcp_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (tcp_socket < 0) {
std::cerr << "could not create TUIO/TCP socket" << std::endl;
return;
}
struct sockaddr_in tcp_server;
memset( &tcp_server, 0, sizeof (tcp_server));
unsigned long addr = inet_addr(host);
if (addr != INADDR_NONE) {
memcpy( (char *)&tcp_server.sin_addr, &addr, sizeof(addr));
} else {
struct hostent *host_info = gethostbyname(host);
if (host_info == NULL) std::cerr << "unknown host name: " << host << std::endl;
memcpy( (char *)&tcp_server.sin_addr, host_info->h_addr, host_info->h_length );
}
tcp_server.sin_family = AF_INET;
tcp_server.sin_port = htons(port);
int ret = tcp_connect(tcp_socket,(struct sockaddr*)&tcp_server,sizeof(tcp_server));
if (ret<0) {
#ifdef WIN32
closesocket(tcp_socket);
#else
close(tcp_socket);
#endif
std::cerr << "could not connect to TUIO/TCP server at " << host << ":"<< port << std::endl;
tcp_socket=-1;
return;
} else {
tcp_client_list.push_back(tcp_socket);
std::cout << "listening to TUIO/TCP messages from " << host << ":" << port << std::endl;
}
}
TcpReceiver::~TcpReceiver() {
}
void TcpReceiver::connect(bool lk) {
if (connected) return;
if ((int)tcp_socket<0) return;
locked = lk;
if (tcp_client_list.size()>0) {
if (!locked) {
#ifndef WIN32
pthread_create(&server_thread , NULL, ClientThreadFunc, this);
#else
server_thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &ServerThreadId );
#endif
} else ClientThreadFunc(this);
} else {
if (!locked) {
#ifndef WIN32
pthread_create(&server_thread , NULL, ServerThreadFunc, this);
#else
server_thread = CreateThread( 0, 0, ServerThreadFunc, this, 0, &ServerThreadId );
#endif
} else ServerThreadFunc(this);
}
connected = true;
}
void TcpReceiver::disconnect() {
if (!connected) return;
if ((int)tcp_socket<0) return;
#ifdef WIN32
for (std::list<SOCKET>::iterator client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++)
closesocket((*client));
closesocket(tcp_socket);
if( server_thread ) CloseHandle( server_thread );
#else
for (std::list<int>::iterator client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++)
close((*client));
close(tcp_socket);
server_thread = 0;
#endif
tcp_client_list.clear();
if (!locked) {
#ifdef WIN32
if( server_thread ) CloseHandle( server_thread );
#endif
server_thread = 0;
} else locked = false;
connected = false;
}

View File

@@ -0,0 +1,102 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TCPRECEIVER_H
#define INCLUDED_TCPRECEIVER_H
#include "OscReceiver.h"
#define MAX_TCP_SIZE 65536
#ifdef WIN32
#include <winsock.h>
#include <io.h>
typedef int socklen_t;
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
namespace TUIO {
/**
* The TcpReceiver provides the OscReceiver functionality for the TCP transport method
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TcpReceiver: public OscReceiver {
public:
/**
* This constructor creates a TcpReceiver instance listening to the provided TCP port
*
* @param port the number of the TCP port to listen to, defaults to 3333
*/
TcpReceiver (int port=3333);
/**
* This constructor creates a TcpReceiver connected to the provided host and TCP port
*
* @param host the host name to connect
* @param port the number of the TCP port to listen to, defaults to 3333
*/
TcpReceiver (const char *host, int port);
/**
* The destructor is doing nothing in particular.
*/
virtual ~TcpReceiver();
/**
* The TcpReceiver connects and starts receiving TUIO messages via TCP
*
* @param lock running in the background if set to false (default)
*/
void connect(bool lock=false);
/**
* The TcpReceiver disconnects and stops receiving TUIO messages via TCP
*/
void disconnect();
#ifndef WIN32
int tcp_socket;
std::list<int> tcp_client_list;
#else
SOCKET tcp_socket;
std::list<SOCKET> tcp_client_list;
#endif
private:
#ifndef WIN32
pthread_t server_thread;
#else
HANDLE server_thread;
DWORD ServerThreadId;
#endif
bool locked;
};
};
#endif /* INCLUDED_TcpReceiver_H */

View File

@@ -0,0 +1,303 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TcpSender.h"
using namespace TUIO;
#ifndef WIN32
static void* ClientThreadFunc( void* obj )
#else
static DWORD WINAPI ClientThreadFunc( LPVOID obj )
#endif
{
TcpSender *sender = static_cast<TcpSender*>(obj);
char buf[16];
#ifdef WIN32
SOCKET client = sender->tcp_client_list.back();
#else
int client = sender->tcp_client_list.back();
#endif
int connected = 1;
while (connected) {
connected = recv(client, buf, sizeof(buf),0);
}
sender->tcp_client_list.remove(client);
std::cout << sender->tuio_type() << " connection closed"<< std::endl;
if (sender->tcp_client_list.size()==0) sender->connected=false;
//std::cout << sender->tcp_client_list.size() << " clients left"<< std::endl;
return 0;
};
#ifndef WIN32
static void* ServerThreadFunc( void* obj )
#else
static DWORD WINAPI ServerThreadFunc( LPVOID obj )
#endif
{
TcpSender *sender = static_cast<TcpSender*>(obj);
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
std::cout << sender->tuio_type() << " socket created on port " << sender->port_no << std::endl;
while (sender->tcp_socket) {
#ifdef WIN32
SOCKET tcp_client = -1;
#else
int tcp_client = -1;
#endif
tcp_client = accept(sender->tcp_socket, (struct sockaddr*)&client_addr, &len);
#ifdef WIN32
//win32 workaround on exit
if (!client_addr.sin_addr.S_un.S_addr && !client_addr.sin_port) return 0;
if ((client_addr.sin_addr.S_un.S_addr==3435973836) && (client_addr.sin_port==52428)) return 0;
#endif
if (tcp_client>0) {
std::cout << sender->tuio_type() << " client connected from " << inet_ntoa(client_addr.sin_addr) << "@" << client_addr.sin_port << std::endl;
sender->tcp_client_list.push_back(tcp_client);
sender->connected=true;
sender->newClient(tcp_client);
//std::cout << sender->tcp_client_list.size() << " clients connected"<< std::endl;
#ifndef WIN32
pthread_t client_thread;
pthread_create(&client_thread , NULL, ClientThreadFunc,obj);
#else
DWORD ClientThreadId;
HANDLE client_thread = CreateThread( 0, 0, ClientThreadFunc, obj, 0, &ClientThreadId );
#endif
} else break;
}
return 0;
};
TcpSender::TcpSender()
:connected (false)
{
local = true;
buffer_size = MAX_TCP_SIZE;
tcp_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if (tcp_socket < 0) {
std::cerr << "could not create " << tuio_type() << " socket" << std::endl;
return;
}
struct sockaddr_in tcp_server;
memset( &tcp_server, 0, sizeof (tcp_server));
//unsigned long addr = inet_addr("127.0.0.1");
//memcpy( (char *)&tcp_server.sin_addr, &addr, sizeof(addr));
tcp_server.sin_family = AF_INET;
tcp_server.sin_port = htons(3333);
tcp_server.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = connect(tcp_socket,(struct sockaddr*)&tcp_server,sizeof(tcp_server));
if (ret<0) {
std::cerr << "could not open " << tuio_type() << " connection to 127.0.0.1:3333" << std::endl;
return;
} else {
std::cout << tuio_type() << " connection opened to 127.0.0.1:3333" << std::endl;
tcp_client_list.push_back(tcp_socket);
connected = true;
#ifndef WIN32
pthread_create(&server_thread , NULL, ClientThreadFunc,this);
#else
HANDLE server_thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &ServerThreadId );
#endif
}
}
TcpSender::TcpSender(const char *host, int port)
:connected (false)
{
if ((strcmp(host,"127.0.0.1")==0) || (strcmp(host,"localhost")==0)) {
local = true;
} else local = false;
buffer_size = MAX_TCP_SIZE;
tcp_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if (tcp_socket < 0) {
std::cerr << "could not create " << tuio_type() << " socket" << std::endl;
return;
}
struct sockaddr_in tcp_server;
memset( &tcp_server, 0, sizeof (tcp_server));
unsigned long addr = inet_addr(host);
if (addr != INADDR_NONE) {
memcpy( (char *)&tcp_server.sin_addr, &addr, sizeof(addr));
} else {
struct hostent *host_info = gethostbyname(host);
if (host_info == NULL) {
std::cerr << "unknown host name: " << host << std::endl;
throw std::exception();
}
memcpy( (char *)&tcp_server.sin_addr, host_info->h_addr, host_info->h_length );
}
tcp_server.sin_family = AF_INET;
tcp_server.sin_port = htons(port);
int ret = connect(tcp_socket,(struct sockaddr*)&tcp_server,sizeof(tcp_server));
if (ret<0) {
#ifdef WIN32
closesocket(tcp_socket);
#else
close(tcp_socket);
#endif
std::cerr << "could not open " << tuio_type() << " connection to " << host << ":"<< port << std::endl;
throw std::exception();
} else {
std::cout << tuio_type() << " connection opened to " << host << ":"<< port << std::endl;
tcp_client_list.push_back(tcp_socket);
connected = true;
#ifndef WIN32
pthread_create(&server_thread , NULL, ClientThreadFunc,this);
#else
HANDLE server_thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &ServerThreadId );
#endif
}
}
TcpSender::TcpSender(int port)
:connected (false)
{
local = false;
buffer_size = MAX_TCP_SIZE;
port_no = port;
tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (tcp_socket < 0) {
std::cerr << "could not create TUIO/TCP socket" << std::endl;
throw std::exception();
}
int optval = 1;
#ifdef WIN32
int ret = setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR, (const char *)&optval, sizeof(int));
#else
int ret = setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR, (const void *)&optval, sizeof(int));
#endif
if (ret < 0) {
std::cerr << "could not reuse TUIO/TCP socket address" << std::endl;
throw std::exception();
}
struct sockaddr_in tcp_server;
memset( &tcp_server, 0, sizeof (tcp_server));
tcp_server.sin_family = AF_INET;
tcp_server.sin_addr.s_addr = htonl(INADDR_ANY);
tcp_server.sin_port = htons(port);
socklen_t len = sizeof(tcp_server);
ret = bind(tcp_socket,(struct sockaddr*)&tcp_server,len);
if (ret < 0) {
std::cerr << "could not bind to TUIO/TCP socket on port " << port << std::endl;
throw std::exception();
}
ret = listen(tcp_socket, 1);
if (ret < 0) {
std::cerr << "could not start listening to TUIO/TCP socket" << std::endl;
#ifdef WIN32
closesocket(tcp_socket);
#else
close(tcp_socket);
#endif
throw std::exception();
}
#ifndef WIN32
pthread_create(&server_thread , NULL, ServerThreadFunc, this);
#else
DWORD ServerThreadId;
server_thread = CreateThread( 0, 0, ServerThreadFunc, this, 0, &ServerThreadId );
#endif
}
bool TcpSender::isConnected() {
return connected;
}
TcpSender::~TcpSender() {
#ifdef WIN32
for (std::list<SOCKET>::iterator client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++) {
closesocket((*client));
}
closesocket(tcp_socket);
if( server_thread ) CloseHandle( server_thread );
#else
for (std::list<int>::iterator client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++) {
close((*client));
}
close(tcp_socket);
tcp_socket = 0;
server_thread = 0;
#endif
}
bool TcpSender::sendOscPacket (osc::OutboundPacketStream *bundle) {
if (!connected) return false;
if ( bundle->Size() > buffer_size ) return false;
if ( bundle->Size() == 0 ) return false;
#ifdef OSC_HOST_LITTLE_ENDIAN
data_size[0] = bundle->Size()>>24;
data_size[1] = (bundle->Size()>>16) & 255;
data_size[2] = (bundle->Size()>>8) & 255;
data_size[3] = (bundle->Size()) & 255;
#else
*((int32_t*)data_size) = bundle->Size();
#endif
#ifdef WIN32
std::list<SOCKET>::iterator client;
#else
std::list<int>::iterator client;
#endif
for (client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++) {
//send((*client), data_size, 4,0);
//send((*client), bundle->Data(), bundle->Size(),0);
memcpy(&data_buffer[0], &data_size, 4);
memcpy(&data_buffer[4], bundle->Data(), bundle->Size());
send((*client),data_buffer, 4+bundle->Size(),0);
}
return true;
}
void TcpSender::newClient( int tcp_client ) { }

View File

@@ -0,0 +1,126 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TCPSENDER_H
#define INCLUDED_TCPSENDER_H
#include "OscSender.h"
#ifdef WIN32
#include <winsock.h>
#include <io.h>
typedef int socklen_t;
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include <list>
#define MAX_TCP_SIZE 65536
namespace TUIO {
/**
* The TcpSender implements the TCP transport method for OSC
*
* @author Martin Kaltenbrunner
* @version 2.0.a0
*/
class LIBDECL TcpSender : public OscSender {
public:
/**
* The default constructor creates a TcpSender that sends to the default TUIO port 3333 on localhost
*/
TcpSender();
/**
* This constructor creates a TcpSender that sends to the provided port on the the given host
*
* @param host the receiving host name
* @param port the outgoing TUIO TCP port number
*/
TcpSender(const char *host, int port);
/**
* This constructor creates a TcpSender that listens to the provided port
*
* @param port the incoming TUIO TCP port number
*/
TcpSender(int port);
/**
* The destructor closes the socket.
*/
virtual ~TcpSender();
/**
* This method delivers the provided OSC data
*
* @param *bundle the OSC stream to deliver
* @return true if the data was delivered successfully
*/
bool sendOscPacket (osc::OutboundPacketStream *bundle);
/**
* This method returns the connection state
*
* @return true if the connection is alive
*/
bool isConnected ();
/**
* This method is called whenever a new client connects
*
* @param tcp_client the socket handle of the new client
*/
virtual void newClient( int tcp_client );
int port_no;
#ifdef WIN32
SOCKET tcp_socket;
std::list<SOCKET> tcp_client_list;
#else
int tcp_socket;
std::list<int> tcp_client_list;
#endif
bool connected;
const char* tuio_type() { return "TUIO/TCP"; }
protected:
char data_size[4];
char data_buffer[MAX_TCP_SIZE+4];
#ifdef WIN32
HANDLE server_thread;
DWORD ServerThreadId;
#else
pthread_t server_thread;
#endif
};
}
#endif /* INCLUDED_TCPSENDER_H */

View File

@@ -0,0 +1,253 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TuioBlob.h"
using namespace TUIO;
TuioBlob::TuioBlob (TuioTime ttime, long si, int bi, float xp, float yp, float a, float w, float h, float f):TuioContainer(ttime, si, xp, yp) {
blob_id = bi;
angle = a;
angle_sum = a;
width = w;
height = h;
area = f;
rotation_speed = 0.0f;
rotation_accel = 0.0f;
angleFilter = NULL;
angleThreshold = 0.0f;
widthFilter = NULL;
heightFilter = NULL;
sizeThreshold = 0.0f;
}
TuioBlob::TuioBlob (long si, int bi, float xp, float yp, float a, float w, float h, float f):TuioContainer(si, xp, yp) {
blob_id = bi;
angle = a;
angle_sum = a;
width = w;
height = h;
area = f;
rotation_speed = 0.0f;
rotation_accel = 0.0f;
angleFilter = NULL;
angleThreshold = 0.0f;
widthFilter = NULL;
heightFilter = NULL;
sizeThreshold = 0.0f;
}
TuioBlob::TuioBlob (TuioBlob *tblb):TuioContainer(tblb) {
blob_id = tblb->getBlobID();
angle = tblb->getAngle();
angle_sum = tblb->getAngleSum();
width = tblb->getWidth();
height = tblb->getHeight();
area = tblb->getArea();
rotation_speed = 0.0f;
rotation_accel = 0.0f;
angleFilter = NULL;
angleThreshold = 0.0f;
widthFilter = NULL;
heightFilter = NULL;
sizeThreshold = 0.0f;
}
int TuioBlob::getBlobID() const{
return blob_id;
}
void TuioBlob::setBlobID(long b_id) {
blob_id = b_id;
}
void TuioBlob::update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra) {
TuioContainer::update(ttime,xp,yp,xs,ys,ma);
angle = a;
angle_sum = a;
width = w;
height = h;
area = f;
rotation_speed = rs;
rotation_accel = ra;
if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING;
}
void TuioBlob::update (float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra) {
TuioContainer::update(xp,yp,xs,ys,ma);
angle = a;
angle_sum = a;
width = w;
height = h;
area = f;
rotation_speed = rs;
rotation_accel = ra;
if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING;
}
void TuioBlob::update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f) {
TuioPoint lastPoint = path.back();
TuioContainer::update(ttime,xp,yp);
TuioTime diffTime = currentTime - lastPoint.getTuioTime();
float dt = diffTime.getTotalMilliseconds()/1000.0f;
float last_rotation_speed = rotation_speed;
float prev_angle = angle_sum;
float da = a-angle;
if (da > M_PI/2.0f) angle_sum += (da-2*M_PI);
else if (da < M_PI/-2.0f) angle_sum += (da+2*M_PI);
else angle_sum += da;
if (angleFilter) angle_sum = angleFilter->filter(angle_sum,dt);
if (fabs(angle_sum-prev_angle)<angleThreshold) angle_sum = prev_angle;
int m = floor(angle_sum/(2*M_PI));
angle = angle_sum-(m*(2*M_PI));
da = (angle-a)/(2*M_PI);
if (da > 0.75f) da-=1.0f;
else if (da < -0.75f) da+=1.0f;
if (widthFilter && heightFilter) {
w = widthFilter->filter(w,dt);
h = heightFilter->filter(h,dt);
}
float dw = fabs(width - w);
float dh = fabs(height - h);
if ((dw>sizeThreshold) || (dh>sizeThreshold)) {
width = w;
height = h;
}
area = f;
rotation_speed = (float)da/dt;
rotation_accel = (rotation_speed - last_rotation_speed)/dt;
if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING;
}
void TuioBlob::stop (TuioTime ttime) {
update(ttime,xpos,ypos,angle,width,height,area);
}
void TuioBlob::update (TuioBlob *tblb) {
TuioContainer::update(tblb);
angle = tblb->getAngle();
angle = tblb->getAngleSum();
width = tblb->getWidth();
height = tblb->getHeight();
area = tblb->getArea();
rotation_speed = tblb->getRotationSpeed();
rotation_accel = tblb->getRotationAccel();
if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING;
}
float TuioBlob::getWidth() const{
return width;
}
float TuioBlob::getHeight() const{
return height;
}
int TuioBlob::getScreenWidth(int w) const{
return (int)(w*width);
}
int TuioBlob::getScreenHeight(int h) const{
return (int)(h*height);
}
float TuioBlob::getArea() const{
return area;
}
float TuioBlob::getAngle() const{
return angle;
}
float TuioBlob::getAngleSum() const{
return angle_sum;
}
float TuioBlob::getAngleDegrees() const{
return (float)(angle/M_PI*180);
}
float TuioBlob::getRotationSpeed() const{
return rotation_speed;
}
float TuioBlob::getRotationAccel() const{
return rotation_accel;
}
bool TuioBlob::isMoving() const{
if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING) || (state==TUIO_ROTATING)) return true;
else return false;
}
void TuioBlob::addAngleThreshold(float thresh) {
angleThreshold = thresh;
}
void TuioBlob::removeAngleThreshold() {
angleThreshold = 0.0f;
}
void TuioBlob::addAngleFilter(float mcut, float beta) {
if (angleFilter) delete angleFilter;
angleFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f);
}
void TuioBlob::removeAngleFilter() {
if (angleFilter) delete angleFilter;
angleFilter = NULL;
}
void TuioBlob::addSizeThreshold(float thresh) {
sizeThreshold = thresh;
}
void TuioBlob::removeSizeThreshold() {
sizeThreshold = 0.0f;
}
void TuioBlob::addSizeFilter(float mcut, float beta) {
if (widthFilter) delete widthFilter;
widthFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f);
if (heightFilter) delete heightFilter;
heightFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f);
}
void TuioBlob::removeSizeFilter() {
if (widthFilter) delete widthFilter;
widthFilter = NULL;
if (heightFilter) delete heightFilter;
heightFilter = NULL;
}

View File

@@ -0,0 +1,287 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TUIOBLOB_H
#define INCLUDED_TUIOBLOB_H
#include "TuioContainer.h"
namespace TUIO {
/**
* The TuioBlob class encapsulates /tuio/2Dblb TUIO objects.
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TuioBlob: public TuioContainer {
protected:
/**
* The individual blob ID number that is assigned to each TuioBlob.
*/
int blob_id;
/**
* The rotation angle value.
*/
float angle;
/**
* The accumulated angle value.
*/
float angle_sum;
/**
* The width value.
*/
float width;
/**
* The height value.
*/
float height;
/**
* The area value.
*/
float area;
/**
* The rotation speed value.
*/
float rotation_speed;
/**
* The rotation acceleration value.
*/
float rotation_accel;
float angleThreshold;
OneEuroFilter *angleFilter;
float sizeThreshold;
OneEuroFilter *widthFilter;
OneEuroFilter *heightFilter;
public:
using TuioContainer::update;
/**
* This constructor takes a TuioTime argument and assigns it along with the provided
* Session ID, X and Y coordinate, width, height and angle to the newly created TuioBlob.
*
* @param ttime the TuioTime to assign
* @param si the Session ID to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the angle to assign
* @param w the width to assign
* @param h the height to assign
* @param f the area to assign
*/
TuioBlob (TuioTime ttime, long si, int bi, float xp, float yp, float a, float w, float h, float f);
/**
* This constructor takes the provided Session ID, X and Y coordinate
* width, height and angle, and assigs these values to the newly created TuioBlob.
*
* @param si the Session ID to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the angle to assign
* @param w the width to assign
* @param h the height to assign
* @param f the area to assign
*/
TuioBlob (long si, int bi, float xp, float yp, float a, float w, float h, float f);
/**
* This constructor takes the atttibutes of the provided TuioBlob
* and assigs these values to the newly created TuioBlob.
*
* @param tblb the TuioBlob to assign
*/
TuioBlob (TuioBlob *tblb);
/**
* The destructor is doing nothing in particular.
*/
virtual ~TuioBlob() {
if (widthFilter) delete widthFilter;
if (heightFilter) delete heightFilter;
if (angleFilter) delete angleFilter;
};
/**
* Returns the Blob ID of this TuioBlob.
* @return the Blob ID of this TuioBlob
*/
int getBlobID() const;
/**
* Sets the Blob ID of this TuioBlob.
* @param b_id the new Blob ID for this TuioBlob
*/
void setBlobID(long b_id);
/**
* Takes a TuioTime argument and assigns it along with the provided
* X and Y coordinate, angle, X and Y velocity, motion acceleration,
* rotation speed and rotation acceleration to the private TuioBlob attributes.
*
* @param ttime the TuioTime to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the rotation angle to assign
* @param w the width to assign
* @param h the height to assign
* @param f the area to assign
* @param xs the X velocity to assign
* @param ys the Y velocity to assign
* @param rs the rotation velocity to assign
* @param ma the motion acceleration to assign
* @param ra the rotation acceleration to assign
*/
void update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra);
/**
* Assigns the provided X and Y coordinate, angle, X and Y velocity, motion acceleration
* rotation velocity and rotation acceleration to the private TuioContainer attributes.
* The TuioTime time stamp remains unchanged.
*
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the angle to assign
* @param w the width to assign
* @param h the height to assign
* @param f the area to assign
* @param xs the X velocity to assign
* @param ys the Y velocity to assign
* @param rs the rotation velocity to assign
* @param ma the motion acceleration to assign
* @param ra the rotation acceleration to assign
*/
void update (float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra);
/**
* Takes a TuioTime argument and assigns it along with the provided
* X and Y coordinate and angle to the private TuioBlob attributes.
* The speed and accleration values are calculated accordingly.
*
* @param ttime the TuioTime to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the angle coordinate to assign
* @param w the width to assign
* @param h the height to assign
* @param f the area to assign
*/
void update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f);
/**
* This method is used to calculate the speed and acceleration values of a
* TuioBlob with unchanged position and angle.
*/
void stop (TuioTime ttime);
/**
* Takes the atttibutes of the provided TuioBlob
* and assigs these values to this TuioBlob.
* The TuioTime time stamp of this TuioContainer remains unchanged.
*
* @param tblb the TuioContainer to assign
*/
void update (TuioBlob *tblb);
/**
* Returns the width of this TuioBlob.
* @return the width of this TuioBlob
*/
float getWidth() const;
/**
* Returns the height of this TuioBlob.
* @return the height of this TuioBlob
*/
float getHeight() const;
/**
* Returns the width of this TuioBlob.
* @return the width of this TuioBlob
*/
int getScreenWidth(int w) const;
/**
* Returns the height of this TuioBlob.
* @return the height of this TuioBlob
*/
int getScreenHeight(int h) const;
/**
* Returns the area of this TuioBlob.
* @return the area of this TuioBlob
*/
float getArea() const;
/**
* Returns the rotation angle of this TuioBlob.
* @return the rotation angle of this TuioBlob
*/
float getAngle() const;
/**
* Returns the accumulated rotation angle of this TuioBlob.
* @return the accumulated rotation angle of this TuioBlob
*/
float getAngleSum() const;
/**
* Returns the rotation angle in degrees of this TuioBlob.
* @return the rotation angle in degrees of this TuioBlob
*/
float getAngleDegrees() const;
/**
* Returns the rotation speed of this TuioBlob.
* @return the rotation speed of this TuioBlob
*/
float getRotationSpeed() const;
/**
* Returns the rotation acceleration of this TuioBlob.
* @return the rotation acceleration of this TuioBlob
*/
float getRotationAccel() const;
/**
* Returns true of this TuioBlob is moving.
* @return true of this TuioBlob is moving
*/
bool isMoving() const;
void addAngleThreshold(float thresh);
void removeAngleThreshold();
void addAngleFilter(float mcut, float beta);
void removeAngleFilter();
void addSizeThreshold(float thresh);
void removeSizeThreshold();
void addSizeFilter(float mcut, float beta);
void removeSizeFilter();
};
}
#endif

View File

@@ -0,0 +1,849 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TuioClient.h"
#include "UdpReceiver.h"
using namespace TUIO;
using namespace osc;
TuioClient::TuioClient()
: currentFrame (-1)
, source_id (0)
, source_name (NULL)
, source_addr (NULL)
, local_receiver(true)
{
receiver = new UdpReceiver();
initialize();
}
TuioClient::TuioClient(int port)
: currentFrame (-1)
, source_id (0)
, source_name (NULL)
, source_addr (NULL)
, local_receiver(true)
{
receiver = new UdpReceiver(port);
initialize();
}
TuioClient::TuioClient(OscReceiver *osc)
: currentFrame (-1)
, source_id (0)
, source_name (NULL)
, source_addr (NULL)
, receiver (osc)
, local_receiver(false)
{
initialize();
}
void TuioClient::initialize() {
receiver->addTuioClient(this);
maxCursorID[source_id] = -1;
maxBlobID[source_id] = -1;
}
TuioClient::~TuioClient() {
if (local_receiver) delete receiver;
}
void TuioClient::processOSC( const ReceivedMessage& msg ) {
try {
ReceivedMessageArgumentStream args = msg.ArgumentStream();
//ReceivedMessage::const_iterator arg = msg.ArgumentsBegin();
if( strcmp( msg.AddressPattern(), "/tuio/2Dobj" ) == 0 ){
const char* cmd;
args >> cmd;
if (strcmp(cmd,"source")==0) {
const char* src;
args >> src;
source_name = strtok((char*)src, "@");
char *addr = strtok(NULL, "@");
if (addr!=NULL) source_addr = addr;
else source_addr = (char*)"localhost";
// check if we know that source
std::string source_str(src);
std::map<std::string,int>::iterator iter = sourceList.find(source_str);
// add a new source
if (iter==sourceList.end()) {
source_id = sourceList.size();
sourceList[source_str] = source_id;
} else {
// use the found source_id
source_id = sourceList[source_str];
}
} else if (strcmp(cmd,"set")==0) {
int32 s_id, c_id;
float xpos, ypos, angle, xspeed, yspeed, rspeed, maccel, raccel;
args >> s_id >> c_id >> xpos >> ypos >> angle >> xspeed >> yspeed >> rspeed >> maccel >> raccel;
lockObjectList();
std::list<TuioObject*>::iterator tobj;
for (tobj=objectList.begin(); tobj!= objectList.end(); tobj++)
if((*tobj)->getSessionID()==(long)s_id) break;
if (tobj == objectList.end()) {
TuioObject *addObject = new TuioObject((long)s_id,(int)c_id,xpos,ypos,angle);
frameObjects.push_back(addObject);
} else if ( ((*tobj)->getX()!=xpos) || ((*tobj)->getY()!=ypos) || ((*tobj)->getAngle()!=angle) || ((*tobj)->getXSpeed()!=xspeed) || ((*tobj)->getYSpeed()!=yspeed) || ((*tobj)->getRotationSpeed()!=rspeed) || ((*tobj)->getMotionAccel()!=maccel) || ((*tobj)->getRotationAccel()!=raccel) ) {
TuioObject *updateObject = new TuioObject((long)s_id,(*tobj)->getSymbolID(),xpos,ypos,angle);
updateObject->update(xpos,ypos,angle,xspeed,yspeed,rspeed,maccel,raccel);
frameObjects.push_back(updateObject);
}
unlockObjectList();
} else if (strcmp(cmd,"alive")==0) {
int32 s_id;
aliveObjectList.clear();
while(!args.Eos()) {
args >> s_id;
aliveObjectList.push_back((long)s_id);
}
} else if (strcmp(cmd,"fseq")==0) {
int32 fseq;
args >> fseq;
bool lateFrame = false;
if (fseq>0) {
if (fseq>currentFrame) currentTime = TuioTime::getSessionTime();
if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq;
else lateFrame = true;
} else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) {
currentTime = TuioTime::getSessionTime();
}
if (!lateFrame) {
lockObjectList();
//find the removed objects first
for (std::list<TuioObject*>::iterator tobj=objectList.begin(); tobj != objectList.end(); tobj++) {
if ((*tobj)->getTuioSourceID()==source_id) {
std::list<long>::iterator iter = find(aliveObjectList.begin(), aliveObjectList.end(), (*tobj)->getSessionID());
if (iter == aliveObjectList.end()) {
(*tobj)->remove(currentTime);
frameObjects.push_back(*tobj);
}
}
}
unlockObjectList();
for (std::list<TuioObject*>::iterator iter=frameObjects.begin(); iter != frameObjects.end(); iter++) {
TuioObject *tobj = (*iter);
TuioObject *frameObject = NULL;
switch (tobj->getTuioState()) {
case TUIO_REMOVED:
frameObject = tobj;
frameObject->remove(currentTime);
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->removeTuioObject(frameObject);
lockObjectList();
for (std::list<TuioObject*>::iterator delobj=objectList.begin(); delobj!=objectList.end(); delobj++) {
if((*delobj)->getSessionID()==frameObject->getSessionID()) {
objectList.erase(delobj);
break;
}
}
unlockObjectList();
break;
case TUIO_ADDED:
lockObjectList();
frameObject = new TuioObject(currentTime,tobj->getSessionID(),tobj->getSymbolID(),tobj->getX(),tobj->getY(),tobj->getAngle());
if (source_name) frameObject->setTuioSource(source_id,source_name,source_addr);
objectList.push_back(frameObject);
unlockObjectList();
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->addTuioObject(frameObject);
break;
default:
lockObjectList();
std::list<TuioObject*>::iterator iter;
for (iter=objectList.begin(); iter != objectList.end(); iter++) {
if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getSessionID()==tobj->getSessionID())) {
frameObject = (*iter);
break;
}
}
if (iter==objectList.end()) {
unlockObjectList();
break;
}
if ( (tobj->getX()!=frameObject->getX() && tobj->getXSpeed()==0) || (tobj->getY()!=frameObject->getY() && tobj->getYSpeed()==0) )
frameObject->update(currentTime,tobj->getX(),tobj->getY(),tobj->getAngle());
else
frameObject->update(currentTime,tobj->getX(),tobj->getY(),tobj->getAngle(),tobj->getXSpeed(),tobj->getYSpeed(),tobj->getRotationSpeed(),tobj->getMotionAccel(),tobj->getRotationAccel());
unlockObjectList();
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->updateTuioObject(frameObject);
}
delete tobj;
}
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->refresh(currentTime);
} else {
for (std::list<TuioObject*>::iterator iter=frameObjects.begin(); iter != frameObjects.end(); iter++) {
TuioObject *tobj = (*iter);
delete tobj;
}
}
frameObjects.clear();
}
} else if( strcmp( msg.AddressPattern(), "/tuio/2Dcur" ) == 0 ) {
const char* cmd;
args >> cmd;
if (strcmp(cmd,"source")==0) {
const char* src;
args >> src;
source_name = strtok((char*)src, "@");
char *addr = strtok(NULL, "@");
if (addr!=NULL) source_addr = addr;
else source_addr = (char*)"localhost";
// check if we know that source
std::string source_str(src);
std::map<std::string,int>::iterator iter = sourceList.find(source_str);
// add a new source
if (iter==sourceList.end()) {
source_id = sourceList.size();
sourceList[source_str] = source_id;
maxCursorID[source_id] = -1;
} else {
// use the found source_id
source_id = sourceList[source_str];
}
} else if (strcmp(cmd,"set")==0) {
int32 s_id;
float xpos, ypos, xspeed, yspeed, maccel;
args >> s_id >> xpos >> ypos >> xspeed >> yspeed >> maccel;
lockCursorList();
std::list<TuioCursor*>::iterator tcur;
for (tcur=cursorList.begin(); tcur!= cursorList.end(); tcur++)
if (((*tcur)->getSessionID()==(long)s_id) && ((*tcur)->getTuioSourceID()==source_id)) break;
if (tcur==cursorList.end()) {
TuioCursor *addCursor = new TuioCursor((long)s_id,-1,xpos,ypos);
frameCursors.push_back(addCursor);
} else if ( ((*tcur)->getX()!=xpos) || ((*tcur)->getY()!=ypos) || ((*tcur)->getXSpeed()!=xspeed) || ((*tcur)->getYSpeed()!=yspeed) || ((*tcur)->getMotionAccel()!=maccel) ) {
TuioCursor *updateCursor = new TuioCursor((long)s_id,(*tcur)->getCursorID(),xpos,ypos);
updateCursor->update(xpos,ypos,xspeed,yspeed,maccel);
frameCursors.push_back(updateCursor);
}
unlockCursorList();
} else if (strcmp(cmd,"alive")==0) {
int32 s_id;
aliveCursorList.clear();
while(!args.Eos()) {
args >> s_id;
aliveCursorList.push_back((long)s_id);
}
} else if( strcmp( cmd, "fseq" ) == 0 ) {
int32 fseq;
args >> fseq;
bool lateFrame = false;
if (fseq>0) {
if (fseq>currentFrame) currentTime = TuioTime::getSessionTime();
if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq;
else lateFrame = true;
} else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) {
currentTime = TuioTime::getSessionTime();
}
if (!lateFrame) {
lockCursorList();
// find the removed cursors first
for (std::list<TuioCursor*>::iterator tcur=cursorList.begin(); tcur != cursorList.end(); tcur++) {
if ((*tcur)->getTuioSourceID()==source_id) {
std::list<long>::iterator iter = find(aliveCursorList.begin(), aliveCursorList.end(), (*tcur)->getSessionID());
if (iter == aliveCursorList.end()) {
(*tcur)->remove(currentTime);
frameCursors.push_back(*tcur);
}
}
}
unlockCursorList();
for (std::list<TuioCursor*>::iterator iter=frameCursors.begin(); iter != frameCursors.end(); iter++) {
TuioCursor *tcur = (*iter);
int c_id = 0;
int free_size = 0;
TuioCursor *frameCursor = NULL;
switch (tcur->getTuioState()) {
case TUIO_REMOVED:
frameCursor = tcur;
frameCursor->remove(currentTime);
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->removeTuioCursor(frameCursor);
lockCursorList();
for (std::list<TuioCursor*>::iterator delcur=cursorList.begin(); delcur!=cursorList.end(); delcur++) {
if(((*delcur)->getTuioSourceID()==source_id) && ((*delcur)->getSessionID()==frameCursor->getSessionID())) {
cursorList.erase(delcur);
break;
}
}
if (frameCursor->getCursorID()==maxCursorID[source_id]) {
maxCursorID[source_id] = -1;
delete frameCursor;
if (cursorList.size()>0) {
std::list<TuioCursor*>::iterator clist;
for (clist=cursorList.begin(); clist != cursorList.end(); clist++) {
if ((*clist)->getTuioSourceID()==source_id) {
c_id = (*clist)->getCursorID();
if (c_id>maxCursorID[source_id]) maxCursorID[source_id]=c_id;
}
}
freeCursorBuffer.clear();
for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
TuioCursor *freeCursor = (*flist);
if (freeCursor->getTuioSourceID()==source_id) {
if (freeCursor->getCursorID()>maxCursorID[source_id]) delete freeCursor;
else freeCursorBuffer.push_back(freeCursor);
} else freeCursorBuffer.push_back(freeCursor);
}
freeCursorList = freeCursorBuffer;
} else {
freeCursorBuffer.clear();
for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
TuioCursor *freeCursor = (*flist);
if (freeCursor->getTuioSourceID()==source_id) delete freeCursor;
else freeCursorBuffer.push_back(freeCursor);
}
freeCursorList = freeCursorBuffer;
}
} else if (frameCursor->getCursorID()<maxCursorID[source_id]) {
freeCursorList.push_back(frameCursor);
}
unlockCursorList();
break;
case TUIO_ADDED:
lockCursorList();
for(std::list<TuioCursor*>::iterator iter = cursorList.begin();iter!= cursorList.end(); iter++)
if ((*iter)->getTuioSourceID()==source_id) c_id++;
for(std::list<TuioCursor*>::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++)
if ((*iter)->getTuioSourceID()==source_id) free_size++;
if ((free_size<=maxCursorID[source_id]) && (free_size>0)) {
std::list<TuioCursor*>::iterator closestCursor = freeCursorList.begin();
for(std::list<TuioCursor*>::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) {
if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getDistance(tcur)<(*closestCursor)->getDistance(tcur))) closestCursor = iter;
}
if (closestCursor!=freeCursorList.end()) {
TuioCursor *freeCursor = (*closestCursor);
c_id = freeCursor->getCursorID();
freeCursorList.erase(closestCursor);
delete freeCursor;
}
} else maxCursorID[source_id] = c_id;
frameCursor = new TuioCursor(currentTime,tcur->getSessionID(),c_id,tcur->getX(),tcur->getY());
if (source_name) frameCursor->setTuioSource(source_id,source_name,source_addr);
cursorList.push_back(frameCursor);
delete tcur;
unlockCursorList();
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->addTuioCursor(frameCursor);
break;
default:
lockCursorList();
std::list<TuioCursor*>::iterator iter;
for (iter=cursorList.begin(); iter != cursorList.end(); iter++) {
if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getSessionID()==tcur->getSessionID())) {
frameCursor = (*iter);
break;
}
}
if (iter==cursorList.end()) {
unlockCursorList();
break;
}
if ( (tcur->getX()!=frameCursor->getX() && tcur->getXSpeed()==0) || (tcur->getY()!=frameCursor->getY() && tcur->getYSpeed()==0) )
frameCursor->update(currentTime,tcur->getX(),tcur->getY());
else
frameCursor->update(currentTime,tcur->getX(),tcur->getY(),tcur->getXSpeed(),tcur->getYSpeed(),tcur->getMotionAccel());
delete tcur;
unlockCursorList();
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->updateTuioCursor(frameCursor);
}
}
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->refresh(currentTime);
} else {
for (std::list<TuioCursor*>::iterator iter=frameCursors.begin(); iter != frameCursors.end(); iter++) {
TuioCursor *tcur = (*iter);
delete tcur;
}
}
frameCursors.clear();
}
} else if( strcmp( msg.AddressPattern(), "/tuio/2Dblb" ) == 0 ){
const char* cmd;
args >> cmd;
if (strcmp(cmd,"source")==0) {
const char* src;
args >> src;
source_name = strtok((char*)src, "@");
char *addr = strtok(NULL, "@");
if (addr!=NULL) source_addr = addr;
else source_addr = (char*)"localhost";
// check if we know that source
std::string source_str(src);
std::map<std::string,int>::iterator iter = sourceList.find(source_str);
// add a new source
if (iter==sourceList.end()) {
source_id = sourceList.size();
sourceList[source_str] = source_id;
maxBlobID[source_id] = -1;
} else {
// use the found source_id
source_id = sourceList[source_str];
}
} else if (strcmp(cmd,"set")==0) {
int32 s_id;
float xpos, ypos, angle, width, height, area, xspeed, yspeed, rspeed, maccel, raccel;
args >> s_id >> xpos >> ypos >> angle >> width >> height >> area >> xspeed >> yspeed >> rspeed >> maccel >> raccel;
lockBlobList();
std::list<TuioBlob*>::iterator tblb;
for (tblb=blobList.begin(); tblb!= blobList.end(); tblb++)
if((*tblb)->getSessionID()==(long)s_id) break;
if (tblb==blobList.end()) {
TuioBlob *addBlob = new TuioBlob((long)s_id,-1,xpos,ypos,angle,width,height,area);
frameBlobs.push_back(addBlob);
} else if ( ((*tblb)->getX()!=xpos) || ((*tblb)->getY()!=ypos) || ((*tblb)->getAngle()!=angle) || ((*tblb)->getWidth()!=width) || ((*tblb)->getHeight()!=height) || ((*tblb)->getArea()!=area) || ((*tblb)->getXSpeed()!=xspeed) || ((*tblb)->getYSpeed()!=yspeed) || ((*tblb)->getMotionAccel()!=maccel) ) {
TuioBlob *updateBlob = new TuioBlob((long)s_id,(*tblb)->getBlobID(),xpos,ypos,angle,width,height,area);
updateBlob->update(xpos,ypos,angle,width,height,area,xspeed,yspeed,rspeed,maccel,raccel);
frameBlobs.push_back(updateBlob);
}
unlockBlobList();
} else if (strcmp(cmd,"alive")==0) {
int32 s_id;
aliveBlobList.clear();
while(!args.Eos()) {
args >> s_id;
aliveBlobList.push_back((long)s_id);
}
} else if( strcmp( cmd, "fseq" ) == 0 ) {
int32 fseq;
args >> fseq;
bool lateFrame = false;
if (fseq>0) {
if (fseq>currentFrame) currentTime = TuioTime::getSessionTime();
if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq;
else lateFrame = true;
} else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) {
currentTime = TuioTime::getSessionTime();
}
if (!lateFrame) {
lockBlobList();
// find the removed blobs first
for (std::list<TuioBlob*>::iterator tblb=blobList.begin(); tblb != blobList.end(); tblb++) {
if ((*tblb)->getTuioSourceID()==source_id) {
std::list<long>::iterator iter = find(aliveBlobList.begin(), aliveBlobList.end(), (*tblb)->getSessionID());
if (iter == aliveBlobList.end()) {
(*tblb)->remove(currentTime);
frameBlobs.push_back(*tblb);
}
}
}
unlockBlobList();
for (std::list<TuioBlob*>::iterator iter=frameBlobs.begin(); iter != frameBlobs.end(); iter++) {
TuioBlob *tblb = (*iter);
int b_id = 0;
int free_size = 0;
TuioBlob *frameBlob = NULL;
switch (tblb->getTuioState()) {
case TUIO_REMOVED:
frameBlob = tblb;
frameBlob->remove(currentTime);
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->removeTuioBlob(frameBlob);
lockBlobList();
for (std::list<TuioBlob*>::iterator delblb=blobList.begin(); delblb!=blobList.end(); delblb++) {
if(((*delblb)->getTuioSourceID()==source_id) && ((*delblb)->getSessionID()==frameBlob->getSessionID())) {
blobList.erase(delblb);
break;
}
}
if (frameBlob->getBlobID()==maxBlobID[source_id]) {
maxBlobID[source_id] = -1;
delete frameBlob;
if (blobList.size()>0) {
std::list<TuioBlob*>::iterator clist;
for (clist=blobList.begin(); clist != blobList.end(); clist++) {
if ((*clist)->getTuioSourceID()==source_id) {
b_id = (*clist)->getBlobID();
if (b_id>maxBlobID[source_id]) maxBlobID[source_id]=b_id;
}
}
freeBlobBuffer.clear();
for (std::list<TuioBlob*>::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) {
TuioBlob *freeBlob = (*flist);
if (freeBlob->getTuioSourceID()==source_id) {
if (freeBlob->getBlobID()>maxBlobID[source_id]) delete freeBlob;
else freeBlobBuffer.push_back(freeBlob);
} else freeBlobBuffer.push_back(freeBlob);
}
freeBlobList = freeBlobBuffer;
} else {
freeBlobBuffer.clear();
for (std::list<TuioBlob*>::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) {
TuioBlob *freeBlob = (*flist);
if (freeBlob->getTuioSourceID()==source_id) delete freeBlob;
else freeBlobBuffer.push_back(freeBlob);
}
freeBlobList = freeBlobBuffer;
}
} else if (frameBlob->getBlobID()<maxBlobID[source_id]) {
freeBlobList.push_back(frameBlob);
}
unlockBlobList();
break;
case TUIO_ADDED:
lockBlobList();
for(std::list<TuioBlob*>::iterator iter = blobList.begin();iter!= blobList.end(); iter++)
if ((*iter)->getTuioSourceID()==source_id) b_id++;
for(std::list<TuioBlob*>::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++)
if ((*iter)->getTuioSourceID()==source_id) free_size++;
if ((free_size<=maxBlobID[source_id]) && (free_size>0)) {
std::list<TuioBlob*>::iterator closestBlob = freeBlobList.begin();
for(std::list<TuioBlob*>::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) {
if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getDistance(tblb)<(*closestBlob)->getDistance(tblb))) closestBlob = iter;
}
if (closestBlob!=freeBlobList.end()) {
TuioBlob *freeBlob = (*closestBlob);
b_id = freeBlob->getBlobID();
freeBlobList.erase(closestBlob);
delete freeBlob;
}
} else maxBlobID[source_id] = b_id;
frameBlob = new TuioBlob(currentTime,tblb->getSessionID(),b_id,tblb->getX(),tblb->getY(),tblb->getAngle(),tblb->getWidth(),tblb->getHeight(),tblb->getArea());
if (source_name) frameBlob->setTuioSource(source_id,source_name,source_addr);
blobList.push_back(frameBlob);
delete tblb;
unlockBlobList();
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->addTuioBlob(frameBlob);
break;
default:
lockBlobList();
std::list<TuioBlob*>::iterator iter;
for (iter=blobList.begin(); iter != blobList.end(); iter++) {
if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getSessionID()==tblb->getSessionID())) {
frameBlob = (*iter);
break;
}
}
if (iter==blobList.end()) {
unlockBlobList();
break;
}
if ( (tblb->getX()!=frameBlob->getX() && tblb->getXSpeed()==0) || (tblb->getY()!=frameBlob->getY() && tblb->getYSpeed()==0) || (tblb->getAngle()!=frameBlob->getAngle() && tblb->getRotationSpeed()==0) )
frameBlob->update(currentTime,tblb->getX(),tblb->getY(),tblb->getAngle(),tblb->getWidth(),tblb->getHeight(),tblb->getArea());
else
frameBlob->update(currentTime,tblb->getX(),tblb->getY(),tblb->getAngle(),tblb->getWidth(),tblb->getHeight(),tblb->getArea(),tblb->getXSpeed(),tblb->getYSpeed(),tblb->getRotationSpeed(),tblb->getMotionAccel(),tblb->getRotationAccel());
delete tblb;
unlockBlobList();
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->updateTuioBlob(frameBlob);
}
}
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->refresh(currentTime);
} else {
for (std::list<TuioBlob*>::iterator iter=frameBlobs.begin(); iter != frameBlobs.end(); iter++) {
TuioBlob *tblb = (*iter);
delete tblb;
}
}
frameBlobs.clear();
}
}
} catch( Exception& e ){
std::cerr << "error parsing TUIO message: "<< msg.AddressPattern() << " - " << e.what() << std::endl;
}
}
bool TuioClient::isConnected() {
return receiver->isConnected();
}
void TuioClient::connect(bool lock) {
TuioTime::initSession();
currentTime.reset();
receiver->connect(lock);
unlockCursorList();
unlockObjectList();
unlockBlobList();
}
void TuioClient::disconnect() {
receiver->disconnect();
aliveObjectList.clear();
aliveCursorList.clear();
aliveBlobList.clear();
for (std::list<TuioObject*>::iterator iter=objectList.begin(); iter != objectList.end(); iter++)
delete (*iter);
objectList.clear();
for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++)
delete (*iter);
cursorList.clear();
for (std::list<TuioBlob*>::iterator iter=blobList.begin(); iter != blobList.end(); iter++)
delete (*iter);
blobList.clear();
for (std::list<TuioCursor*>::iterator iter=freeCursorList.begin(); iter != freeCursorList.end(); iter++)
delete(*iter);
freeCursorList.clear();
for (std::list<TuioBlob*>::iterator iter=freeBlobList.begin(); iter != freeBlobList.end(); iter++)
delete(*iter);
freeBlobList.clear();
}
TuioObject* TuioClient::getTuioObject(int src_id, long s_id) {
lockObjectList();
for (std::list<TuioObject*>::iterator iter=objectList.begin(); iter != objectList.end(); iter++) {
if (((*iter)->getTuioSourceID()==src_id) && ((*iter)->getSessionID()==s_id)) {
unlockObjectList();
return (*iter);
}
}
unlockObjectList();
return NULL;
}
TuioCursor* TuioClient::getTuioCursor(int src_id, long s_id) {
lockCursorList();
for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) {
if (((*iter)->getTuioSourceID()==src_id) && ((*iter)->getSessionID()==s_id)) {
unlockCursorList();
return (*iter);
}
}
unlockCursorList();
return NULL;
}
TuioBlob* TuioClient::getTuioBlob(int src_id, long s_id) {
lockBlobList();
for (std::list<TuioBlob*>::iterator iter=blobList.begin(); iter != blobList.end(); iter++) {
if (((*iter)->getTuioSourceID()==src_id) && ((*iter)->getSessionID()==s_id)) {
unlockBlobList();
return (*iter);
}
}
unlockBlobList();
return NULL;
}
std::list<TuioObject*> TuioClient::getTuioObjects(int source_id) {
lockObjectList();
std::list<TuioObject*> listBuffer;
for (std::list<TuioObject*>::iterator iter=objectList.begin(); iter != objectList.end(); iter++) {
TuioObject *tobj = (*iter);
if (tobj->getTuioSourceID()==source_id) listBuffer.push_back(tobj);
}
unlockObjectList();
return listBuffer;
}
std::list<TuioCursor*> TuioClient::getTuioCursors(int source_id) {
lockCursorList();
std::list<TuioCursor*> listBuffer;
for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) {
TuioCursor *tcur = (*iter);
if (tcur->getTuioSourceID()==source_id) listBuffer.push_back(tcur);
}
unlockCursorList();
return listBuffer;
}
std::list<TuioBlob*> TuioClient::getTuioBlobs(int source_id) {
lockBlobList();
std::list<TuioBlob*> listBuffer;
for (std::list<TuioBlob*>::iterator iter=blobList.begin(); iter != blobList.end(); iter++) {
TuioBlob *tblb = (*iter);
if (tblb->getTuioSourceID()==source_id) listBuffer.push_back(tblb);
}
unlockBlobList();
return listBuffer;
}
std::list<TuioObject> TuioClient::copyTuioObjects(int source_id) {
lockObjectList();
std::list<TuioObject> listBuffer;
for (std::list<TuioObject*>::iterator iter=objectList.begin(); iter != objectList.end(); iter++) {
TuioObject *tobj = (*iter);
if (tobj->getTuioSourceID()==source_id) listBuffer.push_back(*tobj);
}
unlockObjectList();
return listBuffer;
}
std::list<TuioCursor> TuioClient::copyTuioCursors(int source_id) {
lockCursorList();
std::list<TuioCursor> listBuffer;
for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) {
TuioCursor *tcur = (*iter);
if (tcur->getTuioSourceID()==source_id) listBuffer.push_back(*tcur);
}
unlockCursorList();
return listBuffer;
}
std::list<TuioBlob> TuioClient::copyTuioBlobs(int source_id) {
lockBlobList();
std::list<TuioBlob> listBuffer;
for (std::list<TuioBlob*>::iterator iter=blobList.begin(); iter != blobList.end(); iter++) {
TuioBlob *tblb = (*iter);
if (tblb->getTuioSourceID()==source_id) listBuffer.push_back(*tblb);
}
unlockBlobList();
return listBuffer;
}

View File

@@ -0,0 +1,301 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TUIOCLIENT_H
#define INCLUDED_TUIOCLIENT_H
#include "TuioDispatcher.h"
#include "OscReceiver.h"
#include "oscpack/osc/OscReceivedElements.h"
#include <iostream>
#include <list>
#include <map>
#include <algorithm>
#include <string>
#include <cstring>
namespace TUIO {
class OscReceiver; // Forward declaration
/**
* <p>The TuioClient class is the central TUIO protocol decoder component. It provides a simple callback infrastructure using the {@link TuioListener} interface.
* In order to receive and decode TUIO messages an instance of TuioClient needs to be created. The TuioClient instance then generates TUIO events
* which are broadcasted to all registered classes that implement the {@link TuioListener} interface.</p>
* <p><code>
* TuioClient *client = new TuioClient();<br/>
* client->addTuioListener(myTuioListener);<br/>
* client->connect();<br/>
* </code></p>
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TuioClient : public TuioDispatcher {
public:
/**
* This constructor creates a TuioClient that uses an internal UdpReceiver listening to the default UDP port 3333
*
*/
TuioClient();
/**
* This constructor creates a TuioClient that uses an internal UdpReceiver listening to the provided UDP port
*
* @param port the UDP port the internal UdpReceiver is listening to
*/
TuioClient(int port);
/**
* This constructor creates a TuioClient that uses the provided OscReceiver for the incoming OSC data
*
* @param oscreceiver the OscReceiver implementation for the chosen transport method (UDP, TCP ...)
*/
TuioClient(OscReceiver *oscreceiver);
/**
* The destructor is doing nothing in particular.
*/
~TuioClient();
/**
* The TuioClient connects and starts receiving TUIO messages from its associated OscReceiver
*
* @param lock running in the background if set to false (default)
*/
void connect(bool lock=false);
/**
* The TuioClient disconnects and stops receiving TUIO messages from its associated OscReceiver
*/
void disconnect();
/**
* Returns true if this TuioClient is currently connected.
* @return true if this TuioClient is currently connected
*/
bool isConnected();
/**
* Returns a List of all currently active TuioObjects
*
* @return a List of TuioObjects
*/
std::list<TuioObject*> getTuioObjects() {
return TuioDispatcher::getTuioObjects();
}
/**
* Returns a List of all currently active TuioObjects
* which are associated to the given Source ID
*
* @param src_id the source ID of the corresponding TUIO source
* @return a List of TuioObjects
*/
std::list<TuioObject*> getTuioObjects(int source_id);
/**
* Returns a List with a copy of all currently active TuioObjects
* which are associated to the given Source ID
*
* @param src_id the source ID of the corresponding TUIO source
* @return a List with a copy of TuioObjects
*/
std::list<TuioObject> copyTuioObjects(int source_id);
/**
* Returns a List with a copy of all currently active TuioObjects
*
* @return a List with a copy of TuioObjects
*/
std::list<TuioObject> copyTuioObjects() {
return TuioDispatcher::copyTuioObjects();
}
/**
* Returns the TuioObject corresponding to the provided Session ID
* or NULL if the Session ID does not refer to an active TuioObject
*
* @param s_id the session ID of the corresponding TuioObject
* @return an active TuioObject corresponding to the provided Session ID or NULL
*/
TuioObject* getTuioObject(long s_id) {
return getTuioObject(0,s_id);
};
/**
* Returns the TuioObject corresponding to the provided Session ID
* which is associated to the given Source ID
* or NULL if the Session ID does not refer to an active TuioObject
*
* @param src_id the source ID of the corresponding TUIO source
* @param s_id the session ID of the corresponding TuioObject
* @return an active TuioObject corresponding to the provided Session ID or NULL
*/
TuioObject* getTuioObject(int src_id, long s_id);
/**
* Returns a List of all currently active TuioCursors
*
* @return a List of TuioCursors
*/
std::list<TuioCursor*> getTuioCursors() {
return TuioDispatcher::getTuioCursors();
}
/**
* Returns a List of all currently active TuioCursors
* which are associated to the given Source ID
*
* @param src_id the source ID of the corresponding TUIO source
* @return a List of TuioCursors
*/
std::list<TuioCursor*> getTuioCursors(int source_id);
/**
* Returns a List with a copy of all currently active TuioCursors
*
* @return a List with a copy of TuioCursors
*/
std::list<TuioCursor> copyTuioCursors() {
return TuioDispatcher::copyTuioCursors();
}
/**
* Returns a List with a copy of all currently active TuioCursors
* which are associated to the given Source ID
*
* @param src_id the source ID of the corresponding TUIO source
* @return a List with a copy of TuioCursors
*/
std::list<TuioCursor> copyTuioCursors(int source_id);
/**
* Returns the TuioCursor corresponding to the provided Session ID
* or NULL if the Session ID does not refer to an active TuioCursor
*
* @param s_id the session ID of the corresponding TuioCursor
* @return an active TuioCursor corresponding to the provided Session ID or NULL
*/
TuioCursor* getTuioCursor(long s_id) {
return getTuioCursor(0,s_id);
};
/**
* Returns the TuioCursor corresponding to the provided Session ID
* which is associated to the given Source ID
* or NULL if the Session ID does not refer to an active TuioCursor
*
* @param src_id the source ID of the corresponding TUIO source
* @param s_id the session ID of the corresponding TuioCursor
* @return an active TuioCursor corresponding to the provided Session ID or NULL
*/
TuioCursor* getTuioCursor(int src_id, long s_id);
/**
* Returns a List of all currently active TuioBlobs
*
* @return a List of TuioBlobs
*/
std::list<TuioBlob*> getTuioBlobs() {
return TuioDispatcher::getTuioBlobs();
}
/**
* Returns a List of all currently active TuioBlobs
* which are associated to the given Source ID
*
* @param src_id the source ID of the corresponding TUIO source
* @return a List of TuioBlobs
*/
std::list<TuioBlob*> getTuioBlobs(int source_id);
/**
* Returns a List with a copy of all currently active TuioBlobs
*
* @return a List with a copy of TuioBlobs
*/
std::list<TuioBlob> copyTuioBlobs() {
return TuioDispatcher::copyTuioBlobs();
}
/**
* Returns a List with a copy of all currently active TuioBlobs
* which are associated to the given Source ID
*
* @param src_id the source ID of the corresponding TUIO source
* @return a List with a copy of TuioBlobs
*/
std::list<TuioBlob> copyTuioBlobs(int source_id);
/**
* Returns the TuioBlob corresponding to the provided Session ID
* or NULL if the Session ID does not refer to an active TuioBlob
*
* @param s_id the session ID of the corresponding TuioBlob
* @return an active TuioBlob corresponding to the provided Session ID or NULL
*/
TuioBlob* getTuioBlob(long s_id) {
return getTuioBlob(0,s_id);
};
/**
* Returns the TuioBlob corresponding to the provided Session ID
* which is associated to the given Source ID
* or NULL if the Session ID does not refer to an active TuioBlob
*
* @param src_id the source ID of the corresponding TUIO source
* @param s_id the session ID of the corresponding TuioBlob
* @return an active TuioBlob corresponding to the provided Session ID or NULL
*/
TuioBlob* getTuioBlob(int src_id, long s_id);
void processOSC( const osc::ReceivedMessage& message);
private:
void initialize();
std::list<TuioObject*> frameObjects;
std::list<long> aliveObjectList;
std::list<TuioCursor*> frameCursors;
std::list<long> aliveCursorList;
std::list<TuioBlob*> frameBlobs;
std::list<long> aliveBlobList;
osc::int32 currentFrame;
TuioTime currentTime;
std::list<TuioCursor*> freeCursorList, freeCursorBuffer;
std::map<int,int> maxCursorID;
std::list<TuioBlob*> freeBlobList, freeBlobBuffer;
std::map<int,int> maxBlobID;
std::map<std::string,int> sourceList;
int source_id;
char *source_name;
char *source_addr;
OscReceiver *receiver;
bool local_receiver;
};
};
#endif /* INCLUDED_TUIOCLIENT_H */

View File

@@ -0,0 +1,277 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TuioContainer.h"
using namespace TUIO;
TuioContainer::TuioContainer (TuioTime ttime, long si, float xp, float yp):TuioPoint(ttime, xp,yp)
,state(TUIO_ADDED)
,source_id(0)
,source_name("undefined")
,source_addr("localhost")
{
session_id = si;
x_speed = 0.0f;
y_speed = 0.0f;
motion_speed = 0.0f;
motion_accel = 0.0f;
x_accel = 0.0f;
y_accel = 0.0f;
TuioPoint p(currentTime,xpos,ypos);
path.push_back(p);
lastPoint = &path.back();
}
TuioContainer::TuioContainer (long si, float xp, float yp):TuioPoint(xp,yp)
,state(TUIO_ADDED)
,source_id(0)
,source_name("undefined")
,source_addr("localhost")
{
session_id = si;
x_speed = 0.0f;
y_speed = 0.0f;
motion_speed = 0.0f;
motion_accel = 0.0f;
x_accel = 0.0f;
y_accel = 0.0f;
TuioPoint p(currentTime,xpos,ypos);
path.push_back(p);
lastPoint = &path.back();
}
TuioContainer::TuioContainer (TuioContainer *tcon):TuioPoint(tcon)
,state(TUIO_ADDED)
,source_id(0)
,source_name("undefined")
,source_addr("localhost")
{
session_id = tcon->getSessionID();
x_speed = 0.0f;
y_speed = 0.0f;
motion_speed = 0.0f;
motion_accel = 0.0f;
x_accel = 0.0f;
y_accel = 0.0f;
TuioPoint p(currentTime,xpos,ypos);
path.push_back(p);
lastPoint = &path.back();
}
void TuioContainer::setTuioSource(int src_id, const char *src_name, const char *src_addr) {
source_id = src_id;
source_name = std::string(src_name);
source_addr = std::string(src_addr);
}
const char* TuioContainer::getTuioSourceName() const{
return source_name.c_str();
}
const char* TuioContainer::getTuioSourceAddress() const{
return source_addr.c_str();
}
int TuioContainer::getTuioSourceID() const{
return source_id;
}
void TuioContainer::update (TuioTime ttime, float xp, float yp) {
lastPoint = &path.back();
TuioPoint::update(ttime,xp, yp);
TuioTime diffTime = currentTime - lastPoint->getTuioTime();
float dt = diffTime.getTotalMilliseconds()/1000.0f;
float dx = xpos - lastPoint->getX();
float dy = ypos - lastPoint->getY();
float dist = sqrt(dx*dx+dy*dy);
float last_motion_speed = motion_speed;
float last_x_speed = x_speed;
float last_y_speed = y_speed;
x_speed = dx/dt;
y_speed = dy/dt;
motion_speed = dist/dt;
motion_accel = (motion_speed - last_motion_speed)/dt;
x_accel = (x_speed - last_x_speed)/dt;
y_accel = (y_speed - last_y_speed)/dt;
TuioPoint p(currentTime,xpos,ypos);
path.push_back(p);
if (path.size()>MAX_PATH_SIZE) path.pop_front();
if (motion_accel>0) state = TUIO_ACCELERATING;
else if (motion_accel<0) state = TUIO_DECELERATING;
else state = TUIO_STOPPED;
}
void TuioContainer::stop(TuioTime ttime) {
if ( state==TUIO_IDLE )update(ttime,xpos,ypos);
else state=TUIO_IDLE;
}
void TuioContainer::update (TuioTime ttime, float xp, float yp, float xs, float ys, float ma) {
TuioPoint::update(ttime,xp, yp);
x_speed = xs;
y_speed = ys;
motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed);
motion_accel = ma;
x_accel = ma;
y_accel = ma;
lastPoint = &path.back();
TuioPoint p(currentTime,xpos,ypos);
path.push_back(p);
if (path.size()>MAX_PATH_SIZE) path.pop_front();
if (motion_accel>0) state = TUIO_ACCELERATING;
else if (motion_accel<0) state = TUIO_DECELERATING;
else state = TUIO_STOPPED;
}
void TuioContainer::update (float xp, float yp, float xs, float ys, float ma) {
TuioPoint::update(xp,yp);
x_speed = xs;
y_speed = ys;
motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed);
motion_accel = ma;
x_accel = ma;
y_accel = ma;
lastPoint = &path.back();
TuioPoint p(currentTime,xpos,ypos);
path.push_back(p);
if (path.size()>MAX_PATH_SIZE) path.pop_front();
if (motion_accel>0) state = TUIO_ACCELERATING;
else if (motion_accel<0) state = TUIO_DECELERATING;
else state = TUIO_STOPPED;
}
void TuioContainer::update (TuioContainer *tcon) {
TuioPoint::update(tcon);
x_speed = tcon->getXSpeed();
y_speed = tcon->getYSpeed();
motion_speed = tcon->getMotionSpeed();
motion_accel = tcon->getMotionAccel();
x_accel = motion_accel;
y_accel = motion_accel;
lastPoint = &path.back();
TuioPoint p(tcon->getTuioTime(),xpos,ypos);
path.push_back(p);
if (path.size()>MAX_PATH_SIZE) path.pop_front();
if (motion_accel>0) state = TUIO_ACCELERATING;
else if (motion_accel<0) state = TUIO_DECELERATING;
else state = TUIO_STOPPED;
}
void TuioContainer::remove(TuioTime ttime) {
currentTime = ttime;
state = TUIO_REMOVED;
}
long TuioContainer::getSessionID() const{
return session_id;
}
void TuioContainer::setSessionID(long s_id) {
session_id = s_id;
}
float TuioContainer::getXSpeed() const{
return x_speed;
}
float TuioContainer::getYSpeed() const{
return y_speed;
}
TuioPoint TuioContainer::getPosition() const{
TuioPoint p(xpos,ypos);
return p;
}
std::list<TuioPoint> TuioContainer::getPath() const{
return path;
}
float TuioContainer::getMotionSpeed() const{
return motion_speed;
}
float TuioContainer::getMotionAccel() const{
return motion_accel;
}
int TuioContainer::getTuioState() const{
return state;
}
bool TuioContainer::isMoving() const{
if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING)) return true;
else return false;
}
TuioPoint TuioContainer::predictPosition() {
/*if (path.size()>1) {
std::list<TuioPoint>::iterator iter = path.end();
std::advance(iter, -2);
TuioTime diffTime = currentTime - (*iter).getTuioTime();
float dt = diffTime.getTotalMilliseconds()/1000.0f;
float tx = x_speed * dt;
float ty = y_speed * dt;
float nx = xpos+tx-tx*x_accel*dt;
float ny = ypos+ty-ty*y_accel*dt;
//if (xposFilter && yposFilter) {
// nx = xposFilter->filter(nx,dt);
// ny = yposFilter->filter(ny,dt);
// //std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl;
//}
//std::cout << nx << " " << ny << std::endl;
return TuioPoint(nx,ny);
} else return TuioPoint(xpos,ypos);*/
TuioTime diffTime = currentTime - lastPoint->getTuioTime();
float dt = diffTime.getTotalMilliseconds()/1000.0f;
float tx = x_speed * dt;
float ty = y_speed * dt;
float nx = xpos+tx-tx*x_accel*dt;
float ny = ypos+ty-ty*y_accel*dt;
//if (xposFilter && yposFilter) {
// nx = xposFilter->filter(nx,dt);
// ny = yposFilter->filter(ny,dt);
// //std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl;
//}
//std::cout << nx << " " << ny << std::endl;
return TuioPoint(nx,ny);
}

View File

@@ -0,0 +1,279 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TUIOCONTAINER_H
#define INCLUDED_TUIOCONTAINER_H
#include "TuioPoint.h"
#include <list>
#include <string>
#define TUIO_IDLE 0
#define TUIO_ADDED 1
#define TUIO_ACCELERATING 2
#define TUIO_DECELERATING 3
#define TUIO_ROTATING 4
#define TUIO_STOPPED 5
#define TUIO_REMOVED 6
#define MAX_PATH_SIZE 128
namespace TUIO {
/**
* The abstract TuioContainer class defines common attributes that apply to both subclasses {@link TuioObject} and {@link TuioCursor}.
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TuioContainer: public TuioPoint {
private:
TuioPoint *lastPoint;
protected:
/**
* The unique session ID number that is assigned to each TUIO object or cursor.
*/
long session_id;
/**
* The X-axis velocity value.
*/
float x_speed;
/**
* The Y-axis velocity value.
*/
float y_speed;
/**
* The motion speed value.
*/
float motion_speed;
/**
* The motion acceleration value.
*/
float motion_accel;
float x_accel;
float y_accel;
/**
* A List of TuioPoints containing all the previous positions of the TUIO component.
*/
std::list<TuioPoint> path;
/**
* Reflects the current state of the TuioComponent
*/
int state;
/**
* The ID of the TUIO source
*/
int source_id;
/**
* The name of the TUIO source
*/
std::string source_name;
/**
* The address of the TUIO source
*/
std::string source_addr;
public:
using TuioPoint::update;
/**
* This constructor takes a TuioTime argument and assigns it along with the provided
* Session ID, X and Y coordinate to the newly created TuioContainer.
*
* @param ttime the TuioTime to assign
* @param si the Session ID to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
*/
TuioContainer (TuioTime ttime, long si, float xp, float yp);
/**
* This constructor takes the provided Session ID, X and Y coordinate
* and assigs these values to the newly created TuioContainer.
*
* @param si the Session ID to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
*/
TuioContainer (long si, float xp, float yp);
/**
* This constructor takes the atttibutes of the provided TuioContainer
* and assigs these values to the newly created TuioContainer.
*
* @param tcon the TuioContainer to assign
*/
TuioContainer (TuioContainer *tcon);
/**
* The destructor is doing nothing in particular.
*/
virtual ~TuioContainer(){};
/**
* Sets the ID, name and address of the TUIO source
*
* @param src_id the ID of the TUIO source
* @param src_name the name of the TUIO source
* @param src_addr the address of the TUIO source
*/
virtual void setTuioSource(int src_id, const char *src_name, const char *src_addr);
/**
* Returns the name of the TUIO source
*/
virtual const char* getTuioSourceName() const;
/**
* Returns the address of the TUIO source
*/
virtual const char* getTuioSourceAddress() const;
/**
* Returns the ID of the TUIO source
*/
virtual int getTuioSourceID() const;
/**
* Takes a TuioTime argument and assigns it along with the provided
* X and Y coordinate to the private TuioContainer attributes.
* The speed and accleration values are calculated accordingly.
*
* @param ttime the TuioTime to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
*/
virtual void update (TuioTime ttime, float xp, float yp);
/**
* This method is used to calculate the speed and acceleration values of
* TuioContainers with unchanged positions.
*/
virtual void stop(TuioTime ttime);
/**
* Takes a TuioTime argument and assigns it along with the provided
* X and Y coordinate, X and Y velocity and acceleration
* to the private TuioContainer attributes.
*
* @param ttime the TuioTime to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param xs the X velocity to assign
* @param ys the Y velocity to assign
* @param ma the acceleration to assign
*/
virtual void update (TuioTime ttime, float xp, float yp, float xs, float ys, float ma);
/**
* Assigns the provided X and Y coordinate, X and Y velocity and acceleration
* to the private TuioContainer attributes. The TuioTime time stamp remains unchanged.
*
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param xs the X velocity to assign
* @param ys the Y velocity to assign
* @param ma the acceleration to assign
*/
virtual void update (float xp, float yp, float xs, float ys, float ma);
/**
* Takes the atttibutes of the provided TuioContainer
* and assigs these values to this TuioContainer.
* The TuioTime time stamp of this TuioContainer remains unchanged.
*
* @param tcon the TuioContainer to assign
*/
virtual void update (TuioContainer *tcon);
/**
* Assigns the REMOVE state to this TuioContainer and sets
* its TuioTime time stamp to the provided TuioTime argument.
*
* @param ttime the TuioTime to assign
*/
virtual void remove(TuioTime ttime);
/**
* Returns the Session ID of this TuioContainer.
* @return the Session ID of this TuioContainer
*/
virtual long getSessionID() const;
/**
* Sets the Session ID of this TuioContainer.
* @param s_id the new Session ID for this TuioContainer
*/
virtual void setSessionID(long s_id);
/**
* Returns the X velocity of this TuioContainer.
* @return the X velocity of this TuioContainer
*/
virtual float getXSpeed() const;
/**
* Returns the Y velocity of this TuioContainer.
* @return the Y velocity of this TuioContainer
*/
virtual float getYSpeed() const;
/**
* Returns the position of this TuioContainer.
* @return the position of this TuioContainer
*/
virtual TuioPoint getPosition() const;
/**
* Returns the path of this TuioContainer.
* @return the path of this TuioContainer
*/
virtual std::list<TuioPoint> getPath() const;
/**
* Returns the motion speed of this TuioContainer.
* @return the motion speed of this TuioContainer
*/
virtual float getMotionSpeed() const;
/**
* Returns the motion acceleration of this TuioContainer.
* @return the motion acceleration of this TuioContainer
*/
virtual float getMotionAccel() const;
/**
* Returns the TUIO state of this TuioContainer.
* @return the TUIO state of this TuioContainer
*/
virtual int getTuioState() const;
/**
* Returns true of this TuioContainer is moving.
* @return true of this TuioContainer is moving
*/
virtual bool isMoving() const;
virtual TuioPoint predictPosition();
};
}
#endif

View File

@@ -0,0 +1,38 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TuioCursor.h"
using namespace TUIO;
TuioCursor::TuioCursor (TuioTime ttime, long si, int ci, float xp, float yp):TuioContainer(ttime,si,xp,yp) {
cursor_id = ci;
}
TuioCursor::TuioCursor (long si, int ci, float xp, float yp):TuioContainer(si,xp,yp) {
cursor_id = ci;
}
TuioCursor::TuioCursor (TuioCursor *tcur):TuioContainer(tcur) {
cursor_id = tcur->getCursorID();
}
int TuioCursor::getCursorID() const{
return cursor_id;
};

View File

@@ -0,0 +1,86 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TUIOCURSOR_H
#define INCLUDED_TUIOCURSOR_H
#include "TuioContainer.h"
namespace TUIO {
/**
* The TuioCursor class encapsulates /tuio/2Dcur TUIO cursors.
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TuioCursor: public TuioContainer {
protected:
/**
* The individual cursor ID number that is assigned to each TuioCursor.
*/
int cursor_id;
public:
using TuioContainer::update;
/**
* This constructor takes a TuioTime argument and assigns it along with the provided
* Session ID, Cursor ID, X and Y coordinate to the newly created TuioCursor.
*
* @param ttime the TuioTime to assign
* @param si the Session ID to assign
* @param ci the Cursor ID to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
*/
TuioCursor (TuioTime ttime, long si, int ci, float xp, float yp);
/**
* This constructor takes the provided Session ID, Cursor ID, X and Y coordinate
* and assigs these values to the newly created TuioCursor.
*
* @param si the Session ID to assign
* @param ci the Cursor ID to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
*/
TuioCursor (long si, int ci, float xp, float yp);
/**
* This constructor takes the atttibutes of the provided TuioCursor
* and assigs these values to the newly created TuioCursor.
*
* @param tcur the TuioCursor to assign
*/
TuioCursor (TuioCursor *tcur);
/**
* The destructor is doing nothing in particular.
*/
virtual ~TuioCursor(){};
/**
* Returns the Cursor ID of this TuioCursor.
* @return the Cursor ID of this TuioCursor
*/
int getCursorID() const;
};
}
#endif

View File

@@ -0,0 +1,211 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TuioDispatcher.h"
#include <iostream>
#include <list>
#include <algorithm>
#include <cstring>
using namespace TUIO;
TuioDispatcher::TuioDispatcher() {
#ifndef WIN32
pthread_mutex_init(&cursorMutex,NULL);
pthread_mutex_init(&objectMutex,NULL);
pthread_mutex_init(&blobMutex,NULL);
#else
cursorMutex = CreateMutex(NULL,FALSE,TEXT("cursorMutex"));
objectMutex = CreateMutex(NULL,FALSE,TEXT("objectMutex"));
blobMutex = CreateMutex(NULL,FALSE,TEXT("blobMutex"));
#endif
}
TuioDispatcher::~TuioDispatcher() {
#ifndef WIN32
pthread_mutex_destroy(&cursorMutex);
pthread_mutex_destroy(&objectMutex);
pthread_mutex_destroy(&blobMutex);
#else
CloseHandle(cursorMutex);
CloseHandle(objectMutex);
CloseHandle(blobMutex);
#endif
}
void TuioDispatcher::lockObjectList() {
#ifndef WIN32
pthread_mutex_lock(&objectMutex);
#else
WaitForSingleObject(objectMutex, INFINITE);
#endif
}
void TuioDispatcher::unlockObjectList() {
#ifndef WIN32
pthread_mutex_unlock(&objectMutex);
#else
ReleaseMutex(objectMutex);
#endif
}
void TuioDispatcher::lockCursorList() {
#ifndef WIN32
pthread_mutex_lock(&cursorMutex);
#else
WaitForSingleObject(cursorMutex, INFINITE);
#endif
}
void TuioDispatcher::unlockCursorList() {
#ifndef WIN32
pthread_mutex_unlock(&cursorMutex);
#else
ReleaseMutex(cursorMutex);
#endif
}
void TuioDispatcher::lockBlobList() {
#ifndef WIN32
pthread_mutex_lock(&blobMutex);
#else
WaitForSingleObject(blobMutex, INFINITE);
#endif
}
void TuioDispatcher::unlockBlobList() {
#ifndef WIN32
pthread_mutex_unlock(&blobMutex);
#else
ReleaseMutex(blobMutex);
#endif
}
void TuioDispatcher::addTuioListener(TuioListener *listener) {
listenerList.push_back(listener);
}
void TuioDispatcher::removeTuioListener(TuioListener *listener) {
std::list<TuioListener*>::iterator result = find(listenerList.begin(),listenerList.end(),listener);
if (result!=listenerList.end()) listenerList.remove(listener);
}
void TuioDispatcher::removeAllTuioListeners() {
listenerList.clear();
}
TuioObject* TuioDispatcher::getTuioObject(long s_id) {
lockObjectList();
for (std::list<TuioObject*>::iterator iter=objectList.begin(); iter != objectList.end(); iter++) {
if((*iter)->getSessionID()==s_id) {
unlockObjectList();
return (*iter);
}
}
unlockObjectList();
return NULL;
}
TuioCursor* TuioDispatcher::getTuioCursor(long s_id) {
lockCursorList();
for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) {
if((*iter)->getSessionID()==s_id) {
unlockCursorList();
return (*iter);
}
}
unlockCursorList();
return NULL;
}
TuioBlob* TuioDispatcher::getTuioBlob(long s_id) {
lockBlobList();
for (std::list<TuioBlob*>::iterator iter=blobList.begin(); iter != blobList.end(); iter++) {
if((*iter)->getSessionID()==s_id) {
unlockBlobList();
return (*iter);
}
}
unlockBlobList();
return NULL;
}
std::list<TuioObject*> TuioDispatcher::getTuioObjects() {
lockObjectList();
std::list<TuioObject*> listBuffer;
listBuffer.insert(listBuffer.end(), objectList.begin(), objectList.end());
//std::list<TuioObject*> listBuffer = objectList;
unlockObjectList();
return listBuffer;
}
std::list<TuioCursor*> TuioDispatcher::getTuioCursors() {
lockCursorList();
std::list<TuioCursor*> listBuffer;
listBuffer.insert(listBuffer.end(), cursorList.begin(), cursorList.end());
//std::list<TuioCursor*> listBuffer = cursorList;
unlockCursorList();
return listBuffer;
}
std::list<TuioBlob*> TuioDispatcher::getTuioBlobs() {
lockBlobList();
std::list<TuioBlob*> listBuffer;
listBuffer.insert(listBuffer.end(), blobList.begin(), blobList.end());
//std::list<TuioBlob*> listBuffer = blobList;
unlockBlobList();
return listBuffer;
}
std::list<TuioObject> TuioDispatcher::copyTuioObjects() {
lockObjectList();
std::list<TuioObject> listBuffer;
for (std::list<TuioObject*>::iterator iter=objectList.begin(); iter != objectList.end(); iter++) {
TuioObject *tobj = (*iter);
listBuffer.push_back(*tobj);
}
unlockObjectList();
return listBuffer;
}
std::list<TuioCursor> TuioDispatcher::copyTuioCursors() {
lockCursorList();
std::list<TuioCursor> listBuffer;
for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) {
TuioCursor *tcur = (*iter);
listBuffer.push_back(*tcur);
}
unlockCursorList();
return listBuffer;
}
std::list<TuioBlob> TuioDispatcher::copyTuioBlobs() {
lockBlobList();
std::list<TuioBlob> listBuffer;
for (std::list<TuioBlob*>::iterator iter=blobList.begin(); iter != blobList.end(); iter++) {
TuioBlob *tblb = (*iter);
listBuffer.push_back(*tblb);
}
unlockBlobList();
return listBuffer;
}

View File

@@ -0,0 +1,187 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TUIODISPATCHER_H
#define INCLUDED_TUIODISPATCHER_H
#include "TuioListener.h"
#ifndef WIN32
#include <pthread.h>
#else
#include <windows.h>
#endif
namespace TUIO {
/**
* <p>The TuioDispatcher generates TUIO events which are broadcasted to all
* registered classes that implement the {@link TuioListener} interface.</p>
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TuioDispatcher {
public:
/**
* This constructor creates a TuioDispatcher
*
*/
TuioDispatcher();
/**
* The destructor is doing nothing in particular.
*/
~TuioDispatcher();
/**
* Adds the provided TuioListener to the list of registered TUIO event listeners
*
* @param listener the TuioListener to add
*/
void addTuioListener(TuioListener *listener);
/**
* Removes the provided TuioListener from the list of registered TUIO event listeners
*
* @param listener the TuioListener to remove
*/
void removeTuioListener(TuioListener *listener);
/**
* Removes all TuioListener from the list of registered TUIO event listeners
*/
void removeAllTuioListeners();
/**
* Returns a List of all currently active TuioObjects
*
* @return a List of all currently active TuioObjects
*/
std::list<TuioObject*> getTuioObjects();
/**
* Returns a List with a copy of currently active TuioObjects
*
* @return a List with a copy of all currently active TuioObjects
*/
std::list<TuioObject> copyTuioObjects();
/**
* Returns a List of all currently active TuioCursors
*
* @return a List of all currently active TuioCursors
*/
std::list<TuioCursor*> getTuioCursors();
/**
* Returns a List with a copy of currently active TuioCursors
*
* @return a List with a copy of all currently active TuioCursors
*/
std::list<TuioCursor> copyTuioCursors();
/**
* Returns a List of all currently active TuioBlobs
*
* @return a List of all currently active TuioBlobs
*/
std::list<TuioBlob*> getTuioBlobs();
/**
* Returns a List with a copy of currently active TuioBlobs
*
* @return a List with a copy of all currently active TuioBlobs
*/
std::list<TuioBlob> copyTuioBlobs();
/**
* Returns the TuioObject corresponding to the provided Session ID
* or NULL if the Session ID does not refer to an active TuioObject
*
* @return an active TuioObject corresponding to the provided Session ID or NULL
*/
TuioObject* getTuioObject(long s_id);
/**
* Returns the TuioCursor corresponding to the provided Session ID
* or NULL if the Session ID does not refer to an active TuioCursor
*
* @return an active TuioCursor corresponding to the provided Session ID or NULL
*/
TuioCursor* getTuioCursor(long s_id);
/**
* Returns the TuioBlob corresponding to the provided Session ID
* or NULL if the Session ID does not refer to an active TuioBlob
*
* @return an active TuioBlob corresponding to the provided Session ID or NULL
*/
TuioBlob* getTuioBlob(long s_id);
/**
* Locks the TuioObject list in order to avoid updates during access
*/
void lockObjectList();
/**
* Releases the lock of the TuioObject list
*/
void unlockObjectList();
/**
* Locks the TuioCursor list in order to avoid updates during access
*/
void lockCursorList();
/**
* Releases the lock of the TuioCursor list
*/
void unlockCursorList();
/**
* Locks the TuioBlob list in order to avoid updates during access
*/
void lockBlobList();
/**
* Releases the lock of the TuioBlob list
*/
void unlockBlobList();
protected:
std::list<TuioListener*> listenerList;
std::list<TuioObject*> objectList;
std::list<TuioCursor*> cursorList;
std::list<TuioBlob*> blobList;
#ifndef WIN32
pthread_mutex_t objectMutex;
pthread_mutex_t cursorMutex;
pthread_mutex_t blobMutex;
#else
HANDLE objectMutex;
HANDLE cursorMutex;
HANDLE blobMutex;
#endif
};
}
#endif /* INCLUDED_TUIODISPATCHER_H */

View File

@@ -0,0 +1,124 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TUIOLISTENER_H
#define INCLUDED_TUIOLISTENER_H
#include "TuioObject.h"
#include "TuioCursor.h"
#include "TuioBlob.h"
namespace TUIO {
/**
* <p>The TuioListener interface provides a simple callback infrastructure which is used by the {@link TuioClient} class
* to dispatch TUIO events to all registered instances of classes that implement the TuioListener interface defined here.</p>
* <p>Any class that implements the TuioListener interface is required to implement all of the callback methods defined here.
* The {@link TuioClient} makes use of these interface methods in order to dispatch TUIO events to all registered TuioListener implementations.</p>
* <p><code>
* public class MyTuioListener implements TuioListener<br/>
* ...</code><p><code>
* MyTuioListener listener = new MyTuioListener();<br/>
* TuioClient client = new TuioClient();<br/>
* client.addTuioListener(listener);<br/>
* client.start();<br/>
* </code></p>
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TuioListener {
public:
/**
* The destructor is doing nothing in particular.
*/
virtual ~TuioListener(){};
/**
* This callback method is invoked by the TuioClient when a new TuioObject is added to the session.
*
* @param tobj the TuioObject reference associated to the addTuioObject event
*/
virtual void addTuioObject(TuioObject *tobj)=0;
/**
* This callback method is invoked by the TuioClient when an existing TuioObject is updated during the session.
*
* @param tobj the TuioObject reference associated to the updateTuioObject event
*/
virtual void updateTuioObject(TuioObject *tobj)=0;
/**
* This callback method is invoked by the TuioClient when an existing TuioObject is removed from the session.
*
* @param tobj the TuioObject reference associated to the removeTuioObject event
*/
virtual void removeTuioObject(TuioObject *tobj)=0;
/**
* This callback method is invoked by the TuioClient when a new TuioCursor is added to the session.
*
* @param tcur the TuioCursor reference associated to the addTuioCursor event
*/
virtual void addTuioCursor(TuioCursor *tcur)=0;
/**
* This callback method is invoked by the TuioClient when an existing TuioCursor is updated during the session.
*
* @param tcur the TuioCursor reference associated to the updateTuioCursor event
*/
virtual void updateTuioCursor(TuioCursor *tcur)=0;
/**
* This callback method is invoked by the TuioClient when an existing TuioCursor is removed from the session.
*
* @param tcur the TuioCursor reference associated to the removeTuioCursor event
*/
virtual void removeTuioCursor(TuioCursor *tcur)=0;
/**
* This callback method is invoked by the TuioClient when a new TuioBlob is added to the session.
*
* @param tcur the TuioBlob reference associated to the addTuioBlob event
*/
virtual void addTuioBlob(TuioBlob *tblb)=0;
/**
* This callback method is invoked by the TuioClient when an existing TuioBlob is updated during the session.
*
* @param tblb the TuioBlob reference associated to the updateTuioBlob event
*/
virtual void updateTuioBlob(TuioBlob *tblb)=0;
/**
* This callback method is invoked by the TuioClient when an existing TuioBlob is removed from the session.
*
* @param tblb the TuioBlob reference associated to the removeTuioBlob event
*/
virtual void removeTuioBlob(TuioBlob *tblb)=0;
/**
* This callback method is invoked by the TuioClient to mark the end of a received TUIO message bundle.
*
* @param ftime the TuioTime associated to the current TUIO message bundle
*/
virtual void refresh(TuioTime ftime)=0;
};
}
#endif /* INCLUDED_TUIOLISTENER_H */

View File

@@ -0,0 +1,615 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TuioManager.h"
using namespace TUIO;
TuioManager::TuioManager()
: currentFrameTime(TuioTime::getSystemTime())
, currentFrame(-1)
, maxCursorID(-1)
, maxBlobID(-1)
, sessionID(-1)
, updateObject(false)
, updateCursor(false)
, updateBlob(false)
, verbose(false)
, invert_x(false)
, invert_y(false)
, invert_a(false)
{
}
TuioManager::~TuioManager() {
}
TuioObject* TuioManager::addTuioObject(int f_id, float x, float y, float a) {
sessionID++;
TuioObject *tobj = new TuioObject(currentFrameTime, sessionID, f_id, x, y, a);
objectList.push_back(tobj);
updateObject = true;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->addTuioObject(tobj);
if (verbose)
std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl;
return tobj;
}
void TuioManager::addExternalTuioObject(TuioObject *tobj) {
if (tobj==NULL) return;
tobj->setSessionID(sessionID++);
objectList.push_back(tobj);
updateObject = true;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->addTuioObject(tobj);
if (verbose)
std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl;
}
void TuioManager::updateTuioObject(TuioObject *tobj, float x, float y, float a) {
if (tobj==NULL) return;
if (tobj->getTuioTime()==currentFrameTime) return;
tobj->update(currentFrameTime,x,y,a);
updateObject = true;
if (tobj->isMoving()) {
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->updateTuioObject(tobj);
if (verbose)
std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle()
<< " " << tobj->getXSpeed() << " " << tobj->getYSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl;
}
}
void TuioManager::updateExternalTuioObject(TuioObject *tobj) {
if (tobj==NULL) return;
updateObject = true;
if (tobj->isMoving()) {
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->updateTuioObject(tobj);
if (verbose)
std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle()
<< " " << tobj->getXSpeed() << " " << tobj->getYSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl;
}
}
void TuioManager::removeTuioObject(TuioObject *tobj) {
if (tobj==NULL) return;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->removeTuioObject(tobj);
if (verbose)
std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ")" << std::endl;
objectList.remove(tobj);
delete tobj;
updateObject = true;
}
void TuioManager::removeExternalTuioObject(TuioObject *tobj) {
if (tobj==NULL) return;
objectList.remove(tobj);
updateObject = true;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->removeTuioObject(tobj);
if (verbose)
std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ")" << std::endl;
}
TuioCursor* TuioManager::addTuioCursor(float x, float y) {
sessionID++;
int cursorID = (int)cursorList.size();
if ((int)(cursorList.size())<=maxCursorID) {
std::list<TuioCursor*>::iterator closestCursor = freeCursorList.begin();
for(std::list<TuioCursor*>::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) {
if((*iter)->getDistance(x,y)<(*closestCursor)->getDistance(x,y)) closestCursor = iter;
}
TuioCursor *freeCursor = (*closestCursor);
cursorID = (*closestCursor)->getCursorID();
freeCursorList.erase(closestCursor);
delete freeCursor;
} else maxCursorID = cursorID;
TuioCursor *tcur = new TuioCursor(currentFrameTime, sessionID, cursorID, x, y);
cursorList.push_back(tcur);
updateCursor = true;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->addTuioCursor(tcur);
if (verbose)
std::cout << "add cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() << std::endl;
return tcur;
}
void TuioManager::addExternalTuioCursor(TuioCursor *tcur) {
if (tcur==NULL) return;
tcur->setSessionID(sessionID++);
cursorList.push_back(tcur);
updateCursor = true;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->addTuioCursor(tcur);
if (verbose)
std::cout << "add cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() << std::endl;
}
void TuioManager::updateTuioCursor(TuioCursor *tcur,float x, float y) {
if (tcur==NULL) return;
//if (tcur->getTuioTime()==currentFrameTime) return;
tcur->update(currentFrameTime,x,y);
updateCursor = true;
if (tcur->isMoving()) {
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->updateTuioCursor(tcur);
if (verbose)
std::cout << "set cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY()
<< " " << tcur->getXSpeed() << " " << tcur->getYSpeed() << " " << tcur->getMotionAccel() << " " << std::endl;
}
}
void TuioManager::updateExternalTuioCursor(TuioCursor *tcur) {
if (tcur==NULL) return;
updateCursor = true;
if (tcur->isMoving()) {
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->updateTuioCursor(tcur);
if (verbose)
std::cout << "set cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY()
<< " " << tcur->getXSpeed() << " " << tcur->getYSpeed() << " " << tcur->getMotionAccel() << " " << std::endl;
}
}
void TuioManager::removeTuioCursor(TuioCursor *tcur) {
if (tcur==NULL) return;
cursorList.remove(tcur);
tcur->remove(currentFrameTime);
updateCursor = true;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->removeTuioCursor(tcur);
if (verbose)
std::cout << "del cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ")" << std::endl;
if (tcur->getCursorID()==maxCursorID) {
maxCursorID = -1;
delete tcur;
if (cursorList.size()>0) {
std::list<TuioCursor*>::iterator clist;
for (clist=cursorList.begin(); clist != cursorList.end(); clist++) {
int cursorID = (*clist)->getCursorID();
if (cursorID>maxCursorID) maxCursorID=cursorID;
}
freeCursorBuffer.clear();
for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
TuioCursor *freeCursor = (*flist);
if (freeCursor->getCursorID()>maxCursorID) delete freeCursor;
else freeCursorBuffer.push_back(freeCursor);
}
freeCursorList = freeCursorBuffer;
} else {
for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
TuioCursor *freeCursor = (*flist);
delete freeCursor;
}
freeCursorList.clear();
}
} else if (tcur->getCursorID()<maxCursorID) {
freeCursorList.push_back(tcur);
}
}
void TuioManager::removeExternalTuioCursor(TuioCursor *tcur) {
if (tcur==NULL) return;
cursorList.remove(tcur);
updateCursor = true;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->removeTuioCursor(tcur);
if (verbose)
std::cout << "del cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ")" << std::endl;
}
TuioBlob* TuioManager::addTuioBlob(float x, float y, float a, float w, float h, float f) {
sessionID++;
int blobID = (int)blobList.size();
if ((int)(blobList.size())<=maxBlobID) {
std::list<TuioBlob*>::iterator closestBlob = freeBlobList.begin();
for(std::list<TuioBlob*>::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) {
if((*iter)->getDistance(x,y)<(*closestBlob)->getDistance(x,y)) closestBlob = iter;
}
TuioBlob *freeBlob = (*closestBlob);
blobID = (*closestBlob)->getBlobID();
freeBlobList.erase(closestBlob);
delete freeBlob;
} else maxBlobID = blobID;
TuioBlob *tblb = new TuioBlob(currentFrameTime, sessionID, blobID, x, y, a, w, h, f);
blobList.push_back(tblb);
updateBlob = true;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->addTuioBlob(tblb);
if (verbose)
std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() << std::endl;
return tblb;
}
void TuioManager::addExternalTuioBlob(TuioBlob *tblb) {
if (tblb==NULL) return;
int blobID = (int)blobList.size();
if (blobID <= maxBlobID) {
std::list<TuioBlob*>::iterator closestBlob = freeBlobList.begin();
for(std::list<TuioBlob*>::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) {
if((*iter)->getDistance(tblb->getX(),tblb->getY())<(*closestBlob)->getDistance(tblb->getX(),tblb->getY())) closestBlob = iter;
}
TuioBlob *freeBlob = (*closestBlob);
blobID = (*closestBlob)->getBlobID();
freeBlobList.erase(closestBlob);
delete freeBlob;
} else maxBlobID = blobID;
tblb->setSessionID(sessionID++);
tblb->setBlobID(blobID);
blobList.push_back(tblb);
updateBlob = true;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->addTuioBlob(tblb);
if (verbose)
std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() << std::endl;
}
void TuioManager::updateTuioBlob(TuioBlob *tblb,float x, float y, float a, float w, float h, float f) {
if (tblb==NULL) return;
if (tblb->getTuioTime()==currentFrameTime) return;
tblb->update(currentFrameTime,x,y,a,w,h,f);
updateBlob = true;
if (tblb->isMoving()) {
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->updateTuioBlob(tblb);
if (verbose)
std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea()
<< " " << tblb->getXSpeed() << " " << tblb->getYSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel()<< " " << tblb->getRotationAccel() << " " << std::endl;
}
}
void TuioManager::updateExternalTuioBlob(TuioBlob *tblb) {
if (tblb==NULL) return;
updateBlob = true;
if (tblb->isMoving()) {
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->updateTuioBlob(tblb);
if (verbose)
std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea()
<< " " << tblb->getXSpeed() << " " << tblb->getYSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel()<< " " << tblb->getRotationAccel() << " " << std::endl;
}
}
void TuioManager::removeTuioBlob(TuioBlob *tblb) {
if (tblb==NULL) return;
blobList.remove(tblb);
tblb->remove(currentFrameTime);
updateBlob = true;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->removeTuioBlob(tblb);
if (verbose)
std::cout << "del blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ")" << std::endl;
if (tblb->getBlobID()==maxBlobID) {
maxBlobID = -1;
delete tblb;
if (blobList.size()>0) {
std::list<TuioBlob*>::iterator clist;
for (clist=blobList.begin(); clist != blobList.end(); clist++) {
int blobID = (*clist)->getBlobID();
if (blobID>maxBlobID) maxBlobID=blobID;
}
freeBlobBuffer.clear();
for (std::list<TuioBlob*>::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) {
TuioBlob *freeBlob = (*flist);
if (freeBlob->getBlobID()>maxBlobID) delete freeBlob;
else freeBlobBuffer.push_back(freeBlob);
}
freeBlobList = freeBlobBuffer;
} else {
for (std::list<TuioBlob*>::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) {
TuioBlob *freeBlob = (*flist);
delete freeBlob;
}
freeBlobList.clear();
}
} else if (tblb->getBlobID()<maxBlobID) {
freeBlobList.push_back(tblb);
}
}
void TuioManager::removeExternalTuioBlob(TuioBlob *tblb) {
if (tblb==NULL) return;
blobList.remove(tblb);
updateBlob = true;
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->removeTuioBlob(tblb);
if (verbose)
std::cout << "del blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ")" << std::endl;
}
long TuioManager::getSessionID() {
sessionID++;
return sessionID;
}
long TuioManager::getFrameID() {
return currentFrame;
}
TuioTime TuioManager::getFrameTime() {
return currentFrameTime;
}
void TuioManager::initFrame(TuioTime ttime) {
currentFrameTime = TuioTime(ttime);
currentFrame++;
}
void TuioManager::commitFrame() {
for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
(*listener)->refresh(currentFrameTime);
}
TuioObject* TuioManager::getClosestTuioObject(float xp, float yp) {
TuioObject *closestObject = NULL;
float closestDistance = 1.0f;
for (std::list<TuioObject*>::iterator iter=objectList.begin(); iter != objectList.end(); iter++) {
float distance = (*iter)->getDistance(xp,yp);
if(distance<closestDistance) {
closestObject = (*iter);
closestDistance = distance;
}
}
return closestObject;
}
TuioCursor* TuioManager::getClosestTuioCursor(float xp, float yp) {
TuioCursor *closestCursor = NULL;
float closestDistance = 1.0f;
for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) {
float distance = (*iter)->getDistance(xp,yp);
if(distance<closestDistance) {
closestCursor = (*iter);
closestDistance = distance;
}
}
return closestCursor;
}
TuioBlob* TuioManager::getClosestTuioBlob(float xp, float yp) {
TuioBlob *closestBlob = NULL;
float closestDistance = 1.0f;
for (std::list<TuioBlob*>::iterator iter=blobList.begin(); iter != blobList.end(); iter++) {
float distance = (*iter)->getDistance(xp,yp);
if(distance<closestDistance) {
closestBlob = (*iter);
closestDistance = distance;
}
}
return closestBlob;
}
std::list<TuioObject*> TuioManager::getUntouchedObjects() {
std::list<TuioObject*> untouched;
for (std::list<TuioObject*>::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) {
TuioObject *tobj = (*tuioObject);
if (tobj->getTuioTime()!=currentFrameTime) untouched.push_back(tobj);
}
return untouched;
}
void TuioManager::stopUntouchedMovingObjects() {
std::list<TuioObject*> untouched;
for (std::list<TuioObject*>::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) {
TuioObject *tobj = (*tuioObject);
if ((tobj->getTuioTime()!=currentFrameTime) && (tobj->isMoving())) {
tobj->stop(currentFrameTime);
updateObject = true;
if (verbose)
std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle()
<< " " << tobj->getXSpeed() << " " << tobj->getYSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl;
}
}
}
void TuioManager::removeUntouchedStoppedObjects() {
std::list<TuioObject*>::iterator tuioObject = objectList.begin();
while (tuioObject!=objectList.end()) {
TuioObject *tobj = (*tuioObject);
if ((tobj->getTuioTime()!=currentFrameTime) && (!tobj->isMoving())) {
removeTuioObject(tobj);
tuioObject = objectList.begin();
} else tuioObject++;
}
}
void TuioManager::resetTuioObjects() {
std::list<TuioObject*>::iterator tuioObject = objectList.begin();
while (tuioObject!=objectList.end()) {
removeTuioObject((*tuioObject));
tuioObject = objectList.begin();
}
}
std::list<TuioCursor*> TuioManager::getUntouchedCursors() {
std::list<TuioCursor*> untouched;
for (std::list<TuioCursor*>::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) {
TuioCursor *tcur = (*tuioCursor);
if (tcur->getTuioTime()!=currentFrameTime) untouched.push_back(tcur);
}
return untouched;
}
void TuioManager::stopUntouchedMovingCursors() {
std::list<TuioCursor*> untouched;
for (std::list<TuioCursor*>::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) {
TuioCursor *tcur = (*tuioCursor);
if ((tcur->getTuioTime()!=currentFrameTime) && (tcur->isMoving())) {
tcur->stop(currentFrameTime);
updateCursor = true;
if (verbose)
std::cout << "set cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY()
<< " " << tcur->getXSpeed() << " " << tcur->getYSpeed()<< " " << tcur->getMotionAccel() << " " << std::endl;
}
}
}
void TuioManager::removeUntouchedStoppedCursors() {
if (cursorList.size()==0) return;
std::list<TuioCursor*>::iterator tuioCursor = cursorList.begin();
while (tuioCursor!=cursorList.end()) {
TuioCursor *tcur = (*tuioCursor);
if ((tcur->getTuioTime()!=currentFrameTime) && (!tcur->isMoving())) {
removeTuioCursor(tcur);
tuioCursor = cursorList.begin();
} else tuioCursor++;
}
}
void TuioManager::resetTuioCursors() {
std::list<TuioCursor*>::iterator tuioCursor = cursorList.begin();
while (tuioCursor!=cursorList.end()) {
removeTuioCursor((*tuioCursor));
tuioCursor = cursorList.begin();
}
}
std::list<TuioBlob*> TuioManager::getUntouchedBlobs() {
std::list<TuioBlob*> untouched;
for (std::list<TuioBlob*>::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) {
TuioBlob *tblb = (*tuioBlob);
if (tblb->getTuioTime()!=currentFrameTime) untouched.push_back(tblb);
}
return untouched;
}
void TuioManager::stopUntouchedMovingBlobs() {
std::list<TuioBlob*> untouched;
for (std::list<TuioBlob*>::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) {
TuioBlob *tblb = (*tuioBlob);
if ((tblb->getTuioTime()!=currentFrameTime) && (tblb->isMoving())) {
tblb->stop(currentFrameTime);
updateBlob = true;
if (verbose)
std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea()
<< " " << tblb->getXSpeed() << " " << tblb->getYSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel()<< " " << tblb->getRotationAccel() << " " << std::endl;
}
}
}
void TuioManager::removeUntouchedStoppedBlobs() {
std::list<TuioBlob*>::iterator tuioBlob = blobList.begin();
while (tuioBlob!=blobList.end()) {
TuioBlob *tblb = (*tuioBlob);
if ((tblb->getTuioTime()!=currentFrameTime) && (!tblb->isMoving())) {
removeTuioBlob(tblb);
tuioBlob = blobList.begin();
} else tuioBlob++;
}
}
void TuioManager::resetTuioBlobs() {
std::list<TuioBlob*>::iterator tuioBlob = blobList.begin();
while (tuioBlob!=blobList.end()) {
removeTuioBlob((*tuioBlob));
tuioBlob = blobList.begin();
}
}

View File

@@ -0,0 +1,389 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TUIOMANAGER_H
#define INCLUDED_TUIOMANAGER_H
#include "TuioDispatcher.h"
#include <iostream>
#include <list>
#include <algorithm>
#define OBJ_MESSAGE_SIZE 108 // setMessage + fseqMessage size
#define CUR_MESSAGE_SIZE 88
#define BLB_MESSAGE_SIZE 116
namespace TUIO {
/**
* <p>The TuioManager class is the central TUIO session management component.</p>
* <p>During runtime the each frame is marked with the initFrame and commitFrame methods,
* while the currently present TuioObjects are managed by the server with ADD, UPDATE and REMOVE methods in analogy to the TuioClient's TuioListener interface.</p>
* <p><code>
* TuioManager *manager = new TuioManager();<br/>
* ...<br/>
* server->initFrame(TuioTime::getSessionTime());<br/>
* TuioObject *tobj = server->addTuioObject(xpos,ypos, angle);<br/>
* TuioCursor *tcur = server->addTuioObject(xpos,ypos);<br/>
* TuioBlob *tblb = server->addTuioBlob(xpos,ypos,width,height,angle);<br/>
* server->commitFrame();<br/>
* ...<br/>
* server->initFrame(TuioTime::getSessionTime());<br/>
* server->updateTuioObject(tobj, xpos,ypos, angle);<br/>
* server->updateTuioCursor(tcur, xpos,ypos);<br/>
* server->updateTuioBlob(tblb, xpos,ypos,width,height,angle);<br/>
* server->commitFrame();<br/>
* ...<br/>
* server->initFrame(TuioTime::getSessionTime());<br/>
* server->removeTuioObject(tobj);<br/>
* server->removeTuioCursor(tcur);<br/>
* server->removeTuioBlob(tblb);<br/>
* server->commitFrame();<br/>
* </code></p>
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TuioManager : public TuioDispatcher {
public:
/**
* The default constructor creates a TuioManager
*/
TuioManager();
/**
* The destructor is doing nothing in particular.
*/
~TuioManager();
/**
* Creates a new TuioObject based on the given arguments.
* The new TuioObject is added to the TuioServer's internal list of active TuioObjects
* and a reference is returned to the caller.
*
* @param sym the Symbol ID to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the angle to assign
* @return reference to the created TuioObject
*/
TuioObject* addTuioObject(int sym, float xp, float yp, float a);
/**
* Updates the referenced TuioObject based on the given arguments.
*
* @param tobj the TuioObject to update
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the angle to assign
*/
void updateTuioObject(TuioObject *tobj, float xp, float yp, float a);
/**
* Removes the referenced TuioObject from the TuioServer's internal list of TuioObjects
* and deletes the referenced TuioObject afterwards
*
* @param tobj the TuioObject to remove
*/
void removeTuioObject(TuioObject *tobj);
/**
* Adds an externally managed TuioObject to the TuioServer's internal list of active TuioObjects
*
* @param tobj the TuioObject to add
*/
void addExternalTuioObject(TuioObject *tobj);
/**
* Updates an externally managed TuioObject
*
* @param tobj the TuioObject to update
*/
void updateExternalTuioObject(TuioObject *tobj);
/**
* Removes an externally managed TuioObject from the TuioServer's internal list of TuioObjects
* The referenced TuioObject is not deleted
*
* @param tobj the TuioObject to remove
*/
void removeExternalTuioObject(TuioObject *tobj);
/**
* Creates a new TuioCursor based on the given arguments.
* The new TuioCursor is added to the TuioServer's internal list of active TuioCursors
* and a reference is returned to the caller.
*
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @return reference to the created TuioCursor
*/
TuioCursor* addTuioCursor(float xp, float yp);
/**
* Updates the referenced TuioCursor based on the given arguments.
*
* @param tcur the TuioObject to update
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
*/
void updateTuioCursor(TuioCursor *tcur, float xp, float yp);
/**
* Removes the referenced TuioCursor from the TuioServer's internal list of TuioCursors
* and deletes the referenced TuioCursor afterwards
*
* @param tcur the TuioCursor to remove
*/
void removeTuioCursor(TuioCursor *tcur);
/**
* Adds an externally managed TuioCursor
*
* @param tcur the TuioCursor to add
*/
void addExternalTuioCursor(TuioCursor *tcur);
/**
* Updates an externally managed TuioCursor
*
* @param tcur the TuioCursor to update
*/
void updateExternalTuioCursor(TuioCursor *tcur);
/**
* Removes an externally managed TuioCursor from the TuioServer's internal list of TuioCursor
* The referenced TuioCursor is not deleted
*
* @param tcur the TuioCursor to remove
*/
void removeExternalTuioCursor(TuioCursor *tcur);
/**
* Creates a new TuioBlob based on the given arguments.
* The new TuioBlob is added to the TuioServer's internal list of active TuioBlobs
* and a reference is returned to the caller.
*
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param angle the angle to assign
* @param width the width to assign
* @param height the height to assign
* @param area the area to assign
* @return reference to the created TuioBlob
*/
TuioBlob* addTuioBlob(float xp, float yp, float angle, float width, float height, float area);
/**
* Updates the referenced TuioBlob based on the given arguments.
*
* @param tblb the TuioObject to update
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param angle the angle to assign
* @param width the width to assign
* @param height the height to assign
* @param area the area to assign
*/
void updateTuioBlob(TuioBlob *tblb, float xp, float yp, float angle, float width, float height, float area);
/**
* Removes the referenced TuioBlob from the TuioServer's internal list of TuioBlobs
* and deletes the referenced TuioBlob afterwards
*
* @param tblb the TuioBlob to remove
*/
void removeTuioBlob(TuioBlob *tblb);
/**
* Updates an externally managed TuioBlob
*
* @param tblb the TuioBlob to update
*/
void addExternalTuioBlob(TuioBlob *tblb);
/**
* Updates an externally managed TuioBlob
*
* @param tblb the TuioBlob to update
*/
void updateExternalTuioBlob(TuioBlob *tblb);
/**
* Removes an externally managed TuioBlob from the TuioServer's internal list of TuioBlob
* The referenced TuioBlob is not deleted
*
* @param tblb the TuioBlob to remove
*/
void removeExternalTuioBlob(TuioBlob *tblb);
/**
* Initializes a new frame with the given TuioTime
*
* @param ttime the frame time
*/
void initFrame(TuioTime ttime);
/**
* Commits the current frame.
* Generates and sends TUIO messages of all currently active and updated TuioObjects and TuioCursors.
*/
void commitFrame();
/**
* Returns the next available Session ID for external use.
* @return the next available Session ID for external use
*/
long getSessionID();
/**
* Returns the current frame ID for external use.
* @return the current frame ID for external use
*/
long getFrameID();
/**
* Returns the current frame ID for external use.
* @return the current frame ID for external use
*/
TuioTime getFrameTime();
/**
* Returns a List of all currently inactive TuioObjects
*
* @return a List of all currently inactive TuioObjects
*/
std::list<TuioObject*> getUntouchedObjects();
/**
* Returns a List of all currently inactive TuioCursors
*
* @return a List of all currently inactive TuioCursors
*/
std::list<TuioCursor*> getUntouchedCursors();
/**
* Returns a List of all currently inactive TuioBlobs
*
* @return a List of all currently inactive TuioBlobs
*/
std::list<TuioBlob*> getUntouchedBlobs();
/**
* Calculates speed and acceleration values for all currently inactive TuioObjects
*/
void stopUntouchedMovingObjects();
/**
* Calculates speed and acceleration values for all currently inactive TuioCursors
*/
void stopUntouchedMovingCursors();
/**
* Calculates speed and acceleration values for all currently inactive TuioBlobs
*/
void stopUntouchedMovingBlobs();
/**
* Removes all currently inactive TuioObjects from the TuioServer's internal list of TuioObjects
*/
void removeUntouchedStoppedObjects();
/**
* Removes all currently inactive TuioCursors from the TuioServer's internal list of TuioCursors
*/
void removeUntouchedStoppedCursors();
/**
* Removes all currently inactive TuioCursors from the TuioServer's internal list of TuioBlobs
*/
void removeUntouchedStoppedBlobs();
/**
* Returns the TuioObject closest to the provided coordinates
* or NULL if there isn't any active TuioObject
*
* @return the closest TuioObject to the provided coordinates or NULL
*/
TuioObject* getClosestTuioObject(float xp, float yp);
/**
* Returns the TuioCursor closest to the provided coordinates
* or NULL if there isn't any active TuioCursor
*
* @return the closest TuioCursor corresponding to the provided coordinates or NULL
*/
TuioCursor* getClosestTuioCursor(float xp, float yp);
/**
* Returns the TuioBlob closest to the provided coordinates
* or NULL if there isn't any active TuioBlob
*
* @return the closest TuioBlob corresponding to the provided coordinates or NULL
*/
TuioBlob* getClosestTuioBlob(float xp, float yp);
/**
* The TuioServer prints verbose TUIO event messages to the console if set to true.
* @param verbose print verbose messages if set to true
*/
void setVerbose(bool verbose) { this->verbose=verbose; }
bool isVerbose() { return verbose; }
void setInversion(bool ix, bool iy, bool ia) {
invert_x = ix;
invert_y = iy;
invert_a = ia;
};
void setInvertXpos(bool ix) { invert_x = ix; };
void setInvertYpos(bool iy) { invert_y = iy; };
void setInvertAngle(bool ia) { invert_a = ia; };
bool getInvertXpos() { return invert_x; };
bool getInvertYpos() { return invert_y; };
bool getInvertAngle() { return invert_a; };
void resetTuioObjects();
void resetTuioCursors();
void resetTuioBlobs();
protected:
std::list<TuioCursor*> freeCursorList;
std::list<TuioCursor*> freeCursorBuffer;
std::list<TuioBlob*> freeBlobList;
std::list<TuioBlob*> freeBlobBuffer;
TuioTime currentFrameTime;
long currentFrame;
int maxCursorID;
int maxBlobID;
long sessionID;
bool updateObject;
bool updateCursor;
bool updateBlob;
bool verbose;
bool invert_x;
bool invert_y;
bool invert_a;
};
}
#endif /* INCLUDED_TUIOMANAGER_H */

View File

@@ -0,0 +1,165 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TuioObject.h"
using namespace TUIO;
TuioObject::TuioObject (TuioTime ttime, long si, int sym, float xp, float yp, float a):TuioContainer(ttime, si, xp, yp) {
symbol_id = sym;
angle = a;
angle_sum = a;
rotation_speed = 0.0f;
rotation_accel = 0.0f;
angleFilter = NULL;
angleThreshold = 0.0f;
}
TuioObject::TuioObject (long si, int sym, float xp, float yp, float a):TuioContainer(si, xp, yp) {
symbol_id = sym;
angle = a;
angle_sum = a;
rotation_speed = 0.0f;
rotation_accel = 0.0f;
angleFilter = NULL;
angleThreshold = 0.0f;
}
TuioObject::TuioObject (TuioObject *tobj):TuioContainer(tobj) {
symbol_id = tobj->getSymbolID();
angle = tobj->getAngle();
angle_sum = tobj->getAngleSum();
rotation_speed = 0.0f;
rotation_accel = 0.0f;
angleFilter = NULL;
angleThreshold = 0.0f;
}
void TuioObject::update (TuioTime ttime, float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) {
TuioContainer::update(ttime,xp,yp,xs,ys,ma);
angle = a;
angle_sum = a;
rotation_speed = rs;
rotation_accel = ra;
if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING;
}
void TuioObject::update (float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) {
TuioContainer::update(xp,yp,xs,ys,ma);
angle = a;
angle_sum = a;
rotation_speed = rs;
rotation_accel = ra;
if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING;
}
void TuioObject::update (TuioTime ttime, float xp, float yp, float a) {
TuioPoint lastPoint = path.back();
TuioContainer::update(ttime,xp,yp);
TuioTime diffTime = currentTime - lastPoint.getTuioTime();
float dt = diffTime.getTotalMilliseconds()/1000.0f;
float last_rotation_speed = rotation_speed;
float prev_angle = angle_sum;
float da = a-angle;
if (da > M_PI/2.0f) angle_sum += (da-2*M_PI);
else if (da < M_PI/-2.0f) angle_sum += (da+2*M_PI);
else angle_sum += da;
if (angleFilter) angle_sum = angleFilter->filter(angle_sum,dt);
if (fabs(angle_sum-prev_angle)<angleThreshold) angle_sum = prev_angle;
int m = floor(angle_sum/(2*M_PI));
angle = angle_sum-(m*(2*M_PI));
da = (angle-a)/(2*M_PI);
if (da > 0.75f) da-=1.0f;
else if (da < -0.75f) da+=1.0f;
rotation_speed = (float)da/dt;
rotation_accel = (rotation_speed - last_rotation_speed)/dt;
if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING;
}
void TuioObject::stop (TuioTime ttime) {
update(ttime,xpos,ypos,angle);
}
void TuioObject::update (TuioObject *tobj) {
TuioContainer::update(tobj);
angle = tobj->getAngle();
angle_sum = tobj->getAngleSum();
rotation_speed = tobj->getRotationSpeed();
rotation_accel = tobj->getRotationAccel();
if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING;
}
int TuioObject::getSymbolID() const{
return symbol_id;
}
float TuioObject::getAngle() const{
return angle;
}
float TuioObject::getAngleSum() const{
return angle_sum;
}
float TuioObject::getAngleDegrees() const{
return (float)(angle/M_PI*180);
}
float TuioObject::getRotationSpeed() const{
return rotation_speed;
}
float TuioObject::getRotationAccel() const{
return rotation_accel;
}
bool TuioObject::isMoving() const{
if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING) || (state==TUIO_ROTATING)) return true;
else return false;
}
void TuioObject::addAngleThreshold(float thresh) {
angleThreshold = thresh;
}
void TuioObject::removeAngleThreshold() {
angleThreshold = 0.0f;
}
void TuioObject::addAngleFilter(float mcut, float beta) {
if (angleFilter) delete angleFilter;
angleFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f);
}
void TuioObject::removeAngleFilter() {
if (angleFilter) delete angleFilter;
angleFilter = NULL;
}

View File

@@ -0,0 +1,213 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TUIOOBJECT_H
#define INCLUDED_TUIOOBJECT_H
#include "TuioContainer.h"
namespace TUIO {
/**
* The TuioObject class encapsulates /tuio/2Dobj TUIO objects.
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TuioObject: public TuioContainer {
protected:
/**
* The individual symbol ID number that is assigned to each TuioObject.
*/
int symbol_id;
/**
* The rotation angle value.
*/
float angle;
/**
* The accumulated angle value.
*/
float angle_sum;
/**
* The rotation speed value.
*/
float rotation_speed;
/**
* The rotation acceleration value.
*/
float rotation_accel;
float angleThreshold;
OneEuroFilter *angleFilter;
public:
using TuioContainer::update;
/**
* This constructor takes a TuioTime argument and assigns it along with the provided
* Session ID, Symbol ID, X and Y coordinate and angle to the newly created TuioObject.
*
* @param ttime the TuioTime to assign
* @param si the Session ID to assign
* @param sym the Symbol ID to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the angle to assign
*/
TuioObject (TuioTime ttime, long si, int sym, float xp, float yp, float a);
/**
* This constructor takes the provided Session ID, Symbol ID, X and Y coordinate
* and angle, and assigs these values to the newly created TuioObject.
*
* @param si the Session ID to assign
* @param sym the Symbol ID to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the angle to assign
*/
TuioObject (long si, int sym, float xp, float yp, float a);
/**
* This constructor takes the atttibutes of the provided TuioObject
* and assigs these values to the newly created TuioObject.
*
* @param tobj the TuioObject to assign
*/
TuioObject (TuioObject *tobj);
/**
* The destructor is doing nothing in particular.
*/
virtual ~TuioObject() {
if (angleFilter) delete angleFilter;
};
/**
* Takes a TuioTime argument and assigns it along with the provided
* X and Y coordinate, angle, X and Y velocity, motion acceleration,
* rotation speed and rotation acceleration to the private TuioObject attributes.
*
* @param ttime the TuioTime to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the angle coordinate to assign
* @param xs the X velocity to assign
* @param ys the Y velocity to assign
* @param rs the rotation velocity to assign
* @param ma the motion acceleration to assign
* @param ra the rotation acceleration to assign
*/
void update (TuioTime ttime, float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra);
/**
* Assigns the provided X and Y coordinate, angle, X and Y velocity, motion acceleration
* rotation velocity and rotation acceleration to the private TuioContainer attributes.
* The TuioTime time stamp remains unchanged.
*
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the angle coordinate to assign
* @param xs the X velocity to assign
* @param ys the Y velocity to assign
* @param rs the rotation velocity to assign
* @param ma the motion acceleration to assign
* @param ra the rotation acceleration to assign
*/
void update (float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra);
/**
* Takes a TuioTime argument and assigns it along with the provided
* X and Y coordinate and angle to the private TuioObject attributes.
* The speed and accleration values are calculated accordingly.
*
* @param ttime the TuioTime to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
* @param a the angle coordinate to assign
*/
void update (TuioTime ttime, float xp, float yp, float a);
/**
* This method is used to calculate the speed and acceleration values of a
* TuioObject with unchanged position and angle.
*/
void stop (TuioTime ttime);
/**
* Takes the atttibutes of the provided TuioObject
* and assigs these values to this TuioObject.
* The TuioTime time stamp of this TuioContainer remains unchanged.
*
* @param tobj the TuioContainer to assign
*/
void update (TuioObject *tobj);
/**
* Returns the symbol ID of this TuioObject.
* @return the symbol ID of this TuioObject
*/
int getSymbolID() const;
/**
* Returns the rotation angle of this TuioObject.
* @return the rotation angle of this TuioObject
*/
float getAngle() const;
/**
* Returns the accumulated rotation angle of this TuioObject.
* @return the accumulated rotation angle of this TuioObject
*/
float getAngleSum() const;
/**
* Returns the rotation angle in degrees of this TuioObject.
* @return the rotation angle in degrees of this TuioObject
*/
float getAngleDegrees() const;
/**
* Returns the rotation speed of this TuioObject.
* @return the rotation speed of this TuioObject
*/
float getRotationSpeed() const;
/**
* Returns the rotation acceleration of this TuioObject.
* @return the rotation acceleration of this TuioObject
*/
float getRotationAccel() const;
/**
* Returns true of this TuioObject is moving.
* @return true of this TuioObject is moving
*/
bool isMoving() const;
void addAngleThreshold(float thresh);
void removeAngleThreshold();
void addAngleFilter(float mcut, float beta);
void removeAngleFilter();
};
}
#endif

View File

@@ -0,0 +1,176 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TuioPoint.h"
using namespace TUIO;
TuioPoint::TuioPoint (float xp, float yp) {
xpos = xp;
ypos = yp;
currentTime = TuioTime::getSessionTime();
startTime = currentTime;
xposFilter = NULL;
yposFilter = NULL;
posThreshold = 0.0f;
}
TuioPoint::TuioPoint (TuioTime ttime, float xp, float yp) {
xpos = xp;
ypos = yp;
currentTime = ttime;
startTime = currentTime;
xposFilter = NULL;
yposFilter = NULL;
posThreshold = 0.0f;
}
TuioPoint::TuioPoint (TuioPoint *tpoint) {
xpos = tpoint->getX();
ypos = tpoint->getY();
currentTime = TuioTime::getSessionTime();
startTime = currentTime;
xposFilter = NULL;
yposFilter = NULL;
posThreshold = 0.0f;
}
void TuioPoint::update (TuioPoint *tpoint) {
xpos = tpoint->getX();
ypos = tpoint->getY();
}
void TuioPoint::update (float xp, float yp) {
xpos = xp;
ypos = yp;
}
void TuioPoint::update (TuioTime ttime, float xp, float yp) {
if (xposFilter && yposFilter) {
TuioTime diffTime = ttime - startTime;
float dt = diffTime.getTotalMilliseconds()/1000.0f;
xp = xposFilter->filter(xp,dt);
yp = yposFilter->filter(yp,dt);
//std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl;
}
float dx = fabs(xpos - xp);
float dy = fabs(ypos - yp);
if ((dx>posThreshold) || (dy>posThreshold)) {
xpos = xp;
ypos = yp;
}
currentTime = ttime;
}
float TuioPoint::getX() const{
return xpos;
}
float TuioPoint::getY() const{
return ypos;
}
float TuioPoint::getDistance(float xp, float yp) const{
float dx = xpos-xp;
float dy = ypos-yp;
return sqrtf(dx*dx+dy*dy);
}
float TuioPoint::getScreenDistance(float xp, float yp, int w, int h) const{
float dx = w*xpos-w*xp;
float dy = h*ypos-h*yp;
return sqrtf(dx*dx+dy*dy);
}
float TuioPoint::getDistance(TuioPoint *tpoint) const{
return getDistance(tpoint->getX(),tpoint->getY());
}
float TuioPoint::getAngle(float xp, float yp) const{
float side = xpos-xp;
float height = ypos-yp;
float distance = getDistance(xp,yp);
float angle = (float)(asin(side/distance)+M_PI/2);
if (height<0) angle = 2.0f*(float)M_PI-angle;
return angle;
}
float TuioPoint::getAngle(TuioPoint *tpoint) const{
return getAngle(tpoint->getX(),tpoint->getY());
}
float TuioPoint::getAngleDegrees(float xp, float yp) const{
return ((getAngle(xp,yp)/(float)M_PI)*180.0f);
}
float TuioPoint::getAngleDegrees(TuioPoint *tpoint) const{
return ((getAngle(tpoint)/(float)M_PI)*180.0f);
}
int TuioPoint::getScreenX(int width) const{
return (int)floor(xpos*width+0.5f);
}
int TuioPoint::getScreenY(int height) const{
return (int)floor(ypos*height+0.5f);
}
TuioTime TuioPoint::getTuioTime() const{
return currentTime;
}
TuioTime TuioPoint::getStartTime() const{
return startTime;
}
void TuioPoint::addPositionThreshold(float thresh) {
posThreshold = thresh;
}
void TuioPoint::removePositionThreshold() {
posThreshold = 0.0f;
}
void TuioPoint::addPositionFilter(float mcut, float beta) {
if (xposFilter) delete xposFilter;
xposFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f);
if (yposFilter) delete yposFilter;
yposFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f);
}
void TuioPoint::removePositionFilter() {
if (xposFilter) delete xposFilter;
xposFilter = NULL;
if (yposFilter) delete yposFilter;
yposFilter = NULL;
}

View File

@@ -0,0 +1,226 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TUIOPOINT_H
#define INCLUDED_TUIOPOINT_H
#include "TuioTime.h"
#include "OneEuroFilter.h"
#include <cmath>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
namespace TUIO {
/**
* The TuioPoint class on the one hand is a simple container and utility class to handle TUIO positions in general,
* on the other hand the TuioPoint is the base class for the TuioCursor and TuioObject classes.
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TuioPoint {
protected:
/**
* X coordinate, representated as a floating point value in a range of 0..1
*/
float xpos;
/**
* X coordinate, representated as a floating point value in a range of 0..1
*/
float ypos;
/**
* The time stamp of the last update represented as TuioTime (time since session start)
*/
TuioTime currentTime;
/**
* The creation time of this TuioPoint represented as TuioTime (time since session start)
*/
TuioTime startTime;
OneEuroFilter *xposFilter;
OneEuroFilter *yposFilter;
float posThreshold;
public:
/**
* The default constructor takes no arguments and sets
* its coordinate attributes to zero and its time stamp to the current session time.
*/
TuioPoint (float xp, float yp);
/**
* This constructor takes a TuioTime object and two floating point coordinate arguments and sets
* its coordinate attributes to these values and its time stamp to the provided TUIO time object.
*
* @param ttime the TuioTime to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
*/
TuioPoint (TuioTime ttime, float xp, float yp);
/**
* This constructor takes a TuioPoint argument and sets its coordinate attributes
* to the coordinates of the provided TuioPoint and its time stamp to the current session time.
*
* @param tpoint the TuioPoint to assign
*/
TuioPoint (TuioPoint *tpoint);
/**
* The destructor is doing nothing in particular.
*/
virtual ~TuioPoint(){
if (xposFilter) delete xposFilter;
if (yposFilter) delete yposFilter;
};
/**
* Takes a TuioPoint argument and updates its coordinate attributes
* to the coordinates of the provided TuioPoint and leaves its time stamp unchanged.
*
* @param tpoint the TuioPoint to assign
*/
void update (TuioPoint *tpoint);
/**
* Takes two floating point coordinate arguments and updates its coordinate attributes
* to the coordinates of the provided TuioPoint and leaves its time stamp unchanged.
*
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
*/
void update (float xp, float yp);
/**
* Takes a TuioTime object and two floating point coordinate arguments and updates its coordinate attributes
* to the coordinates of the provided TuioPoint and its time stamp to the provided TUIO time object.
*
* @param ttime the TuioTime to assign
* @param xp the X coordinate to assign
* @param yp the Y coordinate to assign
*/
void update (TuioTime ttime, float xp, float yp);
/**
* Returns the X coordinate of this TuioPoint.
* @return the X coordinate of this TuioPoint
*/
float getX() const;
/**
* Returns the Y coordinate of this TuioPoint.
* @return the Y coordinate of this TuioPoint
*/
float getY() const;
/**
* Returns the distance to the provided coordinates
*
* @param xp the X coordinate of the distant point
* @param yp the Y coordinate of the distant point
* @return the distance to the provided coordinates
*/
float getDistance(float xp, float yp) const;
/**
* Returns the distance to the provided coordinates
*
* @param xp the X coordinate of the distant point
* @param yp the Y coordinate of the distant point
* @return the distance to the provided coordinates
*/
float getScreenDistance(float xp, float yp, int w, int h) const;
/**
* Returns the distance to the provided TuioPoint
*
* @param tpoint the distant TuioPoint
* @return the distance to the provided TuioPoint
*/
float getDistance(TuioPoint *tpoint) const;
/**
* Returns the angle to the provided coordinates
*
* @param xp the X coordinate of the distant point
* @param yp the Y coordinate of the distant point
* @return the angle to the provided coordinates
*/
float getAngle(float xp, float yp) const;
/**
* Returns the angle to the provided TuioPoint
*
* @param tpoint the distant TuioPoint
* @return the angle to the provided TuioPoint
*/
float getAngle(TuioPoint *tpoint) const;
/**
* Returns the angle in degrees to the provided coordinates
*
* @param xp the X coordinate of the distant point
* @param yp the Y coordinate of the distant point
* @return the angle in degrees to the provided TuioPoint
*/
float getAngleDegrees(float xp, float yp) const;
/**
* Returns the angle in degrees to the provided TuioPoint
*
* @param tpoint the distant TuioPoint
* @return the angle in degrees to the provided TuioPoint
*/
float getAngleDegrees(TuioPoint *tpoint) const;
/**
* Returns the X coordinate in pixels relative to the provided screen width.
*
* @param width the screen width
* @return the X coordinate of this TuioPoint in pixels relative to the provided screen width
*/
int getScreenX(int width) const;
/*
* Returns the Y coordinate in pixels relative to the provided screen height.
*
* @param height the screen height
* @return the Y coordinate of this TuioPoint in pixels relative to the provided screen height
*/
int getScreenY(int height) const;
/**
* Returns current time stamp of this TuioPoint as TuioTime
*
* @return the time stamp of this TuioPoint as TuioTime
*/
TuioTime getTuioTime() const;
/**
* Returns the start time of this TuioPoint as TuioTime.
*
* @return the start time of this TuioPoint as TuioTime
*/
TuioTime getStartTime() const;
void addPositionThreshold(float thresh);
void removePositionThreshold();
void addPositionFilter(float mcut, float beta);
void removePositionFilter();
};
}
#endif

View File

@@ -0,0 +1,634 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TuioServer.h"
#include "UdpSender.h"
using namespace TUIO;
using namespace osc;
TuioServer::TuioServer()
:full_update (false)
,periodic_update (false)
,objectProfileEnabled (true)
,cursorProfileEnabled (true)
,blobProfileEnabled (true)
,source_name (NULL)
{
OscSender *oscsend = new UdpSender();
initialize(oscsend);
}
TuioServer::TuioServer(const char *host, int port)
:full_update (false)
,periodic_update (false)
,objectProfileEnabled (true)
,cursorProfileEnabled (true)
,blobProfileEnabled (true)
,source_name (NULL)
{
OscSender *oscsend = new UdpSender(host,port);
initialize(oscsend);
}
TuioServer::TuioServer(OscSender *oscsend)
:full_update (false)
,periodic_update (false)
,objectProfileEnabled (true)
,cursorProfileEnabled (true)
,blobProfileEnabled (true)
,source_name (NULL)
{
initialize(oscsend);
}
void TuioServer::initialize(OscSender *oscsend) {
senderList.push_back(oscsend);
int size = oscsend->getBufferSize();
oscBuffer = new char[size];
oscPacket = new osc::OutboundPacketStream(oscBuffer,size);
fullBuffer = new char[size];
fullPacket = new osc::OutboundPacketStream(oscBuffer,size);
objectUpdateTime = TuioTime(currentFrameTime);
cursorUpdateTime = TuioTime(currentFrameTime);
blobUpdateTime = TuioTime(currentFrameTime);
if (cursorProfileEnabled) sendEmptyCursorBundle();
if (objectProfileEnabled) sendEmptyObjectBundle();
if (blobProfileEnabled) sendEmptyBlobBundle();
invert_x = false;
invert_y = false;
invert_a = false;
}
TuioServer::~TuioServer() {
initFrame(TuioTime::getSessionTime());
stopUntouchedMovingCursors();
stopUntouchedMovingObjects();
stopUntouchedMovingBlobs();
initFrame(TuioTime::getSessionTime());
removeUntouchedStoppedCursors();
removeUntouchedStoppedObjects();
removeUntouchedStoppedBlobs();
if (cursorProfileEnabled) sendEmptyCursorBundle();
if (objectProfileEnabled) sendEmptyObjectBundle();
if (blobProfileEnabled) sendEmptyBlobBundle();
delete []oscBuffer;
delete oscPacket;
delete []fullBuffer;
delete fullPacket;
if (source_name) delete[] source_name;
for (unsigned int i=0;i<senderList.size();i++)
delete senderList[i];
}
void TuioServer::addOscSender(OscSender *sender) {
// add source address if previously local
/*if ((source_name) && (primary_sender->isLocal()) && (senderList.size()==1)) {
setSourceName(source_name);
}*/
// resize packets to smallest transport method
unsigned int size = sender->getBufferSize();
if (size<oscPacket->Capacity()) {
osc::OutboundPacketStream *temp = oscPacket;
oscPacket = new osc::OutboundPacketStream(oscBuffer,size);
delete temp;
temp = fullPacket;
fullPacket = new osc::OutboundPacketStream(oscBuffer,size);
delete temp;
}
senderList.push_back(sender);
}
void TuioServer::deliverOscPacket(osc::OutboundPacketStream *packet) {
for (unsigned int i=0;i<senderList.size();i++)
senderList[i]->sendOscPacket(packet);
}
void TuioServer::setSourceName(const char *name, const char *ip) {
if (!source_name) source_name = new char[256];
sprintf(source_name,"%s@%s",name,ip);
}
void TuioServer::setSourceName(const char *src) {
if (!source_name) source_name = new char[256];
/*if (senderList[0]->isLocal()) {
sprintf(source_name,"%s",src);
} else {*/
char hostname[64];
char *source_addr = NULL;
struct hostent *hp = NULL;
struct in_addr *addr = NULL;
gethostname(hostname, 64);
hp = gethostbyname(hostname);
if (hp==NULL) {
sprintf(hostname, "%s.local", hostname);
hp = gethostbyname(hostname);
}
if (hp!=NULL) {
for (int i = 0; hp->h_addr_list[i] != 0; ++i) {
addr = (struct in_addr *)(hp->h_addr_list[i]);
//std::cout << inet_ntoa(*addr) << std::endl;
source_addr = inet_ntoa(*addr);
}
} else {
//generate a random internet address
srand ( (unsigned int)time(NULL) );
int32 r = rand();
addr = (struct in_addr*)&r;
source_addr = inet_ntoa(*addr);
}
sprintf(source_name,"%s@%s",src,source_addr);
//}
std::cout << "tuio/src " << source_name << std::endl;
}
void TuioServer::commitFrame() {
TuioManager::commitFrame();
if(updateObject) {
startObjectBundle();
for (std::list<TuioObject*>::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) {
// start a new packet if we exceed the packet capacity
if ((oscPacket->Capacity()-oscPacket->Size())<OBJ_MESSAGE_SIZE) {
sendObjectBundle(currentFrame);
startObjectBundle();
}
TuioObject *tobj = (*tuioObject);
if ((full_update) || (tobj->getTuioTime()==currentFrameTime)) addObjectMessage(tobj);
}
objectUpdateTime = TuioTime(currentFrameTime);
sendObjectBundle(currentFrame);
} else if (objectProfileEnabled && periodic_update) {
TuioTime timeCheck = currentFrameTime - objectUpdateTime;
if(timeCheck.getSeconds()>=update_interval) {
objectUpdateTime = TuioTime(currentFrameTime);
startObjectBundle();
if (full_update) {
for (std::list<TuioObject*>::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) {
// start a new packet if we exceed the packet capacity
if ((oscPacket->Capacity()-oscPacket->Size())<OBJ_MESSAGE_SIZE) {
sendObjectBundle(currentFrame);
startObjectBundle();
}
addObjectMessage(*tuioObject);
}
}
sendObjectBundle(currentFrame);
}
}
updateObject = false;
if(updateCursor) {
startCursorBundle();
for (std::list<TuioCursor*>::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) {
// start a new packet if we exceed the packet capacity
if ((oscPacket->Capacity()-oscPacket->Size())<CUR_MESSAGE_SIZE) {
sendCursorBundle(currentFrame);
startCursorBundle();
}
TuioCursor *tcur = (*tuioCursor);
if ((full_update) || (tcur->getTuioTime()==currentFrameTime)) addCursorMessage(tcur);
}
cursorUpdateTime = TuioTime(currentFrameTime);
sendCursorBundle(currentFrame);
} else if (cursorProfileEnabled && periodic_update) {
TuioTime timeCheck = currentFrameTime - cursorUpdateTime;
if(timeCheck.getSeconds()>=update_interval) {
cursorUpdateTime = TuioTime(currentFrameTime);
startCursorBundle();
if (full_update) {
for (std::list<TuioCursor*>::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) {
// start a new packet if we exceed the packet capacity
if ((oscPacket->Capacity()-oscPacket->Size())<CUR_MESSAGE_SIZE) {
sendCursorBundle(currentFrame);
startCursorBundle();
}
addCursorMessage(*tuioCursor);
}
}
sendCursorBundle(currentFrame);
}
}
updateCursor = false;
if(updateBlob) {
startBlobBundle();
for (std::list<TuioBlob*>::iterator tuioBlob =blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) {
// start a new packet if we exceed the packet capacity
if ((oscPacket->Capacity()-oscPacket->Size())<BLB_MESSAGE_SIZE) {
sendBlobBundle(currentFrame);
startBlobBundle();
}
TuioBlob *tblb = (*tuioBlob);
if ((full_update) || (tblb->getTuioTime()==currentFrameTime)) addBlobMessage(tblb);
}
blobUpdateTime = TuioTime(currentFrameTime);
sendBlobBundle(currentFrame);
} else if (blobProfileEnabled && periodic_update) {
TuioTime timeCheck = currentFrameTime - blobUpdateTime;
if(timeCheck.getSeconds()>=update_interval) {
blobUpdateTime = TuioTime(currentFrameTime);
startBlobBundle();
if (full_update) {
for (std::list<TuioBlob*>::iterator tuioBlob =blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) {
// start a new packet if we exceed the packet capacity
if ((oscPacket->Capacity()-oscPacket->Size())<BLB_MESSAGE_SIZE) {
sendBlobBundle(currentFrame);
startBlobBundle();
}
addBlobMessage(*tuioBlob);
}
}
sendBlobBundle(currentFrame);
}
}
updateBlob = false;
}
void TuioServer::sendEmptyCursorBundle() {
oscPacket->Clear();
(*oscPacket) << osc::BeginBundleImmediate;
if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage;
(*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive" << osc::EndMessage;
(*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << -1 << osc::EndMessage;
(*oscPacket) << osc::EndBundle;
deliverOscPacket( oscPacket );
}
void TuioServer::startCursorBundle() {
oscPacket->Clear();
(*oscPacket) << osc::BeginBundleImmediate;
if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage;
(*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive";
for (std::list<TuioCursor*>::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) {
if ((*tuioCursor)->getTuioState()!=TUIO_ADDED) (*oscPacket) << (int32)((*tuioCursor)->getSessionID());
}
(*oscPacket) << osc::EndMessage;
}
void TuioServer::addCursorMessage(TuioCursor *tcur) {
if (tcur->getTuioState()==TUIO_ADDED) return;
float xpos = tcur->getX();
float xvel = tcur->getXSpeed();
if (invert_x) {
xpos = 1 - xpos;
xvel = -1 * xvel;
}
float ypos = tcur->getY();
float yvel = tcur->getYSpeed();
if (invert_y) {
ypos = 1 - ypos;
yvel = -1 * yvel;
}
(*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "set";
(*oscPacket) << (int32)(tcur->getSessionID()) << xpos << ypos;
(*oscPacket) << xvel << yvel << tcur->getMotionAccel();
(*oscPacket) << osc::EndMessage;
}
void TuioServer::sendCursorBundle(long fseq) {
(*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << (int32)fseq << osc::EndMessage;
(*oscPacket) << osc::EndBundle;
deliverOscPacket( oscPacket );
}
void TuioServer::sendEmptyObjectBundle() {
oscPacket->Clear();
(*oscPacket) << osc::BeginBundleImmediate;
if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage;
(*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive" << osc::EndMessage;
(*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << -1 << osc::EndMessage;
(*oscPacket) << osc::EndBundle;
deliverOscPacket( oscPacket );
}
void TuioServer::startObjectBundle() {
oscPacket->Clear();
(*oscPacket) << osc::BeginBundleImmediate;
if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage;
(*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive";
for (std::list<TuioObject*>::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) {
(*oscPacket) << (int32)((*tuioObject)->getSessionID());
}
(*oscPacket) << osc::EndMessage;
}
void TuioServer::addObjectMessage(TuioObject *tobj) {
float xpos = tobj->getX();
float xvel = tobj->getXSpeed();
if (invert_x) {
xpos = 1 - xpos;
xvel = -1 * xvel;
}
float ypos = tobj->getY();
float yvel = tobj->getYSpeed();
if (invert_y) {
ypos = 1 - ypos;
yvel = -1 * yvel;
}
float angle = tobj->getAngle();
float rvel = tobj->getRotationSpeed();
if (invert_a) {
angle = 2.0f*(float)M_PI - angle;
rvel = -1 * rvel;
}
(*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "set";
(*oscPacket) << (int32)(tobj->getSessionID()) << tobj->getSymbolID() << xpos << ypos << angle;
(*oscPacket) << xvel << yvel << rvel << tobj->getMotionAccel() << tobj->getRotationAccel();
(*oscPacket) << osc::EndMessage;
}
void TuioServer::sendObjectBundle(long fseq) {
(*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << (int32)fseq << osc::EndMessage;
(*oscPacket) << osc::EndBundle;
deliverOscPacket( oscPacket );
}
void TuioServer::sendEmptyBlobBundle() {
oscPacket->Clear();
(*oscPacket) << osc::BeginBundleImmediate;
if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage;
(*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive" << osc::EndMessage;
(*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << -1 << osc::EndMessage;
(*oscPacket) << osc::EndBundle;
deliverOscPacket( oscPacket );
}
void TuioServer::startBlobBundle() {
oscPacket->Clear();
(*oscPacket) << osc::BeginBundleImmediate;
if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage;
(*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive";
for (std::list<TuioBlob*>::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) {
if ((*tuioBlob)->getTuioState()!=TUIO_ADDED) (*oscPacket) << (int32)((*tuioBlob)->getSessionID());
}
(*oscPacket) << osc::EndMessage;
}
void TuioServer::addBlobMessage(TuioBlob *tblb) {
if (tblb->getTuioState()==TUIO_ADDED) return;
float xpos = tblb->getX();
float xvel = tblb->getXSpeed();
if (invert_x) {
xpos = 1 - xpos;
xvel = -1 * xvel;
}
float ypos = tblb->getY();
float yvel = tblb->getYSpeed();
if (invert_y) {
ypos = 1 - ypos;
yvel = -1 * yvel;
}
float angle = tblb->getAngle();
float rvel = tblb->getRotationSpeed();
if (invert_a) {
angle = 2.0f*(float)M_PI - angle;
rvel = -1 * rvel;
}
(*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "set";
(*oscPacket) << (int32)(tblb->getSessionID()) << xpos << ypos << angle << tblb->getWidth() << tblb->getHeight() << tblb->getArea();
(*oscPacket) << xvel << yvel << rvel << tblb->getMotionAccel() << tblb->getRotationAccel();
(*oscPacket) << osc::EndMessage;
}
void TuioServer::sendBlobBundle(long fseq) {
(*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << (int32)fseq << osc::EndMessage;
(*oscPacket) << osc::EndBundle;
deliverOscPacket( oscPacket );
}
void TuioServer::sendFullMessages() {
// prepare the cursor packet
fullPacket->Clear();
(*fullPacket) << osc::BeginBundleImmediate;
if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage;
// add the cursor alive message
(*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive";
for (std::list<TuioCursor*>::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++)
(*fullPacket) << (int32)((*tuioCursor)->getSessionID());
(*fullPacket) << osc::EndMessage;
// add all current cursor set messages
for (std::list<TuioCursor*>::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) {
// start a new packet if we exceed the packet capacity
if ((fullPacket->Capacity()-fullPacket->Size())<CUR_MESSAGE_SIZE) {
// add the immediate fseq message and send the cursor packet
(*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << -1 << osc::EndMessage;
(*fullPacket) << osc::EndBundle;
deliverOscPacket( fullPacket );
// prepare the new cursor packet
fullPacket->Clear();
(*fullPacket) << osc::BeginBundleImmediate;
if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage;
// add the cursor alive message
(*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive";
for (std::list<TuioCursor*>::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++)
(*fullPacket) << (int32)((*tuioCursor)->getSessionID());
(*fullPacket) << osc::EndMessage;
}
float xpos = (*tuioCursor)->getX();
float xvel = (*tuioCursor)->getXSpeed();
if (invert_x) {
xpos = 1 - xpos;
xvel = -1 * xvel;
}
float ypos = (*tuioCursor)->getY();
float yvel = (*tuioCursor)->getYSpeed();
if (invert_y) {
ypos = 1 - ypos;
yvel = -1 * yvel;
}
// add the actual cursor set message
(*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "set";
(*fullPacket) << (int32)((*tuioCursor)->getSessionID()) << xpos << ypos;
(*fullPacket) << xvel << yvel <<(*tuioCursor)->getMotionAccel();
(*fullPacket) << osc::EndMessage;
}
// add the immediate fseq message and send the cursor packet
(*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << -1 << osc::EndMessage;
(*fullPacket) << osc::EndBundle;
deliverOscPacket( fullPacket );
// prepare the object packet
fullPacket->Clear();
(*fullPacket) << osc::BeginBundleImmediate;
if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage;
// add the object alive message
(*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive";
for (std::list<TuioObject*>::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++)
(*fullPacket) << (int32)((*tuioObject)->getSessionID());
(*fullPacket) << osc::EndMessage;
for (std::list<TuioObject*>::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) {
// start a new packet if we exceed the packet capacity
if ((fullPacket->Capacity()-fullPacket->Size())<OBJ_MESSAGE_SIZE) {
// add the immediate fseq message and send the object packet
(*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << -1 << osc::EndMessage;
(*fullPacket) << osc::EndBundle;
deliverOscPacket( fullPacket );
// prepare the new object packet
fullPacket->Clear();
(*fullPacket) << osc::BeginBundleImmediate;
if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage;
// add the object alive message
(*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive";
for (std::list<TuioObject*>::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++)
(*fullPacket) << (int32)((*tuioObject)->getSessionID());
(*fullPacket) << osc::EndMessage;
}
float xpos = (*tuioObject)->getX();
float xvel = (*tuioObject)->getXSpeed();
if (invert_x) {
xpos = 1 - xpos;
xvel = -1 * xvel;
}
float ypos = (*tuioObject)->getY();
float yvel = (*tuioObject)->getYSpeed();
if (invert_y) {
ypos = 1 - ypos;
yvel = -1 * yvel;
}
float angle = (*tuioObject)->getAngle();
float rvel = (*tuioObject)->getRotationSpeed();
if (invert_a) {
angle = 2.0f*(float)M_PI - angle;
rvel = -1 * rvel;
}
// add the actual object set message
(*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "set";
(*fullPacket) << (int32)((*tuioObject)->getSessionID()) << (*tuioObject)->getSymbolID() << xpos << ypos << angle;
(*fullPacket) << xvel << yvel << rvel << (*tuioObject)->getMotionAccel() << (*tuioObject)->getRotationAccel();
(*fullPacket) << osc::EndMessage;
}
// add the immediate fseq message and send the object packet
(*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << -1 << osc::EndMessage;
(*fullPacket) << osc::EndBundle;
deliverOscPacket( fullPacket );
// prepare the blob packet
fullPacket->Clear();
(*fullPacket) << osc::BeginBundleImmediate;
if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage;
// add the object alive message
(*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive";
for (std::list<TuioBlob*>::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++)
(*fullPacket) << (int32)((*tuioBlob)->getSessionID());
(*fullPacket) << osc::EndMessage;
for (std::list<TuioBlob*>::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) {
// start a new packet if we exceed the packet capacity
if ((fullPacket->Capacity()-fullPacket->Size())<BLB_MESSAGE_SIZE) {
// add the immediate fseq message and send the object packet
(*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << -1 << osc::EndMessage;
(*fullPacket) << osc::EndBundle;
deliverOscPacket( fullPacket );
// prepare the new blob packet
fullPacket->Clear();
(*fullPacket) << osc::BeginBundleImmediate;
if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage;
// add the blob alive message
(*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive";
for (std::list<TuioBlob*>::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++)
(*fullPacket) << (int32)((*tuioBlob)->getSessionID());
(*fullPacket) << osc::EndMessage;
}
float xpos = (*tuioBlob)->getX();
float xvel = (*tuioBlob)->getXSpeed();
if (invert_x) {
xpos = 1 - xpos;
xvel = -1 * xvel;
}
float ypos = (*tuioBlob)->getY();
float yvel = (*tuioBlob)->getYSpeed();
if (invert_y) {
ypos = 1 - ypos;
yvel = -1 * yvel;
}
float angle = (*tuioBlob)->getAngle();
float rvel = (*tuioBlob)->getRotationSpeed();
if (invert_a) {
angle = 2.0f*(float)M_PI - angle;
rvel = -1 * rvel;
}
// add the actual blob set message
(*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "set";
(*fullPacket) << (int32)((*tuioBlob)->getSessionID()) << xpos << ypos << angle << (*tuioBlob)->getWidth() << (*tuioBlob)->getHeight() << (*tuioBlob)->getArea();
(*fullPacket) << xvel << yvel << rvel << (*tuioBlob)->getMotionAccel() << (*tuioBlob)->getRotationAccel();
(*fullPacket) << osc::EndMessage;
}
// add the immediate fseq message and send the blob packet
(*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << -1 << osc::EndMessage;
(*fullPacket) << osc::EndBundle;
deliverOscPacket( fullPacket );
}

View File

@@ -0,0 +1,230 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TuioServer_H
#define INCLUDED_TuioServer_H
#include "TuioManager.h"
#include "UdpSender.h"
#include "TcpSender.h"
#include "WebSockSender.h"
#include "FlashSender.h"
#include <iostream>
#include <vector>
#include <stdio.h>
#ifndef WIN32
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
namespace TUIO {
/**
* <p>The TuioServer class is the central TUIO protocol encoder component.
* In order to encode and send TUIO messages an instance of TuioServer needs to be created. The TuioServer instance then generates TUIO messages
* which are deliverered by the provided OSCSender. The shown UDPSender send OSC to UDP port 3333 on localhost or to the configured host and port.</p>
* <p>During runtime the each frame is marked with the initFrame and commitFrame methods,
* while the currently present TuioObjects are managed by the server with ADD, UPDATE and REMOVE methods in analogy to the TuioClient's TuioListener interface.</p>
*<p>See the SimpleSimulator example project for further hints on how to use the TuioServer class and its various methods.
* <p><code>
* OscSender *sender = new UDPSender();</br>
* TuioServer *server = new TuioServer(sender);<br/>
* server->setSourceName("MyTuioSource"); // optional for TUIO 1.1<br/>
* ...<br/>
* server->initFrame(TuioTime::getSessionTime());<br/>
* TuioObject *tobj = server->addTuioObject(xpos,ypos,angle);<br/>
* TuioCursor *tcur = server->addTuiCursor(xpos,ypos);<br/>
* TuioBlob *tblb = server->addTuioBlob(xpos,ypos,angle,width,height, area);<br/>
* server->commitFrame();<br/>
* ...<br/>
* server->initFrame(TuioTime::getSessionTime());<br/>
* server->updateTuioObject(tobj,xpos,ypos,angle);<br/>
* server->updateTuioCursor(tcur,xpos,ypos);<br/>
* server->updateTuioBlob(tblb,xpos,ypos,angle,width,height,area);<br/>
* server->commitFrame();<br/>
* ...<br/>
* server->initFrame(TuioTime::getSessionTime());<br/>
* server->removeTuioObject(tobj);<br/>
* server->removeTuioCursor(tcur);<br/>
* server->removeTuioBlob(tblb);<br/>
* server->commitFrame();<br/>
* </code></p>
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TuioServer : public TuioManager {
public:
/**
* This constructor creates a TuioServer that uses an internal UdpSender delivering the OSC data via UDP port 3333 on localhost
*/
TuioServer();
/**
* This constructor creates a TuioServer that uses an internal UdpSender delivering the OSC data via the provided UDP port on the provided host
*
* @param host the host name for UDP deleivery
* @param port the UDP port number on the provided host
*/
TuioServer(const char *host, int port);
/**
* This constructor creates a TuioServer that sends OSC data using the provided OscSender
*
* @param sender the OscSender used for OSC data delivery
*/
TuioServer(OscSender *sender);
/**
* The destructor is doing nothing in particular.
*/
~TuioServer();
/**
* Generates and sends TUIO messages of all currently active TuioObjects, TuioCursors and TuioBlobs
*/
void sendFullMessages();
/**
* Enables the full update of all currently active and inactive TuioObjects, TuioCursors and TuioBlobs
*
*/
void enableFullUpdate() {
full_update = true;
}
/**
* Disables the full update of all currently active and inactive TuioObjects, TuioCursors and TuioBlobs
*/
void disableFullUpdate() {
full_update = false;
}
/**
* Returns true if the full update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled.
* @return true if the full update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled
*/
bool fullUpdateEnabled() {
return full_update;
}
/**
* Disables the periodic full update of all currently active TuioObjects TuioObjects, TuioCursors and TuioBlobs
*
* @param interval update interval in seconds, defaults to one second
*/
void enablePeriodicMessages(int interval=1) {
periodic_update = true;
update_interval = interval;
}
/**
* Disables the periodic full update of all currently active and inactive TuioObjects, TuioCursors and TuioBlobs
*/
void disablePeriodicMessages() {
periodic_update = false;
}
/**
* Returns true if the periodic update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled.
* @return true if the periodic update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled
*/
bool periodicMessagesEnabled() {
return periodic_update;
}
/**
* Returns the periodic update interval in seconds.
* @return the periodic update interval in seconds
*/
int getUpdateInterval() {
return update_interval;
}
/**
* Commits the current frame.
* Generates and sends TUIO messages of all currently active and updated TuioObjects, TuioCursors and TuioBlobs.
*/
void commitFrame();
/**
* Commits the current frame.
* Generates and sends TUIO messages of all currently active and updated TuioObjects, TuioCursors and TuioBlobs.
*/
/**
* Defines the name of this TUIO source, which is transmitted within the /tuio/[profile] source message.
*
* @param name the desired name of this TUIO source
*/
void setSourceName(const char *name);
/**
* Defines the name and IP address of this TUIO source, which is transmitted within the /tuio/[profile] source message.
*
* @param name the desired name of this TUIO source
* @param ip the local IP address
*/
void setSourceName(const char *name, const char *ip);
void addOscSender(OscSender *sender);
void enableObjectProfile(bool flag) { objectProfileEnabled = flag; };
void enableCursorProfile(bool flag) { cursorProfileEnabled = flag; };
void enableBlobProfile(bool flag) { blobProfileEnabled = flag; };
private:
void initialize(OscSender *oscsend);
std::vector<OscSender*> senderList;
void deliverOscPacket(osc::OutboundPacketStream *packet);
osc::OutboundPacketStream *oscPacket;
char *oscBuffer;
osc::OutboundPacketStream *fullPacket;
char *fullBuffer;
void startObjectBundle();
void addObjectMessage(TuioObject *tobj);
void sendObjectBundle(long fseq);
void sendEmptyObjectBundle();
void startCursorBundle();
void addCursorMessage(TuioCursor *tcur);
void sendCursorBundle(long fseq);
void sendEmptyCursorBundle();
void startBlobBundle();
void addBlobMessage(TuioBlob *tblb);
void sendBlobBundle(long fseq);
void sendEmptyBlobBundle();
int update_interval;
bool full_update, periodic_update;
TuioTime objectUpdateTime, cursorUpdateTime, blobUpdateTime ;
bool objectProfileEnabled, cursorProfileEnabled, blobProfileEnabled;
char *source_name;
};
}
#endif /* INCLUDED_TuioServer_H */

View File

@@ -0,0 +1,129 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "TuioTime.h"
using namespace TUIO;
long TuioTime::start_seconds = 0;
long TuioTime::start_micro_seconds = 0;
TuioTime::TuioTime (long msec) {
seconds = msec/MSEC_SECOND;
micro_seconds = USEC_MILLISECOND*(msec%MSEC_SECOND);
}
TuioTime::TuioTime (long sec, long usec) {
seconds = sec;
micro_seconds = usec;
}
TuioTime TuioTime::operator+(long us) {
long sec = seconds + us/USEC_SECOND;
long usec = micro_seconds + us%USEC_SECOND;
return TuioTime(sec,usec);
}
TuioTime TuioTime::operator+(TuioTime ttime) {
long sec = seconds + ttime.getSeconds();
long usec = micro_seconds + ttime.getMicroseconds();
sec += usec/USEC_SECOND;
usec = usec%USEC_SECOND;
return TuioTime(sec,usec);
}
TuioTime TuioTime::operator-(long us) {
long sec = seconds - us/USEC_SECOND;
long usec = micro_seconds - us%USEC_SECOND;
if (usec<0) {
usec += USEC_SECOND;
sec--;
}
return TuioTime(sec,usec);
}
TuioTime TuioTime::operator-(TuioTime ttime) {
long sec = seconds - ttime.getSeconds();
long usec = micro_seconds - ttime.getMicroseconds();
if (usec<0) {
usec += USEC_SECOND;
sec--;
}
return TuioTime(sec,usec);
}
void TuioTime::operator=(TuioTime ttime) {
seconds = ttime.getSeconds();
micro_seconds = ttime.getMicroseconds();
}
bool TuioTime::operator==(TuioTime ttime) {
if ((seconds==(long)ttime.getSeconds()) && (micro_seconds==(long)ttime.getMicroseconds())) return true;
else return false;
}
bool TuioTime::operator!=(TuioTime ttime) {
if ((seconds!=(long)ttime.getSeconds()) || (micro_seconds!=(long)ttime.getMicroseconds())) return true;
else return false;
}
void TuioTime::reset() {
seconds = 0;
micro_seconds = 0;
}
long TuioTime::getSeconds() const{
return seconds;
}
long TuioTime::getMicroseconds() const{
return micro_seconds;
}
long TuioTime::getTotalMilliseconds() const{
return seconds*MSEC_SECOND+micro_seconds/MSEC_SECOND;
}
void TuioTime::initSession() {
TuioTime startTime = TuioTime::getSystemTime();
start_seconds = startTime.getSeconds();
start_micro_seconds = startTime.getMicroseconds();
}
TuioTime TuioTime::getSessionTime() {
return (getSystemTime() - getStartTime());
}
TuioTime TuioTime::getStartTime() {
return TuioTime(start_seconds,start_micro_seconds);
}
TuioTime TuioTime::getSystemTime() {
#ifdef WIN32
TuioTime systemTime(GetTickCount());
#else
struct timeval tv;
struct timezone tz;
gettimeofday(&tv,&tz);
TuioTime systemTime(tv.tv_sec,tv.tv_usec);
#endif
return systemTime;
}

View File

@@ -0,0 +1,189 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_TUIOTIME_H
#define INCLUDED_TUIOTIME_H
#include "LibExport.h"
#ifndef WIN32
#include <pthread.h>
#include <sys/time.h>
#else
#include <windows.h>
#include <ctime>
#endif
#define MSEC_SECOND 1000
#define USEC_SECOND 1000000
#define USEC_MILLISECOND 1000
namespace TUIO {
/**
* The TuioTime class is a simple structure that is used to reprent the time that has elapsed since the session start.
* The time is internally represented as seconds and fractions of microseconds which should be more than sufficient for gesture related timing requirements.
* Therefore at the beginning of a typical TUIO session the static method initSession() will set the reference time for the session.
* Another important static method getSessionTime will return a TuioTime object representing the time elapsed since the session start.
* The class also provides various addtional convience method, which allow some simple time arithmetics.
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL TuioTime {
private:
long seconds;
long micro_seconds;
static long start_seconds;
static long start_micro_seconds;
public:
/**
* The default constructor takes no arguments and sets
* the Seconds and Microseconds attributes of the newly created TuioTime both to zero.
*/
TuioTime ():seconds(0),micro_seconds(0) {};
/**
* The destructor is doing nothing in particular.
*/
~TuioTime() {}
/**
* This constructor takes the provided time represented in total Milliseconds
* and assigs this value to the newly created TuioTime.
*
* @param msec the total time in Millseconds
*/
TuioTime (long msec);
/**
* This constructor takes the provided time represented in Seconds and Microseconds
* and assigs these value to the newly created TuioTime.
*
* @param sec the total time in seconds
* @param usec the microseconds time component
*/
TuioTime (long sec, long usec);
/**
* Sums the provided time value represented in total Microseconds to this TuioTime.
*
* @param us the total time to add in Microseconds
* @return the sum of this TuioTime with the provided argument in microseconds
*/
TuioTime operator+(long us);
/**
* Sums the provided TuioTime to the private Seconds and Microseconds attributes.
*
* @param ttime the TuioTime to add
* @return the sum of this TuioTime with the provided TuioTime argument
*/
TuioTime operator+(TuioTime ttime);
/**
* Subtracts the provided time represented in Microseconds from the private Seconds and Microseconds attributes.
*
* @param us the total time to subtract in Microseconds
* @return the subtraction result of this TuioTime minus the provided time in Microseconds
*/
TuioTime operator-(long us);
/**
* Subtracts the provided TuioTime from the private Seconds and Microseconds attributes.
*
* @param ttime the TuioTime to subtract
* @return the subtraction result of this TuioTime minus the provided TuioTime
*/
TuioTime operator-(TuioTime ttime);
/**
* Assigns the provided TuioTime to the private Seconds and Microseconds attributes.
*
* @param ttime the TuioTime to assign
*/
void operator=(TuioTime ttime);
/**
* Takes a TuioTime argument and compares the provided TuioTime to the private Seconds and Microseconds attributes.
*
* @param ttime the TuioTime to compare
* @return true if the two TuioTime have equal Seconds and Microseconds attributes
*/
bool operator==(TuioTime ttime);
/**
* Takes a TuioTime argument and compares the provided TuioTime to the private Seconds and Microseconds attributes.
*
* @param ttime the TuioTime to compare
* @return true if the two TuioTime have differnt Seconds or Microseconds attributes
*/
bool operator!=(TuioTime ttime);
/**
* Resets the seconds and micro_seconds attributes to zero.
*/
void reset();
/**
* Returns the TuioTime Seconds component.
* @return the TuioTime Seconds component
*/
long getSeconds() const;
/**
* Returns the TuioTime Microseconds component.
* @return the TuioTime Microseconds component
*/
long getMicroseconds() const;
/**
* Returns the total TuioTime in Milliseconds.
* @return the total TuioTime in Milliseconds
*/
long getTotalMilliseconds() const;
/**
* This static method globally resets the TUIO session time.
*/
static void initSession();
/**
* Returns the present TuioTime representing the time since session start.
* @return the present TuioTime representing the time since session start
*/
static TuioTime getSessionTime();
/**
* Returns the absolut TuioTime representing the session start.
* @return the absolut TuioTime representing the session start
*/
static TuioTime getStartTime();
/**
* Returns the absolut TuioTime representing the current system time.
* @return the absolut TuioTime representing the current system time
*/
static TuioTime getSystemTime();
};
}
#endif /* INCLUDED_TUIOTIME_H */

View File

@@ -0,0 +1,92 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "UdpReceiver.h"
using namespace TUIO;
using namespace osc;
#ifndef WIN32
static void* ClientThreadFunc( void* obj )
#else
static DWORD WINAPI ClientThreadFunc( LPVOID obj )
#endif
{
static_cast<UdpReceiver*>(obj)->socket->Run();
return 0;
};
UdpReceiver::UdpReceiver(int port):locked (false) {
try {
socket = new UdpListeningReceiveSocket(IpEndpointName( IpEndpointName::ANY_ADDRESS, port ), this );
} catch (std::exception &e) {
std::cerr << "could not bind to UDP port " << port << std::endl;
socket = NULL;
}
if (socket!=NULL) {
if (!socket->IsBound()) {
delete socket;
socket = NULL;
} else std::cout << "listening to TUIO/UDP messages on port " << port << std::endl;
}
}
UdpReceiver::~UdpReceiver() {
delete socket;
}
void UdpReceiver::connect(bool lk) {
if (connected) return;
if (socket==NULL) return;
locked = lk;
if (!locked) {
#ifndef WIN32
pthread_create(&thread , NULL, ClientThreadFunc, this);
#else
DWORD threadId;
thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &threadId );
#endif
} else socket->Run();
connected = true;
}
void UdpReceiver::disconnect() {
if (!connected) return;
if (socket==NULL) {
connected = false;
locked = false;
return;
}
socket->Break();
if (!locked) {
#ifdef WIN32
if( thread ) CloseHandle( thread );
#endif
thread = 0;
} else locked = false;
connected = false;
}

View File

@@ -0,0 +1,77 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_UDPRECEIVER_H
#define INCLUDED_UDPRECEIVER_H
#include "OscReceiver.h"
#include "oscpack/ip/UdpSocket.h"
namespace TUIO {
/**
* The UdpReceiver provides the OscReceiver functionality for the UDP transport method
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL UdpReceiver: public OscReceiver {
public:
/**
* The UDP socket is only public to be accessible from the thread function
*/
UdpListeningReceiveSocket *socket;
/**
* This constructor creates a UdpReceiver instance listening to the provided UDP port
*
* @param port the number of the UDP port to listen to, defaults to 3333
*/
UdpReceiver (int port=3333);
/**
* The destructor is doing nothing in particular.
*/
virtual ~UdpReceiver();
/**
* The UdpReceiver connects and starts receiving TUIO messages via UDP
*
* @param lock running in the background if set to false (default)
*/
void connect(bool lock=false);
/**
* The UdpReceiver disconnects and stops receiving TUIO messages via UDP
*/
void disconnect();
private:
#ifndef WIN32
pthread_t thread;
#else
HANDLE thread;
#endif
bool locked;
};
};
#endif /* INCLUDED_UDPRECEIVER_H */

View File

@@ -0,0 +1,89 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "UdpSender.h"
using namespace TUIO;
UdpSender::UdpSender() {
try {
local = true;
long unsigned int ip = GetHostByName("localhost");
socket = new UdpTransmitSocket(IpEndpointName(ip, 3333));
buffer_size = MAX_UDP_SIZE;
std::cout << "TUIO/UDP messages to " << "127.0.0.1@3333" << std::endl;
} catch (std::exception &e) {
std::cout << "could not create UDP socket" << std::endl;
socket = NULL;
throw std::exception();
}
}
UdpSender::UdpSender(const char *host, int port) {
try {
if ((strcmp(host,"127.0.0.1")==0) || (strcmp(host,"localhost")==0)) {
local = true;
buffer_size = MAX_UDP_SIZE;
} else {
local = false;
buffer_size = IP_MTU_SIZE;
}
long unsigned int ip = GetHostByName(host);
socket = new UdpTransmitSocket(IpEndpointName(ip, port));
std::cout << "TUIO/UDP messages to " << host << "@" << port << std::endl;
} catch (std::exception &e) {
std::cout << "could not create UDP socket" << std::endl;
socket = NULL;
throw std::exception();
}
}
UdpSender::UdpSender(const char *host, int port, int size) {
try {
if ((strcmp(host,"127.0.0.1")==0) || (strcmp(host,"localhost")==0)) {
local = true;
} else local = false;
long unsigned int ip = GetHostByName(host);
socket = new UdpTransmitSocket(IpEndpointName(ip, port));
if (buffer_size>MAX_UDP_SIZE) buffer_size = MAX_UDP_SIZE;
else if (buffer_size<MIN_UDP_SIZE) buffer_size = MIN_UDP_SIZE;
std::cout << "TUIO/UDP messages to " << host << "@" << port << std::endl;
} catch (std::exception &e) {
std::cout << "could not create UDP socket" << std::endl;
socket = NULL;
throw std::exception();
}
}
UdpSender::~UdpSender() {
delete socket;
}
bool UdpSender::isConnected() {
if (socket==NULL) return false;
return true;
}
bool UdpSender::sendOscPacket (osc::OutboundPacketStream *bundle) {
if (socket==NULL) return false;
if ( bundle->Size() > buffer_size ) return false;
if ( bundle->Size() == 0 ) return false;
socket->Send( bundle->Data(), bundle->Size() );
return true;
}

View File

@@ -0,0 +1,93 @@
/*
TUIO C++ Library
Copyright (c) 2005-2016 Martin Kaltenbrunner <martin@tuio.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_UDPSENDER_H
#define INCLUDED_UDPSENDER_H
#include "OscSender.h"
#include "oscpack/ip/UdpSocket.h"
#define IP_MTU_SIZE 1500
#define MAX_UDP_SIZE 4096
#define MIN_UDP_SIZE 576
namespace TUIO {
/**
* The UdpSender implements the UDP transport method for OSC
*
* @author Martin Kaltenbrunner
* @version 1.1.6
*/
class LIBDECL UdpSender : public OscSender {
public:
/**
* The default constructor creates a UdpSender that sends to the default UDP port 3333 on localhost
* using the maximum packet size of 65536 bytes for single packets on the loopback device
*/
UdpSender();
/**
* This constructor creates a UdpSender that sends to the provided port on the the given host
* using the default MTU size of 1500 bytes to deliver unfragmented UDP packets on a LAN
*
* @param host the receiving host name
* @param port the outgoing UDP port number
*/
UdpSender(const char *host, int port);
/**
* This constructor creates a UdpSender that sends to the provided port on the the given host
* the UDP packet size can be set to a value between 576 and 65536 bytes
*
* @param host the receiving host name
* @param port the outgoing UDP port number
* @param size the maximum UDP packet size
*/
UdpSender(const char *host, int port, int size);
/**
* The destructor closes the socket.
*/
virtual ~UdpSender();
/**
* This method delivers the provided OSC data
*
* @param *bundle the OSC stream to deliver
* @return true if the data was delivered successfully
*/
bool sendOscPacket (osc::OutboundPacketStream *bundle);
/**
* This method returns the connection state
*
* @return true if the connection is alive
*/
bool isConnected ();
const char* tuio_type() { return "TUIO/UDP"; }
private:
UdpTransmitSocket *socket;
};
}
#endif /* INCLUDED_UDPSENDER_H */

View File

@@ -0,0 +1,287 @@
/*
TUIO C++ Library
Copyright (c) 2009-2016 Martin Kaltenbrunner <martin@tuio.org>
WebSockSender (c) 2015 Florian Echtler <floe@butterbrot.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#include "WebSockSender.h"
#ifdef WIN32
#if not
defined int32_t
typedef DWORD int32_t;
#endif
#endif
using namespace TUIO;
WebSockSender::WebSockSender()
:TcpSender( 8080 )
{
local = true;
buffer_size = MAX_TCP_SIZE;
port_no = 8080;
}
WebSockSender::WebSockSender(int port)
:TcpSender( port )
{
local = true;
buffer_size = MAX_TCP_SIZE;
port_no = port;
}
bool WebSockSender::sendOscPacket (osc::OutboundPacketStream *bundle) {
if (!connected) return false;
if ( bundle->Size() > buffer_size ) return false;
if ( bundle->Size() == 0 ) return false;
#ifdef OSC_HOST_LITTLE_ENDIAN
data_size[0] = bundle->Size()>>24;
data_size[1] = (bundle->Size()>>16) & 255;
data_size[2] = (bundle->Size()>>8) & 255;
data_size[3] = (bundle->Size()) & 255;
#else
*((int32_t*)data_size) = bundle->Size();
#endif
#ifdef WIN32
std::list<SOCKET>::iterator client;
#else
std::list<int>::iterator client;
#endif
for (client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++) {
int len = bundle->Size();
// add WebSocket header on top
uint8_t header[4] = {
0x82,
(uint8_t)( len & 0xFF),
(uint8_t)((len >>8) & 0xFF),
(uint8_t)( len & 0xFF)
};
int hs = 2;
if (len > 125) { hs = 4; header[1] = 126; }
memcpy(&data_buffer[0], &header, hs);
memcpy(&data_buffer[hs], bundle->Data(), bundle->Size());
send((*client),data_buffer, hs+bundle->Size(),0);
}
return true;
}
void WebSockSender::newClient( int tcp_client ) {
// socket -> file descriptor
#ifdef WIN32
FILE* conn = _fdopen( tcp_client, "r+" );
#else
FILE* conn = fdopen( tcp_client, "r+" );
#endif
// websocket challenge-response
uint8_t digest[SHA1_HASH_SIZE];
char buf[1024] = "...";
char key[1024];
// read client handshake challenge
while ((buf[0] != 0) && (buf[0] != '\r')) {
fgets( buf, sizeof(buf), conn );
if (strncmp(buf,"Sec-WebSocket-Key: ",19) == 0) {
strncpy(key,buf+19,sizeof(key));
key[strlen(buf)-21] = 0;
break;
}
}
strncat(key,"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",sizeof(key)-strlen(key)-1);
sha1(digest,(uint8_t*)key,strlen(key));
snprintf(buf, sizeof(buf),
"HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Sec-WebSocket-Accept: %s\r\n\r\n",
base64( digest, SHA1_HASH_SIZE ).c_str() );
send(tcp_client,buf, strlen(buf),0);
}
/*
* Incredibly minimal implementation of SHA1.
* Totally independent of any other code (even libc) so it can be
* run on bare hardware.
*
* Copyright (C) 2009 John Stumpo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JOHN STUMPO ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL JOHN STUMPO BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
void WebSockSender::sha1( uint8_t digest[SHA1_HASH_SIZE], const uint8_t* inbuf, size_t length) {
size_t i, j;
int remaining_bytes;
uint32_t h0, h1, h2, h3, h4, a, b, c, d, e, temp;
uint32_t w[80];
unsigned char buf[64];
/* Initialize SHA1 hash state. */
h0 = 0x67452301;
h1 = 0xefcdab89;
h2 = 0x98badcfe;
h3 = 0x10325476;
h4 = 0xc3d2e1f0;
/* The extra 9 bytes are the pad byte (0x80) and 64-bit bit count that
are appended to the data being hashed. (There will more than likely
also be some zeroes in between the 0x80 and the bit count so that we
operate on a multiple of 64 bytes; 9 bytes, though, is the minimal
amount of extra data.) */
for (i = 0; i < length + 9; i += 64) {
/* Perform any padding necessary. */
remaining_bytes = length - i;
if (remaining_bytes >= 64) {
memcpy(buf, inbuf + i, 64);
} else if (remaining_bytes >= 0) {
memcpy(buf, inbuf + i, remaining_bytes);
memset(buf + remaining_bytes, 0, 64 - remaining_bytes);
buf[remaining_bytes] = 0x80;
} else {
memset(buf, 0, 64);
}
if (remaining_bytes < 56)
*(uint32_t*)(buf + 60) = SWAP(length * 8);
/* Build the input array. */
for (j = 0; j < 16; j++)
w[j] = SWAP(*(uint32_t*)(buf + j * 4));
for (j = 16; j < 80; j++)
w[j] = ROL(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
/* Load hash state. */
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
for (j = 0; j < 80; j++) {
if (j < 20)
temp = ((b & c) | ((~b) & d)) + 0x5a827999;
else if (j < 40)
temp = (b ^ c ^ d) + 0x6ed9eba1;
else if (j < 60)
temp = ((b & c) | (b & d) | (c & d)) + 0x8f1bbcdc;
else
temp = (b ^ c ^ d) + 0xca62c1d6;
temp += ROL(a, 5) + e + w[j];
e = d;
d = c;
c = ROR(b, 2);
b = a;
a = temp;
}
/* Incorporate the results of the hash operation. */
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
}
/* Write the hash into the output buffer. */
*(uint32_t*)(digest) = SWAP(h0);
*(uint32_t*)(digest + 4) = SWAP(h1);
*(uint32_t*)(digest + 8) = SWAP(h2);
*(uint32_t*)(digest + 12) = SWAP(h3);
*(uint32_t*)(digest + 16) = SWAP(h4);
}
/*
* a very simple base64 encoder, licensed as public domain. original source:
* https://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64
*/
const static unsigned char encodeLookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const static unsigned char padCharacter = '=';
std::string WebSockSender::base64( uint8_t* cursor, size_t size ) {
std::string encodedString;
uint32_t temp;
encodedString.reserve(((size/3) + (size % 3 > 0)) * 4);
for (size_t idx = 0; idx < size/3; idx++) {
temp = (*cursor++) << 16;
temp += (*cursor++) << 8;
temp += (*cursor++);
encodedString.append( 1, encodeLookup[(temp & 0x00FC0000) >> 18] );
encodedString.append( 1, encodeLookup[(temp & 0x0003F000) >> 12] );
encodedString.append( 1, encodeLookup[(temp & 0x00000FC0) >> 6 ] );
encodedString.append( 1, encodeLookup[(temp & 0x0000003F) ] );
}
switch (size % 3) {
case 1:
temp = (*cursor++) << 16;
encodedString.append( 1, encodeLookup[(temp & 0x00FC0000) >> 18] );
encodedString.append( 1, encodeLookup[(temp & 0x0003F000) >> 12] );
encodedString.append( 2, padCharacter );
break;
case 2:
temp = (*cursor++) << 16;
temp += (*cursor++) << 8;
encodedString.append( 1, encodeLookup[(temp & 0x00FC0000) >> 18] );
encodedString.append( 1, encodeLookup[(temp & 0x0003F000) >> 12] );
encodedString.append( 1, encodeLookup[(temp & 0x00000FC0) >> 6 ] );
encodedString.append( 1, padCharacter);
break;
}
return encodedString;
}

View File

@@ -0,0 +1,121 @@
/*
TUIO C++ Library
Copyright (c) 2009-2016 Martin Kaltenbrunner <martin@tuio.org>
WebSockSender (c) 2015 Florian Echtler <floe@butterbrot.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
#ifndef INCLUDED_WEBSOCKSENDER_H
#define INCLUDED_WEBSOCKSENDER_H
#if defined(_MSC_VER) && _MSC_VER < 1900
#include <Windows.h>
#include <stdio.h>
#define snprintf c99_snprintf
#define vsnprintf c99_vsnprintf
__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
{
int count = -1;
if (size != 0)
count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
if (count == -1)
count = _vscprintf(format, ap);
return count;
}
__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...)
{
int count;
va_list ap;
va_start(ap, format);
count = c99_vsnprintf(outBuf, size, format, ap);
va_end(ap);
return count;
}
#endif
/* All of these macros assume use on a 32-bit variable.
Additionally, SWAP assumes we're little-endian. */
#define SWAP(a) ((((a) >> 24) & 0x000000ff) | (((a) >> 8) & 0x0000ff00) | \
(((a) << 8) & 0x00ff0000) | (((a) << 24) & 0xff000000))
#define ROL(a, b) (((a) << (b)) | ((a) >> (32 - (b))))
#define ROR(a, b) ROL((a), (32 - (b)))
#define SHA1_HASH_SIZE (160/8)
#include "TcpSender.h"
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <vector>
namespace TUIO {
/**
* The WebSockSender implements the WebSocket transport method for OSC
*
* @author Florian Echtler
* @version 2.0.a0
*/
class LIBDECL WebSockSender : public TcpSender {
public:
/**
* The default constructor creates a WebSockSender that listens to the default HTTP-alt port 8080 on localhost
*/
WebSockSender();
/**
* This constructor creates a WebSockSender that listens to the provided port
*
* @param port the listening WebSocket port number
*/
WebSockSender(int port);
/**
* The destructor closes the socket.
*/
virtual ~WebSockSender() {}
/**
* This method delivers the provided OSC data
*
* @param *bundle the OSC stream to deliver
* @return true if the data was delivered successfully
*/
bool sendOscPacket (osc::OutboundPacketStream *bundle);
/**
* This method is called whenever a new client connects
*
* @param tcp_client the socket handle of the new client
*/
void newClient( int tcp_client );
const char* tuio_type() { return "TUIO/WEB"; }
private:
void sha1( uint8_t digest[SHA1_HASH_SIZE], const uint8_t* inbuf, size_t length );
std::string base64( uint8_t* buffer, size_t size );
};
}
#endif /* INCLUDED_WEBSOCKSENDER_H */

View File

@@ -0,0 +1,159 @@
April 9, 2013
-------------
Changes for the 1.1.0 release (vs 1.0.2) are listed below. Unless
otherwise indicated these changes have been made since
January 2013. The focus has been on general clean-up, fixing bugs,
compiler errors and warnings, and fixing issues on 64 bit platforms.
A few improvements such as support for OSC arrays, functions
for setting broadcast and reuse socket options have been added.
This update merges changes from the openFrameworks version
of oscpack.
- Added support for arrays in messages (see OscUnitTests.cpp
for example usage). (patch thanks to Tim Blechmann)
- Fixed bugs relating to 64 bit usage (e.g. crashes in 64 bit
builds on OS X).
- Some member functions that previously used the "int" or
"unsigned long" type for parameters or return values now use
std::size_t (platform-defined) or
osc_bundle_element_size_t (a.k.a. int32).
This change was made to better support 64 bit platforms.
See SVN revision 70 for details.
- The previous point introduces a breaking change on Linux/x86_64
for callers of AsBlob() and AsBlobUnchecked():
The type of the second argument (the "size" argument) to
ReceivedMessageArgument::AsBlob() and
ReceivedMessageArgument::AsBlobUnchecked() has changed
from unsigned long & to osc_bundle_element_size_t (an int32).
You should declare your size argument variables as
osc_bundle_element_size_t to avoid incompatibilities between
32 and 64 bit builds.
- Note that oscpack does not support packets larger than
0x7FFFFFFC (see comments in class ReceivedPacket for
details).
- Oscpack defines an osc::Nil value used for sending the nil
message argument value. This conflicts with Objective-C.
Therefore osc::Nil is no longer defined in Obj-C++ code.
There is now an osc::OscNil value, which should be preferred.
osc::Nil is still available when writing C++.
(fix thanks to openFrameworks)
- Added UdpSocket::SetEnableBroadcast(). This needs to
be called to enable sending to the broadcast address on some
platforms (e.g. Mac OS X). (thanks to openFrameworks)
- Added UdpSocket::SetAllowReuse(). This is useful for
sharing sockets on some platforms (Mac?), and not so useful
on other platforms. (thanks to openFrameworks)
- Added IpEndpointName::IsMulticastAddress() (2010)
- Cleaned up C++ header usage and std:: namespace usage
to be more standards compliant (fixes issues on recent compilers
such as clang and gcc4.6).
- Improved host endianness detection. Should auto-detect
endianness on most platforms now.
(thanks to Tim Blechmann for help with this)
- Fixed two memory leaks: (1) in OscPrintReceivedElements.cpp
when printing time tag message arguments (thanks to Gwydion ap Dafydd).
(2) in the posix SocketReceiveMultiplexer::Run() method if an exception
was thrown while listening.
- Fixed bug in posix SocketReceiveMultiplexer::Run() that would cause
packets to stop being received if select() returned EINTR.
(thanks to Björn Wöldecke)
- Updated and improved Makefile to avoid redundant re-linking
(thanks to Douglas Mandell)
- Added CMakeLists.txt CMake build file (2010, thanks to David Doria)
- Switched license to plain MIT license with non binding request
for contribution of improvements (same as current PortAudio
boilerplate). See LICENSE file.
Thanks to Tim Blechmann, Rob Canning, Gwydion ap Dafydd, David Doria,
Christopher Delaney, Jon McCormack, Douglas Mandell, Björn Wöldecke,
all the guys at openFrameworks, and everyone who reported bugs,
submitted patches and helped out with testing this release.
Thanks to Syneme at the University of Calgary for providing financial
support for the 1.1.0 update.
September 28, 2005
------------------
Compared to the previous official snapshot (November 2004) the
current version of oscpack includes a re-written set of network
classes and some changes to the syntax of the networking code. It no
longer uses threads, which means that you don't need to use sleep()
if you are writing a simple single-threaded server, or you need to
spawn your own threads in a more complex application.
The list below summarises the changes if you are porting code from
the previous release.
- There are no longer any threads in oscpack. if you need to
set up an asynchronous listener you can create your own thread
and call Run on an instance of SocketReceiveMultiplexer or
UdpListeningReceiveSocket (see ip/UdpSocket.h) yourself.
- Host byte order is now used for network (IP) addresses
- Functions which used to take two parameters <address, port>
now take an instance of IpEndpointName (see
ip/IpEndpointName.h) this class has a number of convenient
constructors for converting numbers and strings to internet
addresses. For example there is one which takes a string and
another that take the dotted address components as separate
parameters.
- The UdpTransmitPort class, formerly in UdpTransmitPort.h, is
now called UdpTransmitSocket, which is simply a convenience
class derived from UdpSocket (see ip/UdpSocket.h). Where you
used to use the constructor UdpTransmitPort( address, port) now
you can use UdpTransmitSocket( IpEndpointName( address, port )
) or you can any of the other possible ctors to IpEndpointName
() (see above). The Send() method is unchanged.
- The packet listener base class is now located in
ip/PacketListener.h instead of PacketListenerPort.h. The
ProcessPacket method now has an additional parameter indicating
the remote endpoint
- The preferred way to set up listeners is with
SocketReceiveMultiplexer (in ip/UdpSocket.h), this also allows
attaching periodic timers. For simple applications which only
listen to a single socket with no timers you can use
UdpListeningReceiveSocket (also in UdpSocket.h) See
osc/OscReceiveTest.cpp or osc/OscDump.cpp for examples of this.
This is more or less equivalent to the UdpPacketListenerPort
object in the old oscpack versions except that you need to
explicitly call Run() before it will start receiving packets
and it runs in the same thread, not a separate thread so Run()
won't usually return.
- Explicit calls to InitializeNetworking() and
TerminateNetworking() are no longer required for simple
applications (more complex windows applications should
instantiate NetworkInitializer in main() or WinMain (see
ip/NetworkingUtils.h/.cpp)
- The OscPacketListener base class (OscPacketListener.h) was
added to make traversing OSC packets easier, it handles bundle
traversal automatically so you only need to process messages in
your derived classes.
- On Windows be sure to link with ws2_32.lib or you will see
a linker error about WSAEventSelect not being found. Also you
will need to link with winmm.lib for timeGetTime()

View File

@@ -0,0 +1,34 @@
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
###
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.

View File

@@ -0,0 +1,150 @@
oscpack -- Open Sound Control packet manipulation library
A simple C++ library for packing and unpacking OSC packets.
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Oscpack is simply a set of C++ classes for packing and unpacking OSC packets.
Oscpack includes a minimal set of UDP networking classes for Windows and POSIX.
The networking classes are sufficient for writing many OSC applications and servers,
but you are encouraged to use another networking framework if it better suits your needs.
Oscpack is not an OSC application framework. It doesn't include infrastructure for
constructing or routing OSC namespaces, just classes for easily constructing,
sending, receiving and parsing OSC packets. The library should also be easy to use
for other transport methods (e.g. serial).
The key goals of the oscpack library are:
- Be a simple and complete implementation of OSC
- Be portable to a wide variety of platforms
- Allow easy development of robust OSC applications
(for example it should be impossible to crash a server
by sending it malformed packets, and difficult to create
malformed packets.)
Here's a quick run down of the key files:
osc/OscReceivedElements -- classes for parsing a packet
osc/OscPrintRecievedElements -- iostream << operators for printing packet elements
osc/OscOutboundPacketStream -- a class for packing messages into a packet
osc/OscPacketListener -- base class for listening to OSC packets on a UdpSocket
ip/IpEndpointName -- class that represents an IP address and port number
ip/UdpSocket -- classes for UDP transmission and listening sockets
tests/OscUnitTests -- unit test program for the OSC modules
tests/OscSendTests -- examples of how to send messages
tests/OscReceiveTest -- example of how to receive the messages sent by OSCSendTests
examples/OscDump -- a program that prints received OSC packets
examples/SimpleSend -- a minimal program to send an OSC message
examples/SimpleReceive -- a minimal program to receive an OSC message
osc/ contains all of the OSC related classes
ip/ contains the networking classes
ip/windows contains the Windows implementation of the networking classes
ip/posix contains the POSIX implementation of the networking classes
Building
--------
The idea is that you will embed this source code in your projects as you
see fit. The Makefile has an install rule for building a shared library and
installing headers in usr/local. It can also build a static library.
There is a CMakeLists.txt for building with cmake.
Makefile builds
...............
The Makefile works for Linux and Max OS X. It should also work on other platforms
that have make. Just run:
$ make
You can run "make install" if you like.
Cmake builds
............
There is a CMakeLists.txt file which has been tested with cmake on
Windows and Linux. It should work on other platforms too.
For example, to generate a Visual Studio 10 project, run cmake
like this:
> cmake -G "Visual Studio 10"
Run cmake without any parameters to get a list of available generators.
Mingw build batch file
......................
For Windows there is a batch file for doing a simple test build with
MinGW gcc called make.MinGW32.bat. This will build the test executables
and oscdump in ./bin and run the unit tests.
Note:
In some rare instances you may need to edit the Makefile or
osc/OscHostEndianness.h to configure oscpack for the endianness of your
processor (see the comments at the top of the Makefile for details).
Verification test
-----------------
To run the unit tests:
$ ./bin/OscUnitTests
To run the send and receive tests. Open two terminals. In one run:
$ ./bin/OscReceiveTest
Then in the other terminal run:
$./bin/OscSendTests
You should see an indication that the messages were received
in the first terminal.
Note that OscSendTests intentionally sends some unexpected
message parameters to test exception handling in the receiver.
You will see some "error while parsing message" messages printed.
You can use ./bin/OscDump to print out OSC messages received
from any program, including the test programs.
--
If you fix anything or write a set of TCP send/receive classes
please consider sending me a patch. My email address is
rossb@audiomulch.com. Thanks :)
For more information about Open Sound Control, see:
http://opensoundcontrol.org/
Thanks to Till Bovermann for helping with POSIX networking code and
Mac compatibility, and to Martin Kaltenbrunner and the rest of the
reacTable team for giving me a reason to finish this library. Thanks
to Merlijn Blaauw for reviewing the interfaces. Thanks to Xavier Oliver
for additional help with Linux builds and POSIX implementation details.
Portions developed at the Music Technology Group, Audiovisual Institute,
University Pompeu Fabra, Barcelona, during my stay as a visiting
researcher, November 2004 - September 2005.
Thanks to Syneme at the University of Calgary for providing financial
support for the 1.1.0 update, December 2012 - March 2013.
See the file CHANGES for information about recent updates.
See the file LICENSE for information about distributing and using this code.
###

View File

@@ -0,0 +1,52 @@
TODO:
- consider adding the local endpoint name to PacketListener::PacketReceived() params
- consider adding ListenerThread class to support old seperate thread listener functionality, something like:
class UdpSocketListenerThread{
public:
UdpSocketListenerThread( UdpSocket& socket, Listener *listener );
UdpSocketListenerThread( UdpSocketReceiveMultiplexer *mux );
~UdpSocketListenerThread();
void Run();
void Stop();
};
- work out a way to make the parsing classes totally safe. at a minimum this
means adding functions to test for invalid float/doublevalues,
making sure the iterators never pass the end of the message, ...
(passing end of message can happen if:
- too many args in type tags
a. typetags overflow message size
b. args fulfilling typetags overflow message size
- strings too long or not terminated correctly
- blobs too long or not terminated correctly
if the message was fully checked during construction, the end() iterator
could be moved back until only arguments which fit withing size() may
be interated (this could be none). A flag could be set to indicate that
something was wrong.
- other packet badness could include:
- time tags too far into the future (the scheduler should deal with
that i guess).
- message address patterns which aren't correctly terminated
- improve the ability to parse messages without tags (SC uses methods which
get the data and advance the iterator in one step.)
- Check* could be modified to do this - ie if typetags are not present
it could check that reading the field won't escape the message size
and return the data, or return false if some consistency
constraint is violated.
(or alternately drop support for messages without type tags)
- add a method to discard an inprogress message if it gets half
constructed and the buffer is full in OutboundPacket
- write a stress testing app which can send garbage packets to try to flush out other bugs in the parsing code.

View File

@@ -0,0 +1,88 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#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 ){
std::sprintf( s, "<any>" );
}else{
std::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 ){
std::sprintf( s, "<any>:<any>" );
}else{
std::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 ){
std::sprintf( s, "<any>:%d", port );
}else{
std::sprintf( s, "%d.%d.%d.%d:%d",
(int)((address >> 24) & 0xFF),
(int)((address >> 16) & 0xFF),
(int)((address >> 8) & 0xFF),
(int)(address & 0xFF),
(int)port );
}
}
}

View File

@@ -0,0 +1,83 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_IPENDPOINTNAME_H
#define INCLUDED_OSCPACK_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_OSCPACK_IPENDPOINTNAME_H */

View File

@@ -0,0 +1,56 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_NETWORKINGUTILS_H
#define INCLUDED_OSCPACK_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_OSCPACK_NETWORKINGUTILS_H */

View File

@@ -0,0 +1,50 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_PACKETLISTENER_H
#define INCLUDED_OSCPACK_PACKETLISTENER_H
class IpEndpointName;
class PacketListener{
public:
virtual ~PacketListener() {}
virtual void ProcessPacket( const char *data, int size,
const IpEndpointName& remoteEndpoint ) = 0;
};
#endif /* INCLUDED_OSCPACK_PACKETLISTENER_H */

View File

@@ -0,0 +1,47 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_TIMERLISTENER_H
#define INCLUDED_OSCPACK_TIMERLISTENER_H
class TimerListener{
public:
virtual ~TimerListener() {}
virtual void TimerExpired() = 0;
};
#endif /* INCLUDED_OSCPACK_TIMERLISTENER_H */

View File

@@ -0,0 +1,176 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_UDPSOCKET_H
#define INCLUDED_OSCPACK_UDPSOCKET_H
#include <cstring> // size_t
#include "NetworkingUtils.h"
#include "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();
// Enable broadcast addresses (e.g. x.x.x.255)
// Sets SO_BROADCAST socket option.
void SetEnableBroadcast( bool enableBroadcast );
// Enable multiple listeners for a single port on same
// network interface*
// Sets SO_REUSEADDR (also SO_REUSEPORT on OS X).
// [*] The exact behavior of SO_REUSEADDR and
// SO_REUSEPORT is undefined for some common cases
// and may have drastically different behavior on different
// operating systems.
void SetAllowReuse( bool allowReuse );
// 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, std::size_t size );
void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t 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;
std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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_OSCPACK_UDPSOCKET_H */

View File

@@ -0,0 +1,64 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "ip/NetworkingUtils.h"
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <cstring>
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;
std::memcpy( &a, h->h_addr_list[0], h->h_length );
result = ntohl(a.s_addr);
}
return result;
}

View File

@@ -0,0 +1,602 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "ip/UdpSocket.h"
#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 <signal.h>
#include <math.h>
#include <errno.h>
#include <string.h>
#include <algorithm>
#include <cassert>
#include <cstring> // for memset
#include <stdexcept>
#include <vector>
#include "ip/PacketListener.h"
#include "ip/TimerListener.h"
#if defined(__APPLE__) && !defined(_SOCKLEN_T)
// pre system 10.3 didn't have socklen_t
typedef ssize_t socklen_t;
#endif
static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint )
{
std::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");
}
std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) );
sendToAddr_.sin_family = AF_INET;
}
~Implementation()
{
if (socket_ != -1) close(socket_);
}
void SetEnableBroadcast( bool enableBroadcast )
{
int broadcast = (enableBroadcast) ? 1 : 0; // int on posix
setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
}
void SetAllowReuse( bool allowReuse )
{
int reuseAddr = (allowReuse) ? 1 : 0; // int on posix
setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr));
#ifdef __APPLE__
// needed also for OS X - enable multiple listeners for a single port on same network interface
int reusePort = (allowReuse) ? 1 : 0; // int on posix
setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &reusePort, sizeof(reusePort));
#endif
}
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;
std::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;
std::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, std::size_t size )
{
assert( isConnected_ );
send( socket_, data, size, 0 );
}
void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t 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_; }
std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size )
{
assert( isBound_ );
struct sockaddr_in fromAddr;
socklen_t fromAddrLen = sizeof(fromAddr);
ssize_t 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 (std::size_t)result;
}
int Socket() { return socket_; }
};
UdpSocket::UdpSocket()
{
impl_ = new Implementation();
}
UdpSocket::~UdpSocket()
{
delete impl_;
}
void UdpSocket::SetEnableBroadcast( bool enableBroadcast )
{
impl_->SetEnableBroadcast( enableBroadcast );
}
void UdpSocket::SetAllowReuse( bool allowReuse )
{
impl_->SetAllowReuse( allowReuse );
}
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, std::size_t size )
{
impl_->Send( data, size );
}
void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size )
{
impl_->SendTo( remoteEndpoint, data, size );
}
void UdpSocket::Bind( const IpEndpointName& localEndpoint )
{
impl_->Bind( localEndpoint );
}
bool UdpSocket::IsBound() const
{
return impl_->IsBound();
}
std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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;
char *data = 0;
try{
// 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;
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;
long timoutSecondsPart = (long)(timeoutMs * .001);
timeout.tv_sec = (time_t)timoutSecondsPart;
// 1000000 microseconds in a second
timeout.tv_usec = (suseconds_t)((timeoutMs - (timoutSecondsPart * 1000)) * 1000);
timeoutPtr = &timeout;
}
if( select( fdmax + 1, &tempfds, 0, 0, timeoutPtr ) < 0 ){
if( break_ ){
break;
}else if( errno == EINTR ){
// on returning an error, select() doesn't clear tempfds.
// so tempfds would remain all set, which would cause read( breakPipe_[0]...
// below to block indefinitely. therefore if select returns EINTR we restart
// the while() loop instead of continuing on to below.
continue;
}else{
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 ) ){
std::size_t size = i->second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE );
if( size > 0 ){
i->first->ProcessPacket( data, (int)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;
}catch(...){
if( data )
delete [] data;
throw;
}
}
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();
}

View File

@@ -0,0 +1,95 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "oscpack/ip/NetworkingUtils.h"
#include <winsock2.h> // this must come first to prevent errors with MSVC7
#include <windows.h>
#include <cstring>
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;
std::memcpy( &a, h->h_addr_list[0], h->h_length );
result = ntohl(a.s_addr);
}
return result;
}

View File

@@ -0,0 +1,571 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include <winsock2.h> // this must come first to prevent errors with MSVC7
#include <windows.h>
#include <mmsystem.h> // for timeGetTime()
#ifndef WINCE
#include <signal.h>
#endif
#include <algorithm>
#include <cassert>
#include <cstring> // for memset
#include <stdexcept>
#include <vector>
#include "oscpack/ip/UdpSocket.h" // usually I'd include the module header first
// but this is causing conflicts with BCB4 due to
// std::size_t usage.
#include "oscpack/ip/NetworkingUtils.h"
#include "oscpack/ip/PacketListener.h"
#include "oscpack/ip/TimerListener.h"
typedef int socklen_t;
static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint )
{
std::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");
}
std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) );
sendToAddr_.sin_family = AF_INET;
}
~Implementation()
{
if (socket_ != INVALID_SOCKET) closesocket(socket_);
}
void SetEnableBroadcast( bool enableBroadcast )
{
char broadcast = (char)((enableBroadcast) ? 1 : 0); // char on win32
setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
}
void SetAllowReuse( bool allowReuse )
{
// Note: SO_REUSEADDR is non-deterministic for listening sockets on Win32. See MSDN article:
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
// http://msdn.microsoft.com/en-us/library/ms740621%28VS.85%29.aspx
char reuseAddr = (char)((allowReuse) ? 1 : 0); // char on win32
setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr));
}
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;
std::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, std::size_t size )
{
assert( isConnected_ );
send( socket_, data, (int)size, 0 );
}
void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size )
{
sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address );
sendToAddr_.sin_port = htons( (short)remoteEndpoint.port );
sendto( socket_, data, (int)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_; }
std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size )
{
assert( isBound_ );
struct sockaddr_in fromAddr;
socklen_t fromAddrLen = sizeof(fromAddr);
int result = recvfrom(socket_, data, (int)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_;
}
void UdpSocket::SetEnableBroadcast( bool enableBroadcast )
{
impl_->SetEnableBroadcast( enableBroadcast );
}
void UdpSocket::SetAllowReuse( bool allowReuse )
{
impl_->SetAllowReuse( allowReuse );
}
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, std::size_t size )
{
impl_->Send( data, size );
}
void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size )
{
impl_->SendTo( remoteEndpoint, data, size );
}
void UdpSocket::Bind( const IpEndpointName& localEndpoint )
{
impl_->Bind( localEndpoint );
}
bool UdpSocket::IsBound() const
{
return impl_->IsBound();
}
std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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 ){
std::size_t size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE );
if( size > 0 ){
socketListeners_[i].first->ProcessPacket( data, (int)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();
}

View File

@@ -0,0 +1,80 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H
#define INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H
#include <cstring>
#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 std::strcmp( lhs, rhs ) < 0; }
};
typedef std::map<const char*, function_type, cstr_compare> function_map_type;
function_map_type functions_;
};
} // namespace osc
#endif /* INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H */

View File

@@ -0,0 +1,62 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCEXCEPTION_H
#define INCLUDED_OSCPACK_OSCEXCEPTION_H
#include <exception>
namespace osc{
class Exception : public std::exception {
const char *what_;
public:
Exception() throw() {}
Exception( const Exception& src ) throw()
: std::exception( src )
, 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_OSCPACK_OSCEXCEPTION_H */

View File

@@ -0,0 +1,127 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H
#define INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H
/*
Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined
We try to use preprocessor symbols to deduce the host endianness.
Alternatively you can define one of the above symbols from the command line.
Usually you do this with the -D flag to the compiler. e.g.:
$ g++ -DOSC_HOST_LITTLE_ENDIAN ...
*/
#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN)
// endianness defined on the command line. nothing to do here.
#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(__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
#endif
#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)
// should cover gcc and clang
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#else
// gcc defines __LITTLE_ENDIAN__ and __BIG_ENDIAN__
// for others used here see http://sourceforge.net/p/predef/wiki/Endianness/
#if (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) \
|| (defined(__ARMEL__) && !defined(__ARMEB__)) \
|| (defined(__AARCH64EL__) && !defined(__AARCH64EB__)) \
|| (defined(_MIPSEL) && !defined(_MIPSEB)) \
|| (defined(__MIPSEL) && !defined(__MIPSEB)) \
|| (defined(__MIPSEL__) && !defined(__MIPSEB__))
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) \
|| (defined(__ARMEB__) && !defined(__ARMEL__)) \
|| (defined(__AARCH64EB__) && !defined(__AARCH64EL__)) \
|| (defined(_MIPSEB) && !defined(_MIPSEL)) \
|| (defined(__MIPSEB) && !defined(__MIPSEL)) \
|| (defined(__MIPSEB__) && !defined(__MIPSEL__))
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#endif
#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN)
#error please edit OSCHostEndianness.h or define one of {OSC_HOST_LITTLE_ENDIAN, OSC_HOST_BIG_ENDIAN} to configure endianness
#endif
#endif /* INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H */

View File

@@ -0,0 +1,683 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscOutboundPacketStream.h"
#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32)
#include <malloc.h> // for alloca
#else
//#include <alloca.h> // alloca on Linux (also OSX)
#include <stdlib.h> // alloca on OSX and FreeBSD (and Linux?)
#endif
#include <cassert>
#include <cstring> // memcpy, memmove, strcpy, strlen
#include <cstddef> // ptrdiff_t
#include "OscHostEndianness.h"
#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug
namespace std {
using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'.
}
#endif
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
}
// round up to the next highest multiple of 4. unless x is already a multiple of 4
static inline std::size_t RoundUp4( std::size_t x )
{
return (x + 3) & ~((std::size_t)0x03);
}
OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity )
: data_( buffer )
, end_( data_ + capacity )
, typeTagsCurrent_( end_ )
, messageCursor_( data_ )
, argumentCurrent_( data_ )
, elementSizePtr_( 0 )
, messageIsInProgress_( false )
{
// sanity check integer types declared in OscTypes.h
// you'll need to fix OscTypes.h if any of these asserts fail
assert( sizeof(osc::int32) == 4 );
assert( sizeof(osc::uint32) == 4 );
assert( sizeof(osc::int64) == 8 );
assert( sizeof(osc::uint64) == 8 );
}
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 =
reinterpret_cast<uint32*>(data_ + *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.
std::ptrdiff_t d = endPtr - reinterpret_cast<char*>(elementSizePtr_);
// assert( d >= 4 && d <= 0x7FFFFFFF ); // assume packets smaller than 2Gb
uint32 elementSize = static_cast<uint32>(d - 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()
{
std::size_t 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
std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0)
+ RoundUp4(std::strlen(addressPattern) + 1) + 4;
if( required > Capacity() )
throw OutOfBufferMemoryException();
}
void OutboundPacketStream::CheckForAvailableArgumentSpace( std::size_t argumentLength )
{
// plus three for extra type tag, comma and null terminator
std::size_t 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;
}
std::size_t OutboundPacketStream::Capacity() const
{
return end_ - data_;
}
std::size_t OutboundPacketStream::Size() const
{
std::size_t 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_ );
std::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_ );
std::strcpy( messageCursor_, rhs.addressPattern );
std::size_t rhsLength = std::strlen(rhs.addressPattern);
messageCursor_ += rhsLength + 1;
// zero pad to 4-byte boundary
std::size_t 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();
std::size_t typeTagsCount = end_ - typeTagsCurrent_;
if( typeTagsCount ){
char *tempTypeTags = (char*)alloca(typeTagsCount);
std::memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );
// slot size includes comma and null terminator
std::size_t typeTagSlotSize = RoundUp4( typeTagsCount + 2 );
std::size_t argumentsSize = argumentCurrent_ - messageCursor_;
std::memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );
messageCursor_[0] = ',';
// copy type tags in reverse (really forward) order
for( std::size_t i=0; i < typeTagsCount; ++i )
messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];
char *p = messageCursor_ + 1 + typeTagsCount;
for( std::size_t 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
std::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(std::strlen(rhs) + 1) );
*(--typeTagsCurrent_) = STRING_TYPE_TAG;
std::strcpy( argumentCurrent_, rhs );
std::size_t rhsLength = std::strlen(rhs);
argumentCurrent_ += rhsLength + 1;
// zero pad to 4-byte boundary
std::size_t i = rhsLength + 1;
while( i & 0x3 ){
*argumentCurrent_++ = '\0';
++i;
}
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
{
CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
*(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;
std::strcpy( argumentCurrent_, rhs );
std::size_t rhsLength = std::strlen(rhs);
argumentCurrent_ += rhsLength + 1;
// zero pad to 4-byte boundary
std::size_t 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;
std::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;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs )
{
(void) rhs;
CheckForAvailableArgumentSpace(0);
*(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG;
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs )
{
(void) rhs;
CheckForAvailableArgumentSpace(0);
*(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG;
return *this;
}
} // namespace osc

View File

@@ -0,0 +1,154 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H
#define INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H
#include <cstring> // size_t
#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, std::size_t capacity );
~OutboundPacketStream();
void Clear();
std::size_t Capacity() const;
// invariant: size() is valid even while building a message.
std::size_t 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 );
#if !(defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__))
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 );
OutboundPacketStream& operator<<( const ArrayInitiator& rhs );
OutboundPacketStream& operator<<( const ArrayTerminator& rhs );
private:
char *BeginElement( char *beginPtr );
void EndElement( char *endPtr );
bool ElementSizeSlotRequired() const;
void CheckForAvailableBundleSpace();
void CheckForAvailableMessageSpace( const char *addressPattern );
void CheckForAvailableArgumentSpace( std::size_t 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_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H */

View File

@@ -0,0 +1,79 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCPACKETLISTENER_H
#define INCLUDED_OSCPACK_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_OSCPACK_OSCPACKETLISTENER_H */

View File

@@ -0,0 +1,261 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscPrintReceivedElements.h"
#include <cstring>
#include <ctime>
#include <iostream>
#include <iomanip>
#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug
namespace std {
using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'.
}
#endif
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 );
const char *timeString = std::ctime( &t );
size_t len = std::strlen( timeString );
// -1 to omit trailing newline from string returned by ctime()
if( len > 1 )
os.write( timeString, len - 1 );
}
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:
{
const void *data;
osc_bundle_element_size_t size;
arg.AsBlobUnchecked( data, size );
os << "OSC-blob:<<" << std::hex << std::setfill('0');
unsigned char *p = (unsigned char*)data;
for( osc_bundle_element_size_t 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;
case ARRAY_BEGIN_TYPE_TAG:
os << "[";
break;
case ARRAY_END_TYPE_TAG:
os << "]";
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

View File

@@ -0,0 +1,54 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H
#define INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H
#include <iosfwd>
#include "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_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H */

View File

@@ -0,0 +1,796 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscReceivedElements.h"
#include "OscHostEndianness.h"
#include <cstddef> // ptrdiff_t
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;
}
// round up to the next highest multiple of 4. unless x is already a multiple of 4
static inline uint32 RoundUp4( uint32 x )
{
return (x + 3) & ~((uint32)0x03);
}
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
}
static inline 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
}
static inline 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] == '#');
}
osc_bundle_element_size_t ReceivedBundleElement::Size() const
{
return ToInt32( sizePtr_ );
}
//------------------------------------------------------------------------------
bool ReceivedMessageArgument::AsBool() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == TRUE_TYPE_TAG )
return true;
else if( *typeTagPtr_ == FALSE_TYPE_TAG )
return false;
else
throw WrongArgumentTypeException();
}
bool ReceivedMessageArgument::AsBoolUnchecked() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == TRUE_TYPE_TAG )
return true;
else
return false;
}
int32 ReceivedMessageArgument::AsInt32() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == 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] = argumentPtr_[3];
u.c[1] = argumentPtr_[2];
u.c[2] = argumentPtr_[1];
u.c[3] = argumentPtr_[0];
return u.i;
#else
return *(int32*)argumentPtr_;
#endif
}
float ReceivedMessageArgument::AsFloat() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == 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] = argumentPtr_[3];
u.c[1] = argumentPtr_[2];
u.c[2] = argumentPtr_[1];
u.c[3] = argumentPtr_[0];
return u.f;
#else
return *(float*)argumentPtr_;
#endif
}
char ReceivedMessageArgument::AsChar() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == CHAR_TYPE_TAG )
return AsCharUnchecked();
else
throw WrongArgumentTypeException();
}
char ReceivedMessageArgument::AsCharUnchecked() const
{
return (char)ToInt32( argumentPtr_ );
}
uint32 ReceivedMessageArgument::AsRgbaColor() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == RGBA_COLOR_TYPE_TAG )
return AsRgbaColorUnchecked();
else
throw WrongArgumentTypeException();
}
uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
{
return ToUInt32( argumentPtr_ );
}
uint32 ReceivedMessageArgument::AsMidiMessage() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG )
return AsMidiMessageUnchecked();
else
throw WrongArgumentTypeException();
}
uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
{
return ToUInt32( argumentPtr_ );
}
int64 ReceivedMessageArgument::AsInt64() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == INT64_TYPE_TAG )
return AsInt64Unchecked();
else
throw WrongArgumentTypeException();
}
int64 ReceivedMessageArgument::AsInt64Unchecked() const
{
return ToInt64( argumentPtr_ );
}
uint64 ReceivedMessageArgument::AsTimeTag() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == TIME_TAG_TYPE_TAG )
return AsTimeTagUnchecked();
else
throw WrongArgumentTypeException();
}
uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
{
return ToUInt64( argumentPtr_ );
}
double ReceivedMessageArgument::AsDouble() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == 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] = argumentPtr_[7];
u.c[1] = argumentPtr_[6];
u.c[2] = argumentPtr_[5];
u.c[3] = argumentPtr_[4];
u.c[4] = argumentPtr_[3];
u.c[5] = argumentPtr_[2];
u.c[6] = argumentPtr_[1];
u.c[7] = argumentPtr_[0];
return u.d;
#else
return *(double*)argumentPtr_;
#endif
}
const char* ReceivedMessageArgument::AsString() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == STRING_TYPE_TAG )
return argumentPtr_;
else
throw WrongArgumentTypeException();
}
const char* ReceivedMessageArgument::AsSymbol() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == SYMBOL_TYPE_TAG )
return argumentPtr_;
else
throw WrongArgumentTypeException();
}
void ReceivedMessageArgument::AsBlob( const void*& data, osc_bundle_element_size_t& size ) const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == BLOB_TYPE_TAG )
AsBlobUnchecked( data, size );
else
throw WrongArgumentTypeException();
}
void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const
{
// read blob size as an unsigned int then validate
osc_bundle_element_size_t sizeResult = (osc_bundle_element_size_t)ToUInt32( argumentPtr_ );
if( !IsValidElementSizeValue(sizeResult) )
throw MalformedMessageException("invalid blob size");
size = sizeResult;
data = (void*)(argumentPtr_+ osc::OSC_SIZEOF_INT32);
}
std::size_t ReceivedMessageArgument::ComputeArrayItemCount() const
{
// it is only valid to call ComputeArrayItemCount when the argument is the array start marker
if( !IsArrayBegin() )
throw WrongArgumentTypeException();
std::size_t result = 0;
unsigned int level = 0;
const char *typeTag = typeTagPtr_ + 1;
// iterate through all type tags. note that ReceivedMessage::Init
// has already checked that the message is well formed.
while( *typeTag ) {
switch( *typeTag++ ) {
case ARRAY_BEGIN_TYPE_TAG:
level += 1;
break;
case ARRAY_END_TYPE_TAG:
if(level == 0)
return result;
level -= 1;
break;
default:
if( level == 0 ) // only count items at level 0
++result;
}
}
return result;
}
//------------------------------------------------------------------------------
void ReceivedMessageArgumentIterator::Advance()
{
if( !value_.typeTagPtr_ )
return;
switch( *value_.typeTagPtr_++ ){
case '\0':
// don't advance past end
--value_.typeTagPtr_;
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_.argumentPtr_ += 4;
break;
case INT64_TYPE_TAG:
case TIME_TAG_TYPE_TAG:
case DOUBLE_TYPE_TAG:
value_.argumentPtr_ += 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_.argumentPtr_ = FindStr4End( value_.argumentPtr_ );
break;
case BLOB_TYPE_TAG:
{
// treat blob size as an unsigned int for the purposes of this calculation
uint32 blobSize = ToUInt32( value_.argumentPtr_ );
value_.argumentPtr_ = value_.argumentPtr_ + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize );
}
break;
case ARRAY_BEGIN_TYPE_TAG:
case ARRAY_END_TYPE_TAG:
// [ 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.
// zero length, don't advance argument ptr
break;
default: // unknown type tag
// don't advance
--value_.typeTagPtr_;
break;
}
}
//------------------------------------------------------------------------------
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, osc_bundle_element_size_t size )
{
if( !IsValidElementSizeValue(size) )
throw MalformedMessageException( "invalid message size" );
if( size == 0 )
throw MalformedMessageException( "zero length messages not permitted" );
if( !IsMultipleOf4(size) )
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_;
unsigned int arrayLevel = 0;
do{
switch( *typeTag ){
case TRUE_TYPE_TAG:
case FALSE_TYPE_TAG:
case NIL_TYPE_TAG:
case INFINITUM_TYPE_TAG:
// zero length
break;
// [ 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.
case ARRAY_BEGIN_TYPE_TAG:
++arrayLevel;
// (zero length argument data)
break;
case ARRAY_END_TYPE_TAG:
--arrayLevel;
// (zero length argument data)
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 + osc::OSC_SIZEOF_INT32 > end )
MalformedMessageException( "arguments exceed message size" );
// treat blob size as an unsigned int for the purposes of this calculation
uint32 blobSize = ToUInt32( argument );
argument = argument + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize );
if( argument > end )
MalformedMessageException( "arguments exceed message size" );
}
break;
default:
throw MalformedMessageException( "unknown type tag" );
}
}while( *++typeTag != '\0' );
typeTagsEnd_ = typeTag;
if( arrayLevel != 0 )
throw MalformedMessageException( "array was not terminated before end of message (expected ']' end of array tag)" );
}
// These invariants should be guaranteed by the above code.
// we depend on them in the implementation of ArgumentCount()
#ifndef NDEBUG
std::ptrdiff_t argumentCount = typeTagsEnd_ - typeTagsBegin_;
assert( argumentCount >= 0 );
assert( argumentCount <= OSC_INT32_MAX );
#endif
}
}
//------------------------------------------------------------------------------
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, osc_bundle_element_size_t size )
{
if( !IsValidElementSizeValue(size) )
throw MalformedBundleException( "invalid bundle size" );
if( size < 16 )
throw MalformedBundleException( "packet too short for bundle" );
if( !IsMultipleOf4(size) )
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 + osc::OSC_SIZEOF_INT32 > end_ )
throw MalformedBundleException( "packet too short for elementSize" );
// treat element size as an unsigned int for the purposes of this calculation
uint32 elementSize = ToUInt32( p );
if( (elementSize & ((uint32)0x03)) != 0 )
throw MalformedBundleException( "bundle element size must be multiple of four" );
p += osc::OSC_SIZEOF_INT32 + 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

View File

@@ -0,0 +1,548 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H
#define INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H
#include <cassert>
#include <cstddef>
#include <cstring> // size_t
#include "OscTypes.h"
#include "OscException.h"
namespace osc{
class MalformedPacketException : public Exception{
public:
MalformedPacketException( const char *w="malformed packet" )
: Exception( w ) {}
};
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:
// Although the OSC spec is not entirely clear on this, we only support
// packets up to 0x7FFFFFFC bytes long (the maximum 4-byte aligned value
// representable by an int32). An exception will be raised if you pass a
// larger value to the ReceivedPacket() constructor.
ReceivedPacket( const char *contents, osc_bundle_element_size_t size )
: contents_( contents )
, size_( ValidateSize(size) ) {}
ReceivedPacket( const char *contents, std::size_t size )
: contents_( contents )
, size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {}
#if !(defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__))
ReceivedPacket( const char *contents, int size )
: contents_( contents )
, size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {}
#endif
bool IsMessage() const { return !IsBundle(); }
bool IsBundle() const;
osc_bundle_element_size_t Size() const { return size_; }
const char *Contents() const { return contents_; }
private:
const char *contents_;
osc_bundle_element_size_t size_;
static osc_bundle_element_size_t ValidateSize( osc_bundle_element_size_t size )
{
// sanity check integer types declared in OscTypes.h
// you'll need to fix OscTypes.h if any of these asserts fail
assert( sizeof(osc::int32) == 4 );
assert( sizeof(osc::uint32) == 4 );
assert( sizeof(osc::int64) == 8 );
assert( sizeof(osc::uint64) == 8 );
if( !IsValidElementSizeValue(size) )
throw MalformedPacketException( "invalid packet size" );
if( size == 0 )
throw MalformedPacketException( "zero length elements not permitted" );
if( !IsMultipleOf4(size) )
throw MalformedPacketException( "element size must be multiple of four" );
return size;
}
};
class ReceivedBundleElement{
public:
ReceivedBundleElement( const char *sizePtr )
: sizePtr_( sizePtr ) {}
friend class ReceivedBundleElementIterator;
bool IsMessage() const { return !IsBundle(); }
bool IsBundle() const;
osc_bundle_element_size_t Size() const;
const char *Contents() const { return sizePtr_ + osc::OSC_SIZEOF_INT32; }
private:
const char *sizePtr_;
};
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_.sizePtr_ = value_.Contents() + value_.Size(); }
bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const
{
return value_.sizePtr_ == rhs.value_.sizePtr_;
}
};
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 *typeTagPtr, const char *argumentPtr )
: typeTagPtr_( typeTagPtr )
, argumentPtr_( argumentPtr ) {}
friend class ReceivedMessageArgumentIterator;
char TypeTag() const { return *typeTagPtr_; }
// 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 *typeTagPtr_ == TRUE_TYPE_TAG || *typeTagPtr_ == FALSE_TYPE_TAG; }
bool AsBool() const;
bool AsBoolUnchecked() const;
bool IsNil() const { return *typeTagPtr_ == NIL_TYPE_TAG; }
bool IsInfinitum() const { return *typeTagPtr_ == INFINITUM_TYPE_TAG; }
bool IsInt32() const { return *typeTagPtr_ == INT32_TYPE_TAG; }
int32 AsInt32() const;
int32 AsInt32Unchecked() const;
bool IsFloat() const { return *typeTagPtr_ == FLOAT_TYPE_TAG; }
float AsFloat() const;
float AsFloatUnchecked() const;
bool IsChar() const { return *typeTagPtr_ == CHAR_TYPE_TAG; }
char AsChar() const;
char AsCharUnchecked() const;
bool IsRgbaColor() const { return *typeTagPtr_ == RGBA_COLOR_TYPE_TAG; }
uint32 AsRgbaColor() const;
uint32 AsRgbaColorUnchecked() const;
bool IsMidiMessage() const { return *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG; }
uint32 AsMidiMessage() const;
uint32 AsMidiMessageUnchecked() const;
bool IsInt64() const { return *typeTagPtr_ == INT64_TYPE_TAG; }
int64 AsInt64() const;
int64 AsInt64Unchecked() const;
bool IsTimeTag() const { return *typeTagPtr_ == TIME_TAG_TYPE_TAG; }
uint64 AsTimeTag() const;
uint64 AsTimeTagUnchecked() const;
bool IsDouble() const { return *typeTagPtr_ == DOUBLE_TYPE_TAG; }
double AsDouble() const;
double AsDoubleUnchecked() const;
bool IsString() const { return *typeTagPtr_ == STRING_TYPE_TAG; }
const char* AsString() const;
const char* AsStringUnchecked() const { return argumentPtr_; }
bool IsSymbol() const { return *typeTagPtr_ == SYMBOL_TYPE_TAG; }
const char* AsSymbol() const;
const char* AsSymbolUnchecked() const { return argumentPtr_; }
bool IsBlob() const { return *typeTagPtr_ == BLOB_TYPE_TAG; }
void AsBlob( const void*& data, osc_bundle_element_size_t& size ) const;
void AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const;
bool IsArrayBegin() const { return *typeTagPtr_ == ARRAY_BEGIN_TYPE_TAG; }
bool IsArrayEnd() const { return *typeTagPtr_ == ARRAY_END_TYPE_TAG; }
// Calculate the number of top-level items in the array. Nested arrays count as one item.
// Only valid at array start. Will throw an exception if IsArrayStart() == false.
std::size_t ComputeArrayItemCount() const;
private:
const char *typeTagPtr_;
const char *argumentPtr_;
};
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_.typeTagPtr_ == rhs.value_.typeTagPtr_;
}
};
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
// same goes for array boundaries
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 )
{
(void) rhs; // suppress unused parameter warning
if( !Eos() )
throw ExcessArgumentException();
return *this;
}
};
class ReceivedMessage{
void Init( const char *bundle, osc_bundle_element_size_t size );
public:
explicit ReceivedMessage( const ReceivedPacket& packet );
explicit ReceivedMessage( const ReceivedBundleElement& bundleElement );
const char *AddressPattern() const { return addressPattern_; }
// Support for non-standard SuperCollider integer address patterns:
bool AddressPatternIsUInt32() const;
uint32 AddressPatternAsUInt32() const;
uint32 ArgumentCount() const { return static_cast<uint32>(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, osc_bundle_element_size_t size );
public:
explicit ReceivedBundle( const ReceivedPacket& packet );
explicit ReceivedBundle( const ReceivedBundleElement& bundleElement );
uint64 TimeTag() const;
uint32 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_;
uint32 elementCount_;
};
} // namespace osc
#endif /* INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H */

View File

@@ -0,0 +1,52 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscTypes.h"
namespace osc{
BundleInitiator BeginBundleImmediate(1);
BundleTerminator EndBundle;
MessageTerminator EndMessage;
NilType OscNil;
#ifndef _OBJC_OBJC_H_
NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead
#endif
InfinitumType Infinitum;
ArrayInitiator BeginArray;
ArrayTerminator EndArray;
} // namespace osc

View File

@@ -0,0 +1,240 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCTYPES_H
#define INCLUDED_OSCPACK_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) || defined(__aarch64__)
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) || defined(__aarch64__)
typedef signed int int32;
typedef unsigned int uint32;
#else
typedef signed long int32;
typedef unsigned long uint32;
#endif
enum ValueTypeSizes{
OSC_SIZEOF_INT32 = 4,
OSC_SIZEOF_UINT32 = 4,
OSC_SIZEOF_INT64 = 8,
OSC_SIZEOF_UINT64 = 8,
};
// osc_bundle_element_size_t is used for the size of bundle elements and blobs
// the OSC spec specifies these as int32 (signed) but we ensure that they
// are always positive since negative field sizes make no sense.
typedef int32 osc_bundle_element_size_t;
enum {
OSC_INT32_MAX = 0x7FFFFFFF,
// Element sizes are specified to be int32, and are always rounded up to nearest
// multiple of 4. Therefore their values can't be greater than 0x7FFFFFFC.
OSC_BUNDLE_ELEMENT_SIZE_MAX = 0x7FFFFFFC
};
inline bool IsValidElementSizeValue( osc_bundle_element_size_t x )
{
// sizes may not be negative or exceed OSC_BUNDLE_ELEMENT_SIZE_MAX
return x >= 0 && x <= OSC_BUNDLE_ELEMENT_SIZE_MAX;
}
inline bool IsMultipleOf4( osc_bundle_element_size_t x )
{
return (x & ((osc_bundle_element_size_t)0x03)) == 0;
}
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',
ARRAY_BEGIN_TYPE_TAG = '[',
ARRAY_END_TYPE_TAG = ']'
};
// 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 OscNil;
#ifndef _OBJC_OBJC_H_
extern NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead
#endif
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_, osc_bundle_element_size_t size_ )
: data( data_ ), size( size_ ) {}
const void* data;
osc_bundle_element_size_t size;
};
struct ArrayInitiator{
};
extern ArrayInitiator BeginArray;
struct ArrayTerminator{
};
extern ArrayTerminator EndArray;
} // namespace osc
#endif /* INCLUDED_OSCPACK_OSCTYPES_H */

View File

@@ -0,0 +1 @@
set (DEFAULT_MODULE ON)

View File

@@ -0,0 +1,80 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* 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. *
* *
* 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 __OPENSPACE_MODULE_TOUCH___TOUCHEAR___H__
#define __OPENSPACE_MODULE_TOUCH___TOUCHEAR___H__
#include <modules/touch/ext/libTUIO/TUIO/TuioListener.h>
#include <modules/touch/ext/libTUIO/TUIO/TuioClient.h>
#include <modules/touch/ext/libTUIO/TUIO/UdpReceiver.h>
#include <modules/touch/ext/libTUIO/TUIO/TcpReceiver.h>
#include <glm/glm.hpp>
#include <math.h>
#include <vector>
#include <mutex>
#include <numeric>
#include <mutex>
#include <algorithm>
using namespace TUIO;
class TuioEar : public TuioListener {
public:
TuioEar();
~TuioEar() {
_tuioClient->disconnect();
delete _tuioClient;
delete _oscReceiver;
}
void addTuioObject(TuioObject *tobj);
void updateTuioObject(TuioObject *tobj);
void removeTuioObject(TuioObject *tobj);
void addTuioCursor(TuioCursor *tcur);
void updateTuioCursor(TuioCursor *tcur);
void removeTuioCursor(TuioCursor *tcur);
void addTuioBlob(TuioBlob *tblb);
void updateTuioBlob(TuioBlob *tblb);
void removeTuioBlob(TuioBlob *tblb);
void refresh(TuioTime frameTime);
std::vector<TuioCursor> getInput();
void clearInput();
private:
TuioClient *_tuioClient;
OscReceiver *_oscReceiver;
std::vector<TuioCursor> _list;
std::vector<int> _removeList;
std::mutex _mx;
};
#endif // __OPENSPACE_MODULE_TOUCH___TOUCHWRAPPER___H__

View File

@@ -0,0 +1,150 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* 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. *
* *
* 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 <modules/touch/include/TuioEar.h>
#include <vector>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/settingsengine.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/interaction/interactionhandler.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/rendering/screenspacerenderable.h>
#include <ghoul/logging/logmanager.h>
namespace {
const std::string _loggerCat = "TuioEar";
}
void TuioEar::addTuioObject(TuioObject *tobj) {
//std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/" << tobj->getTuioSourceID() << ") " << tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl;
}
void TuioEar::updateTuioObject(TuioObject *tobj) {
//std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/" << tobj->getTuioSourceID() << ") " << tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle()
//<< " " << tobj->getMotionSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl;
}
void TuioEar::removeTuioObject(TuioObject *tobj) {
//std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/" << tobj->getTuioSourceID() << ")" << std::endl;
}
void TuioEar::addTuioCursor(TuioCursor *tcur) {
_mx.lock();
// find same id in _list if it exists in _removeList (new input with same ID as a previously stored)
int i = tcur->getSessionID();
std::vector<int>::iterator foundID = std::find_if(
_removeList.begin(),
_removeList.end(),
[&i](int id) { return id == i; });
// if found, remove id from _removeList and update, otherwise add new id to list
if (foundID != _removeList.end()) {
std::find_if(
_list.begin(),
_list.end(),
[&i](const TuioCursor& cursor) {
return cursor.getSessionID() == i;
})->update(tcur);
_removeList.erase(foundID);
}
else
_list.push_back(TuioCursor(*tcur));
_mx.unlock();
}
void TuioEar::updateTuioCursor(TuioCursor *tcur) {
_mx.lock();
int i = tcur->getSessionID();
std::find_if(
_list.begin(),
_list.end(),
[&i](const TuioCursor& cursor) {
return cursor.getSessionID() == i;
})->update(tcur);
_mx.unlock();
}
// save id to be removed and remove it in clearInput
void TuioEar::removeTuioCursor(TuioCursor *tcur) {
_mx.lock();
_removeList.push_back(tcur->getSessionID());
//LINFO("To be removed: " << _removeFromList.size() << "\n");
_mx.unlock();
}
void TuioEar::addTuioBlob(TuioBlob *tblb) {
std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << "/" << tblb->getTuioSourceID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() << std::endl;
}
void TuioEar::updateTuioBlob(TuioBlob *tblb) {
std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << "/" << tblb->getTuioSourceID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea()
<< " " << tblb->getMotionSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel() << " " << tblb->getRotationAccel() << std::endl;
}
void TuioEar::removeTuioBlob(TuioBlob *tblb) {
std::cout << "del blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << "/" << tblb->getTuioSourceID() << ")" << std::endl;
}
void TuioEar::refresh(TuioTime frameTime) {
//LINFO("refresh " << frameTime.getTotalMilliseconds() << "\n"); // about every 15ms on TuioPad app
}
std::vector<TuioCursor> TuioEar::getInput() {
std::lock_guard<std::mutex> lock(_mx);
return _list;
}
void TuioEar::clearInput() {
_mx.lock();
_list.erase(
std::remove_if(
_list.begin(),
_list.end(),
[this](const TuioCursor& cursor) {
return std::find_if(
_removeList.begin(),
_removeList.end(),
[&cursor](int id) {\
return cursor.getSessionID() == id;
}
) != _removeList.end();
}),
_list.end()
);
_removeList.clear();
_mx.unlock();
}
TuioEar::TuioEar() {
_oscReceiver = new UdpReceiver(3333);
//oscReceiver = new TcpReceiver("127.0.0.1",3333);
_tuioClient = new TuioClient(_oscReceiver);
_tuioClient->addTuioListener(this);
_tuioClient->connect();
}

View File

@@ -0,0 +1,200 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* 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. *
* *
* 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 <modules/touch/touchmodule.h>
#include <modules/touch/include/TuioEar.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/settingsengine.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/interaction/interactionhandler.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/rendering/screenspacerenderable.h>
#include <ghoul/logging/logmanager.h>
#include <glm/ext.hpp>
#include <sstream>
#include <string>
#include <iostream>
#include <thread> // std::this_thread::sleep_for
#include <chrono> // std::chrono::seconds
namespace {
const std::string _loggerCat = "TouchModule";
}
namespace openspace {
TuioEar TouchModule::*ear;
bool TouchModule::gotNewInput() {
// Get new input from listener
list = ear->getInput();
ear->clearInput();
// Erase old input id's that no longer exists
lastProcessed.erase(
std::remove_if(
lastProcessed.begin(),
lastProcessed.end(),
[this](const Point& point) {
return std::find_if(
list.begin(),
list.end(),
[&point](const TuioCursor& c) {
return point.first == c.getSessionID();
}
) == list.end(); }),
lastProcessed.end()
);
// Return true if we got new input
if (list.size() == lastProcessed.size() && list.size() > 0) {
for (Point& p : lastProcessed) {
std::vector<TuioCursor>::iterator foundID = find_if(list.begin(), list.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; });
if (p.second.getTuioTime() == foundID->getPath().back().getTuioTime())
return false;
}
return true;
}
else
return false;
}
TouchModule::TouchModule()
: OpenSpaceModule("Touch")
{
OsEng.registerModuleCallback(
OpenSpaceEngine::CallbackOption::Initialize,
[&]() {
LDEBUGC("TouchModule", "Initializing TuioEar");
ear = new TuioEar();
}
);
OsEng.registerModuleCallback(
OpenSpaceEngine::CallbackOption::Deinitialize,
[&]() {
LDEBUGC("TouchModule", "Deinitialize TuioEar");
delete ear;
}
);
OsEng.registerModuleCallback( // maybe call ear->clearInput() here rather than postdraw
OpenSpaceEngine::CallbackOption::PreSync,
[&]() {
if (OsEng.isMaster() && gotNewInput()) {
//std::this_thread::sleep_for(std::chrono::seconds(1));
Camera* cam = OsEng.interactionHandler().camera();
glm::vec3 pos = cam->positionVec3();
glm::vec3 focusDir = glm::normalize(glm::vec3(cam->focusPositionVec3()) - pos);
glm::vec2 centroid;
float distance = 0.0f;
float lastDistance = 0.0f;
float zoomFactor = 0.0f;
if (list.size() > 1) { // calculate centroid if we have multiple IDs
centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](float x, const TuioCursor& c) { return x + c.getX(); }) / list.size();
centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](float y, const TuioCursor& c) { return y + c.getY(); }) / list.size();
// ------- testing, should use more than just one point later on
distance = std::accumulate(list.begin(), list.end(), 0.0f, [&centroid](float d, const TuioCursor& c) {
return d + sqrt(pow(c.getX() - centroid.x, 2) + pow(c.getY() - centroid.y, 2));
});
lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&centroid](float d, const Point& p) {
return d + sqrt(pow(p.second.getX() - centroid.x, 2) + pow(p.second.getY() - centroid.y, 2));
});
zoomFactor = distance - lastDistance; // should be dependant on screen size, distance from focusNode
zoomFactor *= glm::distance(pos, glm::vec3(cam->focusPositionVec3()));
std::cout << "Distance: " << distance << ", Last Distance: " << lastDistance << ", zoomFactor: " << zoomFactor
<< "\n";
glm::vec3 newPos = pos + focusDir*zoomFactor;
cam->setPosition(newPos);
}
else { // do new rotation, work with spherical coordinates. Orbit it both position and rotation, check OrbitInteractionMode in interactionmode
//cam->rotate(rot);
}
// ----------------
std::ostringstream os; // for debugging
for (const TuioCursor &j : list) { // go through each item
std::list<TuioPoint> path = j.getPath();
TuioTime lastTime = find_if(
lastProcessed.begin(),
lastProcessed.end(),
[&j](const Point& p) { return p.first == j.getSessionID(); }
)->second.getTuioTime();
std::list<TuioPoint>::iterator lastPoint = find_if(
path.begin(),
path.end(),
[&lastTime](const TuioPoint& c) { return lastTime == c.getTuioTime(); });
int count = 0;
for (; lastPoint != path.end(); ++lastPoint) // here we can access all elements that are to be processed
count++;
os << ", Id: " << j.getCursorID() << ", path size: " << j.getPath().size() << ", (" << j.getX() << "," << j.getY() << "), To Process: " << count;
}
LINFO("List size: " << list.size() << os.str() << "\n");
os.clear();
}
// update lastProcessed
lastProcessed.clear();
for (const TuioCursor& c : list) {
lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back()));
}
}
);
OsEng.registerModuleCallback(
OpenSpaceEngine::CallbackOption::PostDraw,
[&]() {
WindowWrapper& wrapper = OsEng.windowWrapper();
if (OsEng.isMaster() && wrapper.isRegularRendering()) {
}
}
);
}
} // namespace openspace

View File

@@ -0,0 +1,51 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* 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. *
* *
* 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 __OPENSPACE_MODULE_TOUCH___TOUCHMODULE___H__
#define __OPENSPACE_MODULE_TOUCH___TOUCHMODULE___H__
#include <openspace/util/openspacemodule.h>
#include <modules/touch/include/TuioEar.h>
//using Point = std::vector<TuioCursor>::iterator;
using Point = std::pair<int, TuioPoint>;
namespace openspace {
class TouchModule : public OpenSpaceModule {
public:
TouchModule();
bool gotNewInput();
TuioEar *ear;
std::vector<TuioCursor> list;
std::vector<Point> lastProcessed; // contains an id and the TuioPoint that was processed last frame
};
} // namespace openspace
#endif // __OPENSPACE_MODULE_TOUCH___TOUCHMODULE___H__

View File

@@ -23,7 +23,7 @@ return {
-- Sets the scene that is to be loaded by OpenSpace. A scene file is a description
-- of all entities that will be visible during an instance of OpenSpace
Scene = "${SCENE}/default.scene",
Scene = "${SCENE}/globebrowsing.scene",
-- Scene = "${SCENE}/globebrowsing.scene",
-- Scene = "${SCENE}/rosetta.scene",

View File

@@ -201,7 +201,7 @@ Interpolator<double>& InteractionMode::rotateToFocusNodeInterpolator() {
// KeyframeInteractionMode
KeyframeInteractionMode::KeyframeInteractionMode(){
KeyframeInteractionMode::KeyframeInteractionMode() {
}