root / src / touch / osc / OscHandler.h @ 45

View | Annotate | Download (9.7 KB)

1
/*
2
 * MultitouchOscReceiver.h
3
 *
4
 *      Author: sashikanth
5
 */
6
7
#ifndef MULTITOUCHOSCRECEIVER_H_
8
#define MULTITOUCHOSCRECEIVER_H_
9
10
#include <vector>
11
#include <algorithm>
12
13
#include "osc/OscReceivedElements.h"
14
#include "osc/OscOutboundPacketStream.h"
15
#include "osc/OscPacketListener.h"
16
#include "ip/UdpSocket.h"
17
18
#include "gesture/Gestures.h"
19
20
#define ADDRESS "127.0.0.1"
21
#define OUTPUT_BUFFER_SIZE 4096
22
#define IN_PORT 3330
23
#define OUTPUT_PORT 3333
24
25
using namespace std;
26
ContactSetFrame frame;
27
class OscHandler: public osc::OscPacketListener
28
{
29
public:
30
31
        ContactSetFrame gestrFrame;
32
        ContactSetFrame liveFrame;
33
        GestureCollector *listener;
34
        osc::OutboundPacketStream* outStream;
35
        UdpListeningReceiveSocket* inSock;
36
        bool gestrSampleStart;
37
        char buffer[OUTPUT_BUFFER_SIZE];
38
        vector<int> liveIds;
39
40
41
42
        OscHandler()
43
        {
44
                cout << "Initing osc streams" << endl;
45
                initOutStream();
46
                gestrSampleStart = false;
47
        }
48
49
        ~OscHandler()
50
        {
51
        }
52
53
        void handleGestrSample(osc::ReceivedMessageArgumentIterator & arg,
54
                        const osc::ReceivedMessage & m)
55
        {
56
                const char *smpl = (arg++)->AsString();
57
                if (strcmp(smpl, "start") == 0)
58
                {
59
                        const char *gestureName = (arg++)->AsString();
60
                        gestrSampleStart = true;
61
                        listener->startSample(gestureName);
62
                }
63
                else if (strcmp(smpl, "end") == 0)
64
                {
65
                        gestrSampleStart = false;
66
                        listener->endSample();
67
                }
68
                else if (strcmp(smpl, "set") == 0)
69
                {
70
                        Contact contact = createContactFromOscArgs(arg, m);
71
                        gestrFrame.push_back(contact);
72
                }
73
                else if (strcmp(smpl, "fseq") == 0)
74
                {
75
                        listener->updateFrame(gestrFrame);
76
                        gestrFrame.clear();
77
                }
78
                else
79
                        cout << "MsgParseError";
80
81
        }
82
83
        void handleGestrAction(osc::ReceivedMessageArgumentIterator & arg,
84
                        const osc::ReceivedMessage & m)
85
        {
86
                const char *actionString         = (arg++)->AsString();
87
                vector<string> actionParams;
88
                while (arg != m.ArgumentsEnd())
89
                        actionParams.push_back((arg++)->AsString());
90
91
                vector<string> actionResult = listener->gestureAction(actionString, actionParams);
92
                sendGestrActionResults(actionString, actionResult);
93
        }
94
95
        void handleTUIO(osc::ReceivedMessageArgumentIterator arg,
96
                        const osc::ReceivedMessage & m)
97
        {
98
                const char *param = (arg++)->AsString();
99
                if (strcmp(param, "set") == 0)
100
                {
101
                        Contact contact = createContactFromOscArgs(arg, m);
102
                        cloneContactToOutStream(contact);
103
                        liveFrame.push_back(contact);
104
                }
105
                else if (strcmp(param, "alive") == 0)
106
                {
107
                        vector<int> currIds = getCurrIdsAndSendToOutStream(arg, m);
108
109
                        //Check for change in fingers on screen.
110
                        bool fingersRaised = isFingerRaised(currIds);
111
                        bool fingersLowered = isFingerLowered(currIds);
112
113
                        if(fingersLowered)
114
                        {
115
//                                cout << "FingersLowered" << endl;
116
                                listener->startSample("");
117
                        }
118
                        if(fingersRaised)
119
                        {
120
//                                cout << "FingersRaised" << endl;
121
                                if(listener->isCurrentlyParameterized())
122
                                {
123
                                        listener->unParameterize();
124
                                        listener->startSample("");
125
                                }
126
                        }
127
                        liveIds = currIds;
128
129
                        //We don't create a local cache of the sampleSize, becuase it changes with calls
130
                        if(currIds.size() == 0 && listener->sampleSize() < 10)
131
                        {
132
                                listener->clearSample();
133
                                return; //Had nothing, have nothing worth checking, nothing to do.
134
                        }
135
136
                        if(!listener->isCurrentlyParameterized()) //If the gesture is currently being parameterized, classification temporarily ceases.
137
                        {
138
                                segmentAndClassify(fingersRaised);
139
                        }
140
                }
141
                else if (strcmp(param, "fseq") == 0)
142
                {
143
                        if (!outStream->IsBundleInProgress())
144
                                *outStream << osc::BeginBundleImmediate;
145
146
                        *outStream << osc::BeginMessage("/tuio/2Dcur") << "fseq" << (arg++)->AsInt32() << osc::EndMessage;
147
                        *outStream << osc::EndBundle;
148
                        if (!gestrSampleStart && liveFrame.size() > 0)
149
                        {
150
                                listener->updateFrame(liveFrame);
151
                                if(listener->isCurrentlyParameterized())
152
                                        sendGestrParams(listener->parameterize());
153
                                liveFrame.clear();
154
                        }
155
                        sendStream();
156
                }
157
158
        }
159
160
        void segmentAndClassify(bool fingersRaised)
161
        {
162
                bool currSegmentIsNowStatic = false;
163
164
                if(listener->sampleSize() > 10)                         //Don't check if only 10 frames are collected
165
                {
166
                        if (listener->sampleIsNowStatic())                 //Check to see if sample has stopped moving
167
                        {
168
                                if(listener->sampleIsOnlyStatic())         //Entire sample hasn't moved.
169
                                        listener->startSample("");                 //Restart collection of segment
170
                                else         //Delimiter found. Sample is valid if non-static portion of gesture is > 10 frames
171
                                {
172
                                        currSegmentIsNowStatic = listener->sampleSize() > 10;
173
                                }
174
                        }
175
                        //Two delimiters. currSegmentIsNowStatic or fingersRaised
176
                        if (currSegmentIsNowStatic || (fingersRaised && listener->sampleSize() > 10))
177
                        {
178
                                cout << "Valid Segment with size: " << listener->sampleSize() << endl;
179
180
                                //Segment should be classified
181
                                listener->endSample();
182
                                outStream->Clear();
183
                                const char* gestrAction = "classify";
184
                                vector<string> actionResult = listener->gestureAction(gestrAction, vector<string>());
185
                                if (actionResult.size() > 2) //If the recognition is not "None"
186
                                {
187
                                        sendGestrActionResults(gestrAction, actionResult);
188
                                }
189
                                listener->startSample(""); //Allow a new segment to begin.
190
                        }
191
                }
192
        }
193
        void ProcessMessage(const osc::ReceivedMessage & m,
194
                        const IpEndpointName & remoteEndpoint)
195
        {
196
                try
197
                {
198
                        osc::ReceivedMessageArgumentIterator arg = m.ArgumentsBegin();
199
                        if (strcmp(m.AddressPattern(), "/gestr/sample") == 0)
200
                        {
201
                                handleGestrSample(arg, m);
202
                        }
203
                        else if (strcmp(m.AddressPattern(), "/gestr/action") == 0)
204
                        {
205
                                handleGestrAction(arg, m);
206
                        }
207
                        else if (strcmp(m.AddressPattern(), "/tuio/2Dcur") == 0)
208
                        {
209
                                handleTUIO(arg, m);
210
                        }
211
                } catch (osc::Exception& e)
212
                {
213
                        cout << "error while parsing message: " << m.AddressPattern()
214
                                        << ": " << e.what() << endl;
215
                }
216
        }
217
218
private:
219
        typedef map<string, vector<double> > paramValMapT;
220
        void initOutStream()
221
        {
222
                outStream = new osc::OutboundPacketStream(buffer, OUTPUT_BUFFER_SIZE);
223
        }
224
225
        void sendStream()
226
        {
227
                UdpTransmitSocket socket = UdpTransmitSocket(IpEndpointName(ADDRESS,
228
                                OUTPUT_PORT));
229
                socket.Send(outStream->Data(), outStream->Size());
230
                outStream->Clear();
231
        }
232
233
        bool isFingerLowered(vector<int> & currIds)
234
        {
235
                bool fingerLowered = false;
236
                for (size_t i = 0; i < currIds.size(); i++)
237
                        if (find(liveIds.begin(), liveIds.end(), currIds[i]) == liveIds.end())
238
                                fingerLowered = true;
239
                return fingerLowered;
240
        }
241
        bool isFingerRaised(vector<int> & currIds)
242
        {
243
                bool fingerRaised = false;
244
                for (size_t i = 0; i < liveIds.size(); i++)
245
                        if (find(currIds.begin(), currIds.end(), liveIds[i]) == currIds.end())
246
                                fingerRaised = true;
247
                return fingerRaised;
248
        }
249
        void cloneContactToOutStream(Contact & contact)
250
        {
251
                if (!outStream->IsBundleInProgress())
252
                        *outStream << osc::BeginBundleImmediate;
253
                *outStream << osc::BeginMessage("/tuio/2Dcur") << "set";
254
                *outStream << contact.id << contact.x << contact.y << contact.dx
255
                                << contact.dy << 0.0 << contact.width << contact.height;
256
                *outStream << osc::EndMessage;
257
        }
258
259
        Contact createContactFromOscArgs(
260
                        osc::ReceivedMessageArgumentIterator & arg,
261
                        const osc::ReceivedMessage & m)
262
        {
263
                long int numArgs = m.ArgumentCount();
264
                Contact contact;
265
                if(numArgs == 9) //Most probably from CCV (including the 'set' message)
266
                {
267
                        contact.id = (arg++)->AsInt32();
268
                        contact.x = (arg++)->AsFloat();
269
                        contact.y = (arg++)->AsFloat();
270
                        contact.dx = (arg++)->AsFloat();
271
                        contact.dy = (arg++)->AsFloat();
272
                        arg++;
273
                        contact.width = (arg++)->AsFloat();
274
                        contact.height = (arg++)->AsFloat();
275
                        contact.pressure = 0;
276
                }
277
                else if(numArgs == 7) //From TUIO Simulator (Profile: /tuio/2Dcur set s x y X Y m)
278
                {
279
                        contact.id = (arg++)->AsInt32();
280
                        contact.x = (arg++)->AsFloat();
281
                        contact.y = (arg++)->AsFloat();
282
                        contact.dx = (arg++)->AsFloat();
283
                        contact.dy = (arg++)->AsFloat();
284
                        arg++; //We don't really use motion acceleration ... yet.
285
                }
286
287
                if (arg != m.ArgumentsEnd())
288
                        throw osc::ExcessArgumentException();
289
                return contact;
290
        }
291
        vector<int> getCurrIdsAndSendToOutStream(osc::ReceivedMessageArgumentIterator arg,
292
                        const osc::ReceivedMessage & m)
293
        {
294
                if (!outStream->IsBundleInProgress()
295
                                && !outStream->IsMessageInProgress())
296
                        *outStream << osc::BeginBundleImmediate;
297
298
                *outStream << osc::BeginMessage("/tuio/2Dcur") << "alive";
299
                vector<int> currIds;
300
                while (arg != m.ArgumentsEnd())
301
                {
302
                        int id = (arg++)->AsInt32();
303
                        *outStream << id;
304
                        currIds.push_back(id);
305
                }
306
                *outStream << osc::EndMessage;
307
                return currIds;
308
        }
309
310
        /**
311
         * Generic method for any Gestr Action
312
         */
313
        void sendGestrActionResults(const char *actionString,
314
                        vector<string> actionResult)
315
        {
316
                outStream->Clear();
317
                if (!outStream->IsBundleInProgress())
318
                        *outStream << osc::BeginBundleImmediate;
319
320
                *outStream << osc::BeginMessage("/gestr/action");
321
                cout << "Action performed: " << actionString << "\n\tResult: ";
322
                for (size_t i = 0; i < actionResult.size(); i++)
323
                {
324
                        *outStream << actionResult[i].c_str();
325
                        cout << actionResult[i] << ", ";
326
                }
327
                *outStream << osc::EndMessage;
328
                cout << endl;
329
                sendStream();
330
        }
331
        void sendGestrParams(paramValMapT namedParams)
332
        {
333
                if (!outStream->IsBundleInProgress())
334
                        *outStream << osc::BeginBundleImmediate;
335
336
                BOOST_FOREACH(paramValMapT::value_type &namedParamValPair, namedParams)
337
                {
338
                        *outStream << osc::BeginMessage("/gestr/action");
339
                        *outStream << "param_update";
340
                        const string &name =  namedParamValPair.first;
341
                        *outStream << name.c_str();
342
                        BOOST_FOREACH(double paramVal, namedParamValPair.second)
343
                        {
344
                                *outStream << paramVal;
345
                        }
346
                        *outStream << osc::EndMessage;
347
                }
348
                sendStream();
349
        }
350
351
352
};
353
354
void initMultitouchOscReceiver(GestureCollector *collector)
355
{
356
        OscHandler oscListener;
357
        UdpListeningReceiveSocket s(IpEndpointName(IpEndpointName::ANY_ADDRESS,
358
                        IN_PORT), &oscListener);
359
360
        cout << "Now Listening for input on port " << IN_PORT << "..." << endl;
361
362
        cout << "Output packets to port: " << OUTPUT_PORT << endl;
363
364
        oscListener.listener = collector;
365
        oscListener.inSock = &s;
366
        s.RunUntilSigInt();
367
        cout << "Done listening to OSC.\n";
368
369
}
370
371
#endif /* MULTITOUCHOSCRECEIVER_H_ */