/// <summary>
        /// Send an announcement message, and schedule the next such message.
        /// </summary>
        /// <remarks>
        /// After constructing a Peer, generally one calls Announce() just once
        /// to start the perpetual cycle of announcements that each Peer makes.
        /// </remarks>
        public void Announce(bool isHostingAudio = false)
        {
            logger?.WriteNet(NetLogLevel.Trace, $"DistributedHost.Announce()");

            AnnounceMessage message = new AnnounceMessage
            {
                AnnouncerSocketAddress  = SocketAddress,
                AnnouncerIsHostingAudio = isHostingAudio,
                KnownPeers = netManager
                             .ConnectedPeerList
                             .Select(peer => new SerializedSocketAddress(peer.EndPoint.Serialize()))
                             .ToArray()
            };

            SendBroadcastMessage(message);

            // schedule next announcement
            workQueue.RunLater(() => Announce(isHostingAudio), AnnounceDelayMsec);
        }
        /// <summary>
        /// An announcement has been received (via broadcast); react accordingly.
        /// </summary>
        private void OnAnnounceReceived(AnnounceMessage message, IPEndPoint endpoint)
        {
            // heed only ipv4 for now... TBD what to do about this
            if (endpoint.AddressFamily == AddressFamily.InterNetwork)
            {
                // is this actually our own announcement!?
                SerializedSocketAddress incomingAddress = new SerializedSocketAddress(endpoint.Serialize());
                if (incomingAddress == this.SocketAddress)
                {
                    // ignore this, we're talking to ourselves
                    return;
                }

                PeerAnnounceCount++;

                // do we know this peer already?
                // (could happen in race scenario)
                if (netManager.ConnectedPeerList.Any(peer => peer.EndPoint.Equals(endpoint)))
                {
                    return;
                }

                // did we already respond to this peer?
                if (AnnouncedEndPoints.Contains(endpoint))
                {
                    return;
                }

                // did this peer know us already? (typical scenario given re-announcements)
                if (message.KnownPeers.Contains(SocketAddress))
                {
                    return;
                }

                logger?.WriteNet(NetLogLevel.Trace, $"DistributedHost.OnAnnounceReceived({endpoint}) -- responding. {ConnectionsStatusString()}]");

                // send announce response
                AnnounceResponseMessage response = new AnnounceResponseMessage {
                };
                SendUnconnectedMessage(response, endpoint);
            }
        }