/*
This file is part of Ingen.
Copyright 2007-2016 David Robillard
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 .
*/
#ifndef INGEN_ENGINE_BROADCASTER_HPP
#define INGEN_ENGINE_BROADCASTER_HPP
#include
#include
#include
#include
#include
#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 client);
bool unregister_client(SPtr client);
void set_broadcast(SPtr 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 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& plugin_list);
void send_plugins_to(Interface*, const BlockFactory::Plugins& plugin_list);
#define BROADCAST(msg, ...) \
std::lock_guard lock(_clients_mutex); \
for (const auto& c : _clients) { \
if (c != _ignore_client) { \
c->msg(__VA_ARGS__); \
} \
} \
void bundle_begin() { BROADCAST(bundle_begin); }
void bundle_end() { BROADCAST(bundle_end); }
void put(const Raul::URI& uri,
const Properties& properties,
Resource::Graph ctx = Resource::Graph::DEFAULT) {
BROADCAST(put, uri, properties, ctx);
}
void delta(const Raul::URI& uri,
const Properties& remove,
const Properties& add,
Resource::Graph ctx = Resource::Graph::DEFAULT) {
BROADCAST(delta, uri, remove, add, ctx);
}
void copy(const Raul::URI& old_uri,
const Raul::URI& new_uri) {
BROADCAST(copy, old_uri, new_uri);
}
void move(const Raul::Path& old_path,
const Raul::Path& new_path) {
BROADCAST(move, old_path, new_path);
}
void del(const Raul::URI& uri) {
BROADCAST(del, uri);
}
void connect(const Raul::Path& tail,
const Raul::Path& head) {
BROADCAST(connect, tail, head);
}
void disconnect(const Raul::Path& tail,
const Raul::Path& head) {
BROADCAST(disconnect, tail, head);
}
void disconnect_all(const Raul::Path& graph,
const Raul::Path& path) {
BROADCAST(disconnect_all, graph, path);
}
void set_property(const Raul::URI& subject,
const Raul::URI& predicate,
const Atom& value,
Resource::Graph ctx = Resource::Graph::DEFAULT) {
BROADCAST(set_property, subject, predicate, value, ctx);
}
Raul::URI uri() const { return Raul::URI("ingen:/broadcaster"); }
void undo() {} ///< N/A
void redo() {} ///< N/A
void set_response_id(int32_t id) {} ///< N/A
void get(const Raul::URI& uri) {} ///< N/A
void response(int32_t id, Status status, const std::string& subject) {} ///< N/A
void error(const std::string& msg) { BROADCAST(error, msg); }
private:
friend class Transfer;
typedef std::set> Clients;
std::mutex _clients_mutex;
Clients _clients;
std::set< SPtr > _broadcastees;
std::atomic _must_broadcast;
unsigned _bundle_depth;
SPtr _ignore_client;
};
} // namespace Server
} // namespace Ingen
#endif // INGEN_ENGINE_BROADCASTER_HPP