17 #include <sys/socket.h>
18 #include <netinet/in.h>
20 #include <oscpack/osc/OscOutboundPacketStream.h>
21 #include <oscpack/osc/OscPacketListener.h>
22 #include <oscpack/ip/UdpSocket.h>
23 #include <CoreServices/CoreServices.h>
25 #pragma clang diagnostic push
26 #pragma clang diagnostic ignored "-Wdocumentation"
27 #include <json-c/json.h>
28 #pragma clang diagnostic pop
41 "VuoList_VuoOscMessage",
42 "CoreServices.framework",
97 std::set<VuoOscReceivedMessageTrigger>
triggers;
103 virtual void ProcessBundle(
const osc::ReceivedBundle& b,
const IpEndpointName& remoteEndpoint)
107 for (osc::ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i)
125 virtual void ProcessMessage(
const osc::ReceivedMessage &m,
const IpEndpointName &remoteEndpoint)
136 for (osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin(); arg != m.ArgumentsEnd(); ++arg, ++i)
138 switch (arg->TypeTag())
140 case osc::NIL_TYPE_TAG:
142 dataTypes[i] = VuoOscType_Auto;
144 case osc::TRUE_TYPE_TAG:
145 data[i] = json_object_new_boolean(
true);
146 dataTypes[i] = VuoOscType_Auto;
148 case osc::FALSE_TYPE_TAG:
149 data[i] = json_object_new_boolean(
false);
150 dataTypes[i] = VuoOscType_Auto;
152 case osc::FLOAT_TYPE_TAG:
153 data[i] = json_object_new_double(arg->AsFloat());
154 dataTypes[i] = VuoOscType_Float32;
156 case osc::DOUBLE_TYPE_TAG:
157 data[i] = json_object_new_double(arg->AsDouble());
158 dataTypes[i] = VuoOscType_Auto;
160 case osc::INT32_TYPE_TAG:
161 data[i] = json_object_new_int(arg->AsInt32());
162 dataTypes[i] = VuoOscType_Int32;
164 case osc::INT64_TYPE_TAG:
165 data[i] = json_object_new_int64(arg->AsInt64());
166 dataTypes[i] = VuoOscType_Auto;
168 case osc::STRING_TYPE_TAG:
169 data[i] = json_object_new_string(arg->AsString());
170 dataTypes[i] = VuoOscType_Auto;
173 throw osc::Exception(((std::string)
"unknown argument type tag '" + arg->TypeTag() +
"'").c_str());
181 for (std::set<VuoOscReceivedMessageTrigger>::iterator it =
triggers.begin(); it !=
triggers.end(); ++it)
185 catch (osc::Exception &e)
187 VUserLog(
"Error parsing message: %s: %s", m.AddressPattern(), e.what());
205 bool defaultName =
false;
208 name =
VuoText_format(
"Vuo OSC %s", isServer ?
"Server" :
"Client");
212 CFStringRef nameCF = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
218 CFNetServiceRef netService = CFNetServiceCreate(NULL, CFSTR(
""), CFSTR(
"_osc._udp"), nameCF, port);
223 CFStringRef keys[] = { CFSTR(
"type") };
224 CFTypeRef values[] = { isServer ? CFSTR(
"server") : CFSTR(
"client") };
225 CFDictionaryRef attr = CFDictionaryCreate(NULL, (
const void **)&keys, (
const void **)&values,
sizeof(keys) /
sizeof(keys[0]), NULL, NULL);
226 CFDataRef txtRecord = CFNetServiceCreateTXTDataWithDictionary( NULL, attr );
229 CFNetServiceSetTXTData(netService, txtRecord);
231 CFRelease(txtRecord);
235 CFNetServiceClientContext clientContext = { 0, NULL, NULL, NULL, NULL };
237 CFNetServiceScheduleWithRunLoop(netService, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
239 if (CFNetServiceRegisterWithOptions(netService, kCFNetServiceFlagNoAutoRename, &error) ==
false)
241 CFNetServiceUnscheduleFromRunLoop(netService, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
242 CFNetServiceSetClient(netService, NULL, NULL);
243 CFNetServiceCancel(netService);
244 CFRelease(netService);
245 VUserLog(
"Error: Could not advertise OSC %s via Bonjour (domain=%ld, error=%d)", isServer ?
"server" :
"client", error.domain, error.error);
257 CFNetServiceUnscheduleFromRunLoop(netService, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
258 CFNetServiceSetClient(netService, NULL, NULL);
259 CFNetServiceCancel(netService);
260 CFRelease(netService);
269 SocketReceiveMultiplexer mux_;
271 CFNetServiceRef netService;
273 bool stopping =
false;
274 dispatch_queue_t queue;
289 catch (osc::MalformedPacketException e)
291 VUserLog(
"Malformed OSC packet: %s", e.what());
293 catch (osc::MalformedBundleException e)
295 VUserLog(
"Malformed OSC bundle: %s", e.what());
297 catch (osc::MalformedMessageException e)
299 VUserLog(
"Malformed OSC message: %s", e.what());
301 catch (osc::WrongArgumentTypeException e)
303 VUserLog(
"OSC: Wrong argument type: %s", e.what());
305 catch (osc::MissingArgumentException e)
307 VUserLog(
"OSC: Missing argument: %s", e.what());
309 catch (osc::ExcessArgumentException e)
311 VUserLog(
"OSC: Excess argument: %s", e.what());
313 catch (std::runtime_error &e)
315 VUserLog(
"OSC runtime error: %s", e.what());
317 catch (std::exception &e)
319 VUserLog(
"OSC exception: %s", e.what());
341 catch(std::exception
const &e)
343 VUserLog(
"Error: (port %d) %s", localEndpoint.port, e.what());
347 mux_.AttachSocketListener(
this, listener_);
351 queue = dispatch_queue_create(
"org.vuo.osc.receive", NULL);
353 dispatch_async(queue, ^{
398 mux_.AsynchronousBreak();
399 mux_.DetachSocketListener(
this, listener_);
401 dispatch_sync(queue, ^{});
402 dispatch_release(queue);
415 __attribute__((constructor))
static void VuoOscIn_init(
void)
451 IpEndpointName endpoint(IpEndpointName::ANY_ADDRESS, oii->
device.port==0 ? IpEndpointName::ANY_PORT : oii->
device.port);
525 std::map<unsigned int, VuoOscInSocket *>::iterator it =
VuoOscInPool.find(oii->
device.port);
566 typedef struct _VuoOscOut_internal
569 std::vector<UdpTransmitSocket *> sockets;
570 std::vector<CFNetServiceRef> netServices;
571 dispatch_queue_t queue;
579 int socketFD = socket(PF_INET, SOCK_DGRAM, 0);
582 VUserLog(
"Couldn't open port: %s", strerror(errno));
586 struct sockaddr_in addr;
587 memset(&addr, 0,
sizeof(addr));
588 addr.sin_family = PF_INET;
589 addr.sin_addr.s_addr = INADDR_ANY;
591 if (bind(socketFD, (
struct sockaddr *)&addr,
sizeof(addr)) == -1)
593 VUserLog(
"Couldn't bind: %s", strerror(errno));
598 struct sockaddr_in sin;
599 socklen_t len =
sizeof(sin);
600 if (getsockname(socketFD, (
struct sockaddr *)&sin, &len) == -1)
602 VUserLog(
"Couldn't get socket name: %s", strerror(errno));
609 return ntohs(sin.sin_port);
628 std::vector<IpEndpointName *> endpoints;
629 if (device.
device.ipAddress)
630 endpoints.push_back(
new IpEndpointName(device.
device.ipAddress, actualPort));
636 struct ifaddrs *interfaces;
637 if (getifaddrs(&interfaces))
639 VUserLog(
"Using link-local broadcast, since I couldn't get a list of host interfaces: %s", strerror(errno));
640 endpoints.push_back(
new IpEndpointName(
"255.255.255.255", actualPort));
644 for (
struct ifaddrs *address = interfaces; address; address = address->ifa_next)
647 if (address->ifa_addr->sa_family != AF_INET)
650 struct sockaddr_in *ip = (
struct sockaddr_in *)address->ifa_dstaddr;
651 endpoints.push_back(
new IpEndpointName(ntohl(ip->sin_addr.s_addr), actualPort));
653 freeifaddrs(interfaces);
658 std::vector<UdpTransmitSocket *> sockets;
659 std::vector<CFNetServiceRef> netServices;
660 for (std::vector<IpEndpointName *>::iterator endpoint = endpoints.begin(); endpoint != endpoints.end(); ++endpoint)
666 char s[IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH];
667 (*endpoint)->AddressAndPortAsString(s);
670 UdpTransmitSocket *socket =
new UdpTransmitSocket(**endpoint);
671 socket->SetEnableBroadcast(
true);
672 sockets.push_back(socket);
676 catch (std::exception
const &e)
678 char s[IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH];
679 (*endpoint)->AddressAndPortAsString(s);
680 VUserLog(
"Error: %s %s", s, e.what());
691 ai->netServices = netServices;
693 ai->device = device.
device;
696 ai->sockets = sockets;
698 ai->queue = dispatch_queue_create(
"org.vuo.osc.send", NULL);
704 for (std::vector<CFNetServiceRef>::iterator netService = ai->netServices.begin(); netService != ai->netServices.end(); ++netService)
707 for (std::vector<UdpTransmitSocket *>::iterator socket = ai->sockets.begin(); socket != ai->sockets.end(); ++socket)
710 VuoOscOut_internalPool->removeSharedInstance(ai->device);
714 dispatch_sync(ai->queue, ^{});
715 dispatch_release(ai->queue);
727 return (
VuoOscOut)VuoOscOut_internalPool->getSharedInstance(device);
735 if (!ao || !messages)
740 dispatch_async(aii->queue, ^{
742 int bufferSize = 256;
745 char *buffer = (char *)malloc(bufferSize);
748 osc::OutboundPacketStream p(buffer, bufferSize);
750 VuoInteger messageCount = VuoListGetCount_VuoOscMessage(messages);
752 if (messageCount > 1)
753 p << osc::BeginBundleImmediate;
755 for(VuoInteger i = 1; i <= VuoListGetCount_VuoOscMessage(messages); ++i)
757 VuoOscMessage message = VuoListGetValue_VuoOscMessage(messages, i);
761 p << osc::BeginMessage(message->address);
763 for (int i = 0; i < message->dataCount; ++i)
765 if (message->dataTypes[i] == VuoOscType_Auto)
767 json_object *datum = message->data[i];
769 json_type type = json_object_get_type(datum);
771 if (type == json_type_null)
773 else if (type == json_type_boolean)
774 p << (bool)json_object_get_boolean(datum);
775 else if (type == json_type_double)
776 p << json_object_get_double(datum);
777 else if (type == json_type_int)
778 p << (osc::int64)json_object_get_int64(datum);
779 else if (type == json_type_string)
780 p << json_object_get_string(datum);
783 VUserLog(
"Error: Unknown type: %s", json_type_to_name(type));
787 else if (message->dataTypes[i] == VuoOscType_Int32)
788 p << (osc::int32)json_object_get_int(message->data[i]);
789 else if (message->dataTypes[i] == VuoOscType_Float32)
790 p << (float)json_object_get_double(message->data[i]);
793 VUserLog(
"Error: Unknown type: %d", message->dataTypes[i]);
798 p << osc::EndMessage;
801 if (messageCount > 1)
804 for (std::vector<UdpTransmitSocket *>::iterator socket = aii->sockets.begin(); socket != aii->sockets.end(); ++socket)
805 (*socket)->Send(p.Data(), p.Size());
808 catch (osc::OutOfBufferMemoryException const &)
812 catch (std::exception const &e)
814 VUserLog(
"Error: %s", e.what());