summaryrefslogtreecommitdiffstats
path: root/src/server/Broadcaster.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/Broadcaster.hpp')
-rw-r--r--src/server/Broadcaster.hpp118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/server/Broadcaster.hpp b/src/server/Broadcaster.hpp
new file mode 100644
index 00000000..1d5dd16e
--- /dev/null
+++ b/src/server/Broadcaster.hpp
@@ -0,0 +1,118 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2016 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_ENGINE_BROADCASTER_HPP
+#define INGEN_ENGINE_BROADCASTER_HPP
+
+#include <atomic>
+#include <list>
+#include <mutex>
+#include <set>
+#include <string>
+
+#include "ingen/Interface.hpp"
+#include "ingen/types.hpp"
+
+#include "BlockFactory.hpp"
+
+namespace ingen {
+namespace server {
+
+/** Broadcaster for all clients.
+ *
+ * This is an Interface that forwards all messages to all registered
+ * clients (for updating all clients on state changes in the engine).
+ *
+ * \ingroup engine
+ */
+class Broadcaster : public Interface
+{
+public:
+ Broadcaster();
+ ~Broadcaster();
+
+ void register_client(SPtr<Interface> client);
+ bool unregister_client(SPtr<Interface> client);
+
+ void set_broadcast(SPtr<Interface> client, bool broadcast);
+
+ /** Ignore a client when broadcasting.
+ *
+ * This is used to prevent feeding back updates to the client that
+ * initiated a property set in the first place.
+ */
+ void set_ignore_client(SPtr<Interface> client) { _ignore_client = client; }
+ void clear_ignore_client() { _ignore_client.reset(); }
+
+ /** Return true iff there are any clients with broadcasting enabled.
+ *
+ * This is used in the audio thread to decide whether or not notifications
+ * should be calculated and emitted.
+ */
+ bool must_broadcast() const { return _must_broadcast; }
+
+ /** A handle that represents a transfer of possibly several changes.
+ *
+ * This object going out of scope signifies the transfer is completed.
+ * This makes doing the right thing in recursive functions that send
+ * updates simple (e.g. Event::post_process()).
+ */
+ class Transfer : public Raul::Noncopyable {
+ public:
+ explicit Transfer(Broadcaster& b) : broadcaster(b) {
+ if (++broadcaster._bundle_depth == 1) {
+ broadcaster.bundle_begin();
+ }
+ }
+ ~Transfer() {
+ if (--broadcaster._bundle_depth == 0) {
+ broadcaster.bundle_end();
+ }
+ }
+ Broadcaster& broadcaster;
+ };
+
+ void send_plugins(const BlockFactory::Plugins& plugins);
+ void send_plugins_to(Interface*, const BlockFactory::Plugins& plugins);
+
+ void message(const Message& msg) override {
+ std::lock_guard<std::mutex> lock(_clients_mutex);
+ for (const auto& c : _clients) {
+ if (c != _ignore_client) {
+ c->message(msg);
+ }
+ }
+ }
+
+ URI uri() const override { return URI("ingen:/broadcaster"); }
+
+private:
+ friend class Transfer;
+
+ typedef std::set<SPtr<Interface>> Clients;
+
+ std::mutex _clients_mutex;
+ Clients _clients;
+ std::set< SPtr<Interface> > _broadcastees;
+ std::atomic<bool> _must_broadcast;
+ unsigned _bundle_depth;
+ SPtr<Interface> _ignore_client;
+};
+
+} // namespace server
+} // namespace ingen
+
+#endif // INGEN_ENGINE_BROADCASTER_HPP