27 extern void acquireMulticastLock();
28 extern void releaseMulticastLock();
32 const String& serviceDescription,
33 int broadcastPortToUse,
int connectionPort,
35 :
Thread (
"Discovery_broadcast"),
36 message (serviceTypeUID), broadcastPort (broadcastPortToUse),
37 minInterval (minTimeBetweenBroadcasts)
53void NetworkServiceDiscovery::Advertiser::run()
55 if (! socket.bindToPort (0))
61 while (! threadShouldExit())
64 wait ((
int) minInterval.inMilliseconds());
68void NetworkServiceDiscovery::Advertiser::sendBroadcast()
70 static IPAddress local = IPAddress::local();
77 message.setAttribute (
"address", address.toString());
80 auto data = message.toString (XmlElement::TextFormat().singleLine().withoutHeader());
82 socket.write (broadcastAddress.toString(), broadcastPort, data.toRawUTF8(), (
int) data.getNumBytesAsUTF8());
88 :
Thread (
"Discovery_listen"), serviceTypeUID (serviceType)
91 acquireMulticastLock();
104 releaseMulticastLock();
108void NetworkServiceDiscovery::AvailableServiceList::run()
110 while (! threadShouldExit())
112 if (socket.waitUntilReady (
true, 200) == 1)
115 auto bytesRead = socket.read (buffer,
sizeof (buffer) - 1,
false);
120 if (xml->hasTagName (serviceTypeUID))
121 handleMessage (*xml);
124 removeTimedOutServices();
131 auto listCopy = services;
135void NetworkServiceDiscovery::AvailableServiceList::handleAsyncUpdate()
137 NullCheckedInvocation::invoke (onChange);
140void NetworkServiceDiscovery::AvailableServiceList::handleMessage (
const XmlElement& xml)
145 if (service.instanceID.trim().isNotEmpty())
152 handleMessage (service);
156static void sortServiceList (std::vector<NetworkServiceDiscovery::Service>& services)
158 auto compareServices = [] (
const NetworkServiceDiscovery::Service& s1,
159 const NetworkServiceDiscovery::Service& s2)
161 return s1.instanceID < s2.instanceID;
164 std::sort (services.begin(), services.end(), compareServices);
167void NetworkServiceDiscovery::AvailableServiceList::handleMessage (
const Service& service)
169 const ScopedLock sl (listLock);
171 for (
auto& s : services)
173 if (s.instanceID == service.instanceID)
175 if (s.description != service.description
176 || s.address != service.address
177 || s.port != service.port)
180 triggerAsyncUpdate();
183 s.lastSeen = service.lastSeen;
188 services.push_back (service);
189 sortServiceList (services);
190 triggerAsyncUpdate();
193void NetworkServiceDiscovery::AvailableServiceList::removeTimedOutServices()
195 const double timeoutSeconds = 5.0;
198 const ScopedLock sl (listLock);
200 auto oldEnd = std::end (services);
201 auto newEnd = std::remove_if (std::begin (services), oldEnd,
202 [=] (
const Service& s) {
return s.lastSeen < oldestAllowedTime; });
204 if (newEnd != oldEnd)
206 services.erase (newEnd, oldEnd);
207 triggerAsyncUpdate();
bool bindToPort(int localPortNumber)
static Array< IPAddress > getAllAddresses(bool includeIPv6=false)
static IPAddress getInterfaceBroadcastAddress(const IPAddress &interfaceAddress)
static RelativeTime seconds(double seconds) noexcept
static Time JUCE_CALLTYPE getCurrentTime() noexcept
int getIntAttribute(StringRef attributeName, int defaultReturnValue=0) const
const String & getStringAttribute(StringRef attributeName) const noexcept
void setAttribute(const Identifier &attributeName, const String &newValue)
Advertiser(const String &serviceTypeUID, const String &serviceDescription, int broadcastPort, int connectionPort, RelativeTime minTimeBetweenBroadcasts=RelativeTime::seconds(1.5))
AvailableServiceList(const String &serviceTypeUID, int broadcastPort)
~AvailableServiceList() override
std::vector< Service > getServices() const