andrew@0
|
1 /*
|
andrew@0
|
2
|
andrew@0
|
3 Copyright (c) 2007-2009, Damian Stewart
|
andrew@0
|
4 All rights reserved.
|
andrew@0
|
5
|
andrew@0
|
6 Redistribution and use in source and binary forms, with or without
|
andrew@0
|
7 modification, are permitted provided that the following conditions are met:
|
andrew@0
|
8 * Redistributions of source code must retain the above copyright
|
andrew@0
|
9 notice, this list of conditions and the following disclaimer.
|
andrew@0
|
10 * Redistributions in binary form must reproduce the above copyright
|
andrew@0
|
11 notice, this list of conditions and the following disclaimer in the
|
andrew@0
|
12 documentation and/or other materials provided with the distribution.
|
andrew@0
|
13 * Neither the name of the developer nor the
|
andrew@0
|
14 names of its contributors may be used to endorse or promote products
|
andrew@0
|
15 derived from this software without specific prior written permission.
|
andrew@0
|
16
|
andrew@0
|
17 THIS SOFTWARE IS PROVIDED BY DAMIAN STEWART ''AS IS'' AND ANY
|
andrew@0
|
18 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
andrew@0
|
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
andrew@0
|
20 DISCLAIMED. IN NO EVENT SHALL DAMIAN STEWART BE LIABLE FOR ANY
|
andrew@0
|
21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
andrew@0
|
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
andrew@0
|
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
andrew@0
|
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
andrew@0
|
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
andrew@0
|
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
andrew@0
|
27 */
|
andrew@0
|
28
|
andrew@0
|
29 #include "ofxOscReceiver.h"
|
andrew@0
|
30
|
andrew@0
|
31 #ifndef TARGET_WIN32
|
andrew@0
|
32 #include <pthread.h>
|
andrew@0
|
33 #endif
|
andrew@0
|
34 #include <iostream>
|
andrew@0
|
35 #include <assert.h>
|
andrew@0
|
36
|
andrew@0
|
37 ofxOscReceiver::ofxOscReceiver()
|
andrew@0
|
38 {
|
andrew@0
|
39 listen_socket = NULL;
|
andrew@0
|
40 }
|
andrew@0
|
41
|
andrew@0
|
42 void ofxOscReceiver::setup( int listen_port )
|
andrew@0
|
43 {
|
andrew@0
|
44 // if we're already running, shutdown before running again
|
andrew@0
|
45 if ( listen_socket )
|
andrew@0
|
46 shutdown();
|
andrew@0
|
47
|
andrew@0
|
48 // create the mutex
|
andrew@0
|
49 #ifdef TARGET_WIN32
|
andrew@0
|
50 mutex = CreateMutexA( NULL, FALSE, NULL );
|
andrew@0
|
51 #else
|
andrew@0
|
52 pthread_mutex_init( &mutex, NULL );
|
andrew@0
|
53 #endif
|
andrew@0
|
54
|
andrew@0
|
55 // create socket
|
andrew@0
|
56 socketHasShutdown = false;
|
andrew@0
|
57 listen_socket = new UdpListeningReceiveSocket( IpEndpointName( IpEndpointName::ANY_ADDRESS, listen_port ), this );
|
andrew@0
|
58
|
andrew@0
|
59 // start thread
|
andrew@0
|
60 #ifdef TARGET_WIN32
|
andrew@0
|
61 thread = CreateThread(
|
andrew@0
|
62 NULL, // default security attributes
|
andrew@0
|
63 0, // use default stack size
|
andrew@0
|
64 &ofxOscReceiver::startThread, // thread function
|
andrew@0
|
65 (void*)this, // argument to thread function
|
andrew@0
|
66 0, // use default creation flags
|
andrew@0
|
67 NULL); // we don't the the thread id
|
andrew@0
|
68
|
andrew@0
|
69 #else
|
andrew@0
|
70 pthread_create( &thread, NULL, &ofxOscReceiver::startThread, (void*)this );
|
andrew@0
|
71 #endif
|
andrew@0
|
72 }
|
andrew@0
|
73
|
andrew@0
|
74 void ofxOscReceiver::shutdown()
|
andrew@0
|
75 {
|
andrew@0
|
76 if ( listen_socket )
|
andrew@0
|
77 {
|
andrew@0
|
78 // tell the socket to shutdown
|
andrew@0
|
79 listen_socket->AsynchronousBreak();
|
andrew@0
|
80 // wait for shutdown to complete
|
andrew@0
|
81 while (!socketHasShutdown)
|
andrew@0
|
82 {
|
andrew@0
|
83 #ifdef TARGET_WIN32
|
andrew@0
|
84 Sleep(1);
|
andrew@0
|
85 #else
|
andrew@0
|
86 // sleep 0.1ms
|
andrew@0
|
87 usleep(100);
|
andrew@0
|
88 #endif
|
andrew@0
|
89 }
|
andrew@0
|
90
|
andrew@0
|
91 // thread will clean up itself
|
andrew@0
|
92
|
andrew@0
|
93 // clean up the mutex
|
andrew@0
|
94 #ifdef TARGET_WIN32
|
andrew@0
|
95 ReleaseMutex( mutex );
|
andrew@0
|
96 #else
|
andrew@0
|
97 pthread_mutex_destroy( &mutex );
|
andrew@0
|
98 #endif
|
andrew@0
|
99
|
andrew@0
|
100 // delete the socket
|
andrew@0
|
101 delete listen_socket;
|
andrew@0
|
102 listen_socket = NULL;
|
andrew@0
|
103 }
|
andrew@0
|
104 }
|
andrew@0
|
105
|
andrew@0
|
106 ofxOscReceiver::~ofxOscReceiver()
|
andrew@0
|
107 {
|
andrew@0
|
108 shutdown();
|
andrew@0
|
109 }
|
andrew@0
|
110
|
andrew@0
|
111 #ifdef TARGET_WIN32
|
andrew@0
|
112 DWORD WINAPI
|
andrew@0
|
113 #else
|
andrew@0
|
114 void*
|
andrew@0
|
115 #endif
|
andrew@0
|
116 ofxOscReceiver::startThread( void* receiverInstance )
|
andrew@0
|
117 {
|
andrew@0
|
118 // cast the instance
|
andrew@0
|
119 ofxOscReceiver* instance = (ofxOscReceiver*)receiverInstance;
|
andrew@0
|
120 // start the socket listener
|
andrew@0
|
121 instance->listen_socket->Run();
|
andrew@0
|
122 // socket listener has finished - remember this fact
|
andrew@0
|
123 instance->socketHasShutdown = true;
|
andrew@0
|
124 // return
|
andrew@0
|
125 #ifdef TARGET_WIN32
|
andrew@0
|
126 return 0;
|
andrew@0
|
127 #else
|
andrew@0
|
128 return NULL;
|
andrew@0
|
129 #endif
|
andrew@0
|
130 }
|
andrew@0
|
131
|
andrew@0
|
132 void ofxOscReceiver::ProcessMessage( const osc::ReceivedMessage &m, const IpEndpointName& remoteEndpoint )
|
andrew@0
|
133 {
|
andrew@0
|
134 // convert the message to an ofxOscMessage
|
andrew@0
|
135 ofxOscMessage* ofMessage = new ofxOscMessage();
|
andrew@0
|
136
|
andrew@0
|
137 // set the address
|
andrew@0
|
138 ofMessage->setAddress( m.AddressPattern() );
|
andrew@0
|
139
|
andrew@0
|
140 // set the sender ip/host
|
andrew@0
|
141 char endpoint_host[ IpEndpointName::ADDRESS_STRING_LENGTH ];
|
andrew@0
|
142 remoteEndpoint.AddressAsString( endpoint_host );
|
andrew@0
|
143 ofMessage->setRemoteEndpoint( endpoint_host, remoteEndpoint.port );
|
andrew@0
|
144
|
andrew@0
|
145 // transfer the arguments
|
andrew@0
|
146 for ( osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
|
andrew@0
|
147 arg != m.ArgumentsEnd();
|
andrew@0
|
148 ++arg )
|
andrew@0
|
149 {
|
andrew@0
|
150 if ( arg->IsInt32() )
|
andrew@0
|
151 ofMessage->addIntArg( arg->AsInt32Unchecked() );
|
andrew@0
|
152 else if ( arg->IsFloat() )
|
andrew@0
|
153 ofMessage->addFloatArg( arg->AsFloatUnchecked() );
|
andrew@0
|
154 else if ( arg->IsString() )
|
andrew@0
|
155 ofMessage->addStringArg( arg->AsStringUnchecked() );
|
andrew@0
|
156 else
|
andrew@0
|
157 {
|
andrew@0
|
158 assert( false && "message argument is not int, float, or string" );
|
andrew@0
|
159 }
|
andrew@0
|
160 }
|
andrew@0
|
161
|
andrew@0
|
162 // now add to the queue
|
andrew@0
|
163
|
andrew@0
|
164 // at this point we are running inside the thread created by startThread,
|
andrew@0
|
165 // so anyone who calls hasWaitingMessages() or getNextMessage() is coming
|
andrew@0
|
166 // from a different thread
|
andrew@0
|
167
|
andrew@0
|
168 // so we have to practise shared memory management
|
andrew@0
|
169
|
andrew@0
|
170 // grab a lock on the queue
|
andrew@0
|
171 grabMutex();
|
andrew@0
|
172
|
andrew@0
|
173 // add incoming message on to the queue
|
andrew@0
|
174 messages.push_back( ofMessage );
|
andrew@0
|
175
|
andrew@0
|
176 // release the lock
|
andrew@0
|
177 releaseMutex();
|
andrew@0
|
178 }
|
andrew@0
|
179
|
andrew@0
|
180 bool ofxOscReceiver::hasWaitingMessages()
|
andrew@0
|
181 {
|
andrew@0
|
182 // grab a lock on the queue
|
andrew@0
|
183 grabMutex();
|
andrew@0
|
184
|
andrew@0
|
185 // check the length of the queue
|
andrew@0
|
186 int queue_length = (int)messages.size();
|
andrew@0
|
187
|
andrew@0
|
188 // release the lock
|
andrew@0
|
189 releaseMutex();
|
andrew@0
|
190
|
andrew@0
|
191 // return whether we have any messages
|
andrew@0
|
192 return queue_length > 0;
|
andrew@0
|
193 }
|
andrew@0
|
194
|
andrew@0
|
195 bool ofxOscReceiver::getNextMessage( ofxOscMessage* message )
|
andrew@0
|
196 {
|
andrew@0
|
197 // grab a lock on the queue
|
andrew@0
|
198 grabMutex();
|
andrew@0
|
199
|
andrew@0
|
200 // check if there are any to be got
|
andrew@0
|
201 if ( messages.size() == 0 )
|
andrew@0
|
202 {
|
andrew@0
|
203 // no: release the mutex
|
andrew@0
|
204 releaseMutex();
|
andrew@0
|
205 return false;
|
andrew@0
|
206 }
|
andrew@0
|
207
|
andrew@0
|
208 // copy the message from the queue to message
|
andrew@0
|
209 ofxOscMessage* src_message = messages.front();
|
andrew@0
|
210 message->copy( *src_message );
|
andrew@0
|
211
|
andrew@0
|
212 // now delete the src message
|
andrew@0
|
213 delete src_message;
|
andrew@0
|
214 // and remove it from the queue
|
andrew@0
|
215 messages.pop_front();
|
andrew@0
|
216
|
andrew@0
|
217 // release the lock on the queue
|
andrew@0
|
218 releaseMutex();
|
andrew@0
|
219
|
andrew@0
|
220 // return success
|
andrew@0
|
221 return true;
|
andrew@0
|
222 }
|
andrew@0
|
223
|
andrew@0
|
224 void ofxOscReceiver::grabMutex()
|
andrew@0
|
225 {
|
andrew@0
|
226 #ifdef TARGET_WIN32
|
andrew@0
|
227 WaitForSingleObject( mutex, INFINITE );
|
andrew@0
|
228 #else
|
andrew@0
|
229 pthread_mutex_lock( &mutex );
|
andrew@0
|
230 #endif
|
andrew@0
|
231 }
|
andrew@0
|
232
|
andrew@0
|
233 void ofxOscReceiver::releaseMutex()
|
andrew@0
|
234 {
|
andrew@0
|
235 #ifdef TARGET_WIN32
|
andrew@0
|
236 ReleaseMutex( mutex );
|
andrew@0
|
237 #else
|
andrew@0
|
238 pthread_mutex_unlock( &mutex );
|
andrew@0
|
239 #endif
|
andrew@0
|
240 }
|