Vuo 2.4.4
Loading...
Searching...
No Matches
VuoSyphonListener.m
Go to the documentation of this file.
1
10#import "VuoSyphon.h"
11#import "VuoSyphonListener.h"
12#include "VuoImageRenderer.h"
13#include <OpenGL/OpenGL.h>
14#include <OpenGL/CGLMacro.h>
15#include "VuoGlContext.h"
16
17#ifdef VUO_COMPILER
19 "title" : "VuoSyphonListener",
20 "dependencies" : [
21 "VuoSyphonServerNotifier",
22 "AppKit.framework",
23 "VuoGlContext"
24 ]
25 });
26#endif
27
28#include <pthread.h>
29static pthread_t VuoSyphonListener_mainThread = NULL;
30
34static void __attribute__((constructor)) VuoSyphonListener_init()
35{
36 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
37 VUOLOG_PROFILE_BEGIN(mainQueue);
38 dispatch_sync(dispatch_get_main_queue(), ^{
39 VUOLOG_PROFILE_END(mainQueue);
40 VuoSyphonListener_mainThread = pthread_self();
41 });
42 });
43}
44
49{
50 return VuoSyphonListener_mainThread == pthread_self();
51}
52
53
58{
59 SyphonImage *frame = (SyphonImage *)image->freeCallbackContext;
60 [frame release];
61}
62
63@implementation VuoSyphonListener
64
65@synthesize syphonClient;
66
70-(id) init
71{
72 if (self = [super init])
73 {
74 // Wait for VuoSyphonListener_init() to complete.
75 VUOLOG_PROFILE_BEGIN(mainQueue);
76 dispatch_sync(dispatch_get_main_queue(), ^{
77 VUOLOG_PROFILE_END(mainQueue);
78 });
79
80 callback = NULL;
81 serverNotifier = NULL;
84 refreshQueue = dispatch_queue_create("vuo.syphon.VuoSyphonListener", 0);
85 }
86 return self;
87}
88
92-(void) startListeningWithServerDescription:(VuoSyphonServerDescription)description callback:(void(*)(VuoImage))receivedFrame
93{
94 dispatch_sync(refreshQueue, ^{
95
98 desiredServer = description;
99
100 callback = receivedFrame;
101
103 VuoRetain(allServerDescriptions);
104 [self refreshSyphonClientThreadUnsafe:allServerDescriptions];
105 VuoRelease(allServerDescriptions);
106
107 if (!serverNotifier)
108 {
111 VuoSyphonServerNotifier_setNotificationMethod(serverNotifier, self, @selector(refreshSyphonClient:));
113 }
114 });
115}
116
122-(void) refreshSyphonClientThreadUnsafe:(VuoList_VuoSyphonServerDescription)serverDescriptions
123{
124 if (syphonClient)
125 {
126 // Already connected to a server — make sure it's still desired and available.
127
128 __block NSDictionary *currentDict;
130 currentDict = [[syphonClient serverDescription] retain];
131 else
132 {
133 VUOLOG_PROFILE_BEGIN(mainQueue);
134 dispatch_sync(dispatch_get_main_queue(), ^{
135 VUOLOG_PROFILE_END(mainQueue);
136 currentDict = [[syphonClient serverDescription] retain];
137 });
138 }
139
140 bool isCurrentStillDesired;
141 {
142 VuoText currentName = VuoText_make([[currentDict objectForKey:SyphonServerDescriptionUUIDKey] UTF8String]);
143 VuoText currentAppName = VuoText_make([[currentDict objectForKey:SyphonServerDescriptionUUIDKey] UTF8String]);
144 VuoSyphonServerDescription current = VuoSyphonServerDescription_make(VuoText_make("*"), currentName, currentAppName, true);
146 VuoListAppendValue_VuoSyphonServerDescription(currentAsList, current);
148 isCurrentStillDesired = (VuoListGetCount_VuoSyphonServerDescription(currentMatchingDesired) > 0);
149 }
150
151 bool isCurrentStillAvailable;
152 {
153 VuoText currentUUID = VuoText_make([[currentDict objectForKey:SyphonServerDescriptionUUIDKey] UTF8String]);
155 VuoList_VuoSyphonServerDescription availableMatchingCurrent = VuoSyphon_filterServerDescriptions(serverDescriptions, current);
156 isCurrentStillAvailable = (VuoListGetCount_VuoSyphonServerDescription(availableMatchingCurrent) > 0);
157 }
158 [currentDict release];
159
160 if (isCurrentStillDesired && isCurrentStillAvailable)
161 {
162 return;
163 }
164 else
165 {
167 [syphonClient stop];
168 else
169 {
170 VUOLOG_PROFILE_BEGIN(mainQueue);
171 dispatch_sync(dispatch_get_main_queue(), ^{
172 VUOLOG_PROFILE_END(mainQueue);
173 [syphonClient stop];
174 });
175 }
176 self.syphonClient = nil;
177 }
178 }
179
180 // Not connected to a server — see if a desired one is available.
181
183 VuoRetain(matchingServers);
184
185 if (VuoListGetCount_VuoSyphonServerDescription(matchingServers) == 0)
186 {
187 // No desired server is available.
189 [syphonClient stop];
190 else
191 {
192 VUOLOG_PROFILE_BEGIN(mainQueue);
193 dispatch_sync(dispatch_get_main_queue(), ^{
194 VUOLOG_PROFILE_END(mainQueue);
195 [syphonClient stop];
196 });
197 }
198 self.syphonClient = nil;
199 VuoRelease(matchingServers);
200 return;
201 }
202
204 VuoRelease(matchingServers);
205
206 // Look up the official server description. (SyphonClient won't accept one constructed from chosenServer's fields.)
207 NSDictionary *chosenServerDict = nil;
208 NSString *chosenUUID = [NSString stringWithUTF8String:chosenServer.serverUUID];
209 NSArray *allServerDicts = [[SyphonServerDirectory sharedDirectory] servers];
210 for (NSDictionary *serverDict in allServerDicts)
211 {
212 if ([chosenUUID isEqualToString:[serverDict objectForKey:SyphonServerDescriptionUUIDKey]])
213 {
214 chosenServerDict = serverDict;
215 break;
216 }
217 }
218
219 // Connect the client to the server.
220 void (^connect)(void) = ^{
221 __block SyphonClient *s;
222 VuoGlContext_perform(^(CGLContextObj cgl_ctx){
223 s = [[SyphonClient alloc] initWithServerDescription:chosenServerDict context:cgl_ctx options:nil newFrameHandler:^(SyphonClient *client) {
224 SyphonImage *frame = [client newFrameImage];
225
226 if (frame.textureSize.width < 1 || frame.textureSize.height < 1)
227 {
228 [frame release];
229 return;
230 }
231
232 VuoImage image = VuoImage_makeClientOwnedGlTextureRectangle(frame.textureName, GL_RGBA, frame.textureSize.width, frame.textureSize.height, VuoSyphonListener_freeSyphonImageCallback, frame);
233 VuoRetain(image);
234 callback(VuoImage_makeCopy(image, false, 0, 0, false));
235 VuoRelease(image);
236
237 }];
238 });
239 self.syphonClient = s;
240 [s release];
241 };
243 connect();
244 else
245 {
246 VUOLOG_PROFILE_BEGIN(mainQueue);
247 dispatch_sync(dispatch_get_main_queue(), ^{
248 VUOLOG_PROFILE_END(mainQueue);
249 connect();
250 });
251 }
252}
253
257-(void) refreshSyphonClient:(VuoList_VuoSyphonServerDescription)serverDescriptions
258{
259 dispatch_async(refreshQueue, ^{
260 [self refreshSyphonClientThreadUnsafe:serverDescriptions];
261 });
262}
263
267-(void) stopListening
268{
269 dispatch_sync(refreshQueue, ^{
270
273 serverNotifier = NULL;
274
275 VUOLOG_PROFILE_BEGIN(mainQueue);
276 dispatch_sync(dispatch_get_main_queue(), ^{
277 VUOLOG_PROFILE_END(mainQueue);
278 [syphonClient stop];
279 });
280 self.syphonClient = nil;
281 });
282}
283
284-(void) dealloc
285{
287 dispatch_release(refreshQueue);
288 [super dealloc];
289}
290
291@end