diff options
Diffstat (limited to 'src/libs/client')
-rw-r--r-- | src/libs/client/ClientStore.cpp | 10 | ||||
-rw-r--r-- | src/libs/client/HTTPClientReceiver.cpp | 97 | ||||
-rw-r--r-- | src/libs/client/HTTPClientReceiver.hpp | 62 | ||||
-rw-r--r-- | src/libs/client/HTTPEngineSender.cpp | 300 | ||||
-rw-r--r-- | src/libs/client/HTTPEngineSender.hpp | 162 | ||||
-rw-r--r-- | src/libs/client/Makefile.am | 16 | ||||
-rw-r--r-- | src/libs/client/NodeModel.cpp | 12 | ||||
-rw-r--r-- | src/libs/client/NodeModel.hpp | 9 | ||||
-rw-r--r-- | src/libs/client/OSCClientReceiver.hpp | 14 | ||||
-rw-r--r-- | src/libs/client/OSCEngineSender.hpp | 8 | ||||
-rw-r--r-- | src/libs/client/ObjectModel.cpp | 33 | ||||
-rw-r--r-- | src/libs/client/PortModel.cpp | 4 | ||||
-rw-r--r-- | src/libs/client/PortModel.hpp | 2 | ||||
-rw-r--r-- | src/libs/client/SigClientInterface.hpp | 2 | ||||
-rw-r--r-- | src/libs/client/ThreadedSigClientInterface.cpp | 32 | ||||
-rw-r--r-- | src/libs/client/ThreadedSigClientInterface.hpp | 13 | ||||
-rw-r--r-- | src/libs/client/client.cpp | 24 | ||||
-rw-r--r-- | src/libs/client/client.hpp | 2 |
18 files changed, 729 insertions, 73 deletions
diff --git a/src/libs/client/ClientStore.cpp b/src/libs/client/ClientStore.cpp index 0597aa21..18582046 100644 --- a/src/libs/client/ClientStore.cpp +++ b/src/libs/client/ClientStore.cpp @@ -72,17 +72,15 @@ ClientStore::add_plugin_orphan(SharedPtr<NodeModel> node) { if (!_handle_orphans) return; - cerr << "WARNING: Node " << node->path() << " received, but plugin " - << node->plugin_uri() << " unknown." << endl; Raul::Table<string, list<SharedPtr<NodeModel> > >::iterator spawn = _plugin_orphans.find(node->plugin_uri()); - _engine->request_plugin(node->plugin_uri()); - if (spawn != _plugin_orphans.end()) { spawn->second.push_back(node); } else { + cerr << "WARNING: Orphans of plugin " << node->plugin_uri() << " received" << endl; + _engine->request_plugin(node->plugin_uri()); list<SharedPtr<NodeModel> > l; l.push_back(node); _plugin_orphans[node->plugin_uri()] = l; @@ -108,7 +106,7 @@ ClientStore::resolve_plugin_orphans(SharedPtr<PluginModel> plugin) for (list<SharedPtr<NodeModel> >::iterator i = spawn.begin(); i != spawn.end(); ++i) { (*i)->_plugin = plugin; - add_object(*i); + //add_object(*i); } } } @@ -248,7 +246,6 @@ ClientStore::add_object(SharedPtr<ObjectModel> object) // one (with precedence to the new values). iterator existing = find(object->path()); if (existing != end()) { - cout << "WARNING: Object " << object->path() << " already exists in store" << endl; PtrCast<ObjectModel>(existing->second)->set(object); } else { @@ -444,6 +441,7 @@ ClientStore::new_node(const string& path, const string& plugin_uri) if (!plug) { SharedPtr<NodeModel> n(new NodeModel(plugin_uri, path)); add_plugin_orphan(n); + add_object(n); } else { SharedPtr<NodeModel> n(new NodeModel(plug, path)); add_object(n); diff --git a/src/libs/client/HTTPClientReceiver.cpp b/src/libs/client/HTTPClientReceiver.cpp new file mode 100644 index 00000000..ece55ab2 --- /dev/null +++ b/src/libs/client/HTTPClientReceiver.cpp @@ -0,0 +1,97 @@ +/* This file is part of Ingen. + * Copyright (C) 2008 Dave Robillard <http://drobilla.net> + * + * Ingen is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <list> +#include <cassert> +#include <cstring> +#include <iostream> +#include <sstream> +#include <raul/AtomLiblo.hpp> +#include "module/Module.hpp" +#include "HTTPClientReceiver.hpp" + +using namespace std; +using namespace Raul; + +namespace Ingen { +namespace Client { + + +HTTPClientReceiver::HTTPClientReceiver( + Shared::World* world, + const std::string& url, + SharedPtr<Shared::ClientInterface> target) + : _target(target) + , _world(world) + , _url(url) + , _session(NULL) +{ + start(false); +} + + +HTTPClientReceiver::~HTTPClientReceiver() +{ + stop(); +} + + +void +HTTPClientReceiver::message_callback(SoupSession* session, SoupMessage* msg, void* ptr) +{ + HTTPClientReceiver* me = (HTTPClientReceiver*)ptr; + cout << "RECEIVED ASYNC MESSAGE: " << msg->response_body->data << endl; + me->_target->response_ok(0); + me->_target->enable(); + me->_parser->parse_string(me->_world, me->_target.get(), Glib::ustring(msg->response_body->data), + Glib::ustring("/"), Glib::ustring("")); +} + + +void +HTTPClientReceiver::start(bool dump) +{ + Glib::Mutex::Lock lock(_world->rdf_world->mutex()); + if (!_parser) { + if (!_world->serialisation_module) + _world->serialisation_module = Ingen::Shared::load_module("ingen_serialisation"); + + if (_world->serialisation_module) { + Parser* (*new_parser)() = NULL; + if (_world->serialisation_module->get_symbol("new_parser", (void*&)new_parser)) + _parser = SharedPtr<Parser>(new_parser()); + } + } + _session = soup_session_async_new(); + SoupMessage* msg = soup_message_new("GET", _url.c_str()); + soup_session_queue_message (_session, msg, message_callback, this); +} + + +void +HTTPClientReceiver::stop() +{ + if (_session != NULL) { + //unregister_client(); + soup_session_abort(_session); + _session = NULL; + } +} + + +} // namespace Client +} // namespace Ingen diff --git a/src/libs/client/HTTPClientReceiver.hpp b/src/libs/client/HTTPClientReceiver.hpp new file mode 100644 index 00000000..bab55578 --- /dev/null +++ b/src/libs/client/HTTPClientReceiver.hpp @@ -0,0 +1,62 @@ +/* This file is part of Ingen. + * Copyright (C) 2008 Dave Robillard <http://drobilla.net> + * + * Ingen is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef HTTPCLIENTRECEIVER_H +#define HTTPCLIENTRECEIVER_H + +#include <cstdlib> +#include <boost/utility.hpp> +#include <libsoup/soup.h> +#include "interface/ClientInterface.hpp" +#include "serialisation/Parser.hpp" +#include "redlandmm/World.hpp" +#include "raul/Deletable.hpp" + +namespace Ingen { +namespace Client { + + +class HTTPClientReceiver : public boost::noncopyable, public Raul::Deletable +{ +public: + HTTPClientReceiver(Shared::World* world, + const std::string& url, + SharedPtr<Shared::ClientInterface> target); + + ~HTTPClientReceiver(); + + std::string uri() const { return _url; } + + void start(bool dump); + void stop(); + +private: + static void message_callback(SoupSession* session, SoupMessage* msg, void* ptr); + + SharedPtr<Shared::ClientInterface> _target; + + Shared::World* _world; + const std::string _url; + SoupSession* _session; + SharedPtr<Parser> _parser; +}; + + +} // namespace Client +} // namespace Ingen + +#endif // HTTPCLIENTRECEIVER_H diff --git a/src/libs/client/HTTPEngineSender.cpp b/src/libs/client/HTTPEngineSender.cpp new file mode 100644 index 00000000..882a4bc4 --- /dev/null +++ b/src/libs/client/HTTPEngineSender.cpp @@ -0,0 +1,300 @@ +/* This file is part of Ingen. + * Copyright (C) 2008 Dave Robillard <http://drobilla.net> + * + * Ingen is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <iostream> +#include <libsoup/soup.h> +#include "HTTPEngineSender.hpp" + +using namespace std; + +namespace Ingen { +namespace Client { + + +HTTPEngineSender::HTTPEngineSender(const string& engine_url) + : _engine_url(engine_url) + , _id(0) + , _enabled(true) +{ + _session = soup_session_sync_new(); +} + + +HTTPEngineSender::~HTTPEngineSender() +{ + soup_session_abort(_session); +} + + +void +HTTPEngineSender::attach(int32_t ping_id, bool block) +{ + /*SoupMessage *msg; + msg = soup_message_new ("GET", _engine_url.c_str()); + int status = soup_session_send_message (_session, msg); + cout << "STATUS: " << status << endl; + cout << "RESPONSE: " << msg->response_body->data << endl;*/ +} + + +/* *** EngineInterface implementation below here *** */ + + +/** Register with the engine via HTTP. + * + * Note that this does not actually use 'key', since the engine creates + * it's own key for HTTP clients (namely the incoming URL), for NAT + * traversal. It is a parameter to remain compatible with EngineInterface. + */ +void +HTTPEngineSender::register_client(ClientInterface* client) +{ + +} + + +void +HTTPEngineSender::unregister_client(const string& uri) +{ + +} + + +// Engine commands +void +HTTPEngineSender::load_plugins() +{ + +} + + +void +HTTPEngineSender::activate() +{ + +} + + +void +HTTPEngineSender::deactivate() +{ + +} + + +void +HTTPEngineSender::quit() +{ + +} + + + +// Object commands + +void +HTTPEngineSender::new_patch(const string& path, + uint32_t poly) +{ +} + + +void +HTTPEngineSender::new_port(const string& path, + uint32_t index, + const string& data_type, + bool is_output) +{ +} + + +void +HTTPEngineSender::new_node(const string& path, + const string& plugin_uri) +{ +} + + +/** Create a node using library name and plugin label (DEPRECATED). + * + * DO NOT USE THIS. + */ +void +HTTPEngineSender::new_node_deprecated(const string& path, + const string& plugin_type, + const string& library_name, + const string& plugin_label) +{ +} + + +void +HTTPEngineSender::rename(const string& old_path, + const string& new_name) +{ +} + + +void +HTTPEngineSender::destroy(const string& path) +{ +} + + +void +HTTPEngineSender::clear_patch(const string& patch_path) +{ +} + + +void +HTTPEngineSender::connect(const string& src_port_path, + const string& dst_port_path) +{ +} + + +void +HTTPEngineSender::disconnect(const string& src_port_path, + const string& dst_port_path) +{ +} + + +void +HTTPEngineSender::disconnect_all(const string& parent_patch_path, + const string& node_path) +{ +} + + +void +HTTPEngineSender::set_port_value(const string& port_path, + const Raul::Atom& value) +{ +} + + +void +HTTPEngineSender::set_voice_value(const string& port_path, + uint32_t voice, + const Raul::Atom& value) +{ +} + + +void +HTTPEngineSender::set_port_value_immediate(const string& port_path, + const Raul::Atom& value) +{ +} + + +void +HTTPEngineSender::set_voice_value_immediate(const string& port_path, + uint32_t voice, + const Raul::Atom& value) +{ +} + + +void +HTTPEngineSender::set_program(const string& node_path, + uint32_t bank, + uint32_t program) +{ +} + + +void +HTTPEngineSender::midi_learn(const string& node_path) +{ +} + + +void +HTTPEngineSender::set_variable(const string& obj_path, + const string& predicate, + const Raul::Atom& value) +{ +} + + +void +HTTPEngineSender::set_property(const string& obj_path, + const string& predicate, + const Raul::Atom& value) +{ +} + + + +// Requests // + +void +HTTPEngineSender::ping() +{ +} + + +void +HTTPEngineSender::request_plugin(const string& uri) +{ +} + + +void +HTTPEngineSender::request_object(const string& path) +{ +} + + +void +HTTPEngineSender::request_port_value(const string& port_path) +{ +} + + +void +HTTPEngineSender::request_variable(const string& object_path, const string& key) +{ +} + + +void +HTTPEngineSender::request_property(const string& object_path, const string& key) +{ +} + + +void +HTTPEngineSender::request_plugins() +{ +} + + +void +HTTPEngineSender::request_all_objects() +{ +} + + + +} // namespace Client +} // namespace Ingen + + diff --git a/src/libs/client/HTTPEngineSender.hpp b/src/libs/client/HTTPEngineSender.hpp new file mode 100644 index 00000000..f753eea3 --- /dev/null +++ b/src/libs/client/HTTPEngineSender.hpp @@ -0,0 +1,162 @@ +/* This file is part of Ingen. + * Copyright (C) 2008 Dave Robillard <http://drobilla.net> + * + * Ingen is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) 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 General Public License for details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef HTTPENGINESENDER_H +#define HTTPENGINESENDER_H + +#include <inttypes.h> +#include <string> +#include <libsoup/soup.h> +#include "interface/EngineInterface.hpp" +using std::string; +using Ingen::Shared::EngineInterface; +using Ingen::Shared::ClientInterface; + +namespace Ingen { +namespace Client { + + +/* HTTP (via libsoup) interface to the engine. + * + * Clients can use this opaquely as an EngineInterface to control the engine + * over HTTP (whether over a network or not). + * + * \ingroup IngenClient + */ +class HTTPEngineSender : public EngineInterface { +public: + HTTPEngineSender(const string& engine_url); + ~HTTPEngineSender(); + + string uri() const { return _engine_url; } + + inline int32_t next_id() + { int32_t ret = (_id == -1) ? -1 : _id++; return ret; } + + void set_next_response_id(int32_t id) { _id = id; } + void disable_responses() { _id = -1; } + + void attach(int32_t ping_id, bool block); + + + /* *** EngineInterface implementation below here *** */ + + void enable() { _enabled = true; } + void disable() { _enabled = false; } + + void bundle_begin() { transfer_begin(); } + void bundle_end() { transfer_end(); } + + void transfer_begin(); + void transfer_end(); + + // Client registration + void register_client(ClientInterface* client); + void unregister_client(const string& uri); + + // Engine commands + void load_plugins(); + void activate(); + void deactivate(); + void quit(); + + // Object commands + + void new_patch(const string& path, + uint32_t poly); + + void new_port(const string& path, + uint32_t index, + const string& data_type, + bool is_output); + + void new_node(const string& path, + const string& plugin_uri); + + void new_node_deprecated(const string& path, + const string& plugin_type, + const string& library_name, + const string& plugin_label); + + void rename(const string& old_path, + const string& new_name); + + void destroy(const string& path); + + void clear_patch(const string& patch_path); + + void connect(const string& src_port_path, + const string& dst_port_path); + + void disconnect(const string& src_port_path, + const string& dst_port_path); + + void disconnect_all(const string& parent_patch_path, + const string& node_path); + + void set_port_value(const string& port_path, + const Raul::Atom& value); + + void set_voice_value(const string& port_path, + uint32_t voice, + const Raul::Atom& value); + + void set_port_value_immediate(const string& port_path, + const Raul::Atom& value); + + void set_voice_value_immediate(const string& port_path, + uint32_t voice, + const Raul::Atom& value); + + void set_program(const string& node_path, + uint32_t bank, + uint32_t program); + + void midi_learn(const string& node_path); + + void set_variable(const string& obj_path, + const string& predicate, + const Raul::Atom& value); + + void set_property(const string& obj_path, + const string& predicate, + const Raul::Atom& value); + + // Requests // + void ping(); + void request_plugin(const string& uri); + void request_object(const string& path); + void request_port_value(const string& port_path); + void request_variable(const string& path, const string& key); + void request_property(const string& path, const string& key); + void request_plugins(); + void request_all_objects(); + +protected: + SoupSession* _session; + const string _engine_url; + int _client_port; + int32_t _id; + bool _enabled; +}; + + +} // namespace Client +} // namespace Ingen + +#endif // HTTPENGINESENDER_H + diff --git a/src/libs/client/Makefile.am b/src/libs/client/Makefile.am index 88e2b393..76835de6 100644 --- a/src/libs/client/Makefile.am +++ b/src/libs/client/Makefile.am @@ -15,7 +15,8 @@ libingen_client_la_CXXFLAGS = \ @LXML2_CFLAGS@ \ @RAUL_CFLAGS@ \ @REDLANDMM_CFLAGS@ \ - @SLV2_CFLAGS@ + @SLV2_CFLAGS@ \ + @SOUP_CFLAGS@ libingen_client_la_LIBADD = \ ../shared/libingen_shared.la \ @@ -25,14 +26,21 @@ libingen_client_la_LIBADD = \ @LXML2_LIBS@ \ @RAUL_LIBS@ \ @REDLANDMM_LIBS@ \ - @SLV2_LIBS@ + @SLV2_LIBS@ \ + @SOUP_LIBS@ libingen_client_la_SOURCES = \ $(top_srcdir)/ingen/src/common/interface/ClientInterface.hpp \ $(top_srcdir)/ingen/src/common/interface/EngineInterface.hpp \ + ClientStore.cpp \ + ClientStore.hpp \ ConnectionModel.hpp \ DeprecatedLoader.cpp \ DeprecatedLoader.hpp \ + HTTPClientReceiver.cpp \ + HTTPClientReceiver.hpp \ + HTTPEngineSender.cpp \ + HTTPEngineSender.hpp \ NodeModel.cpp \ NodeModel.hpp \ OSCClientReceiver.cpp \ @@ -45,13 +53,11 @@ libingen_client_la_SOURCES = \ PatchModel.hpp \ PluginModel.cpp \ PluginModel.hpp \ - PluginUI.hpp \ PluginUI.cpp \ + PluginUI.hpp \ PortModel.cpp \ PortModel.hpp \ SigClientInterface.hpp \ - ClientStore.cpp \ - ClientStore.hpp \ ThreadedSigClientInterface.cpp \ ThreadedSigClientInterface.hpp \ client.cpp \ diff --git a/src/libs/client/NodeModel.cpp b/src/libs/client/NodeModel.cpp index 02a0a678..ac0c8e68 100644 --- a/src/libs/client/NodeModel.cpp +++ b/src/libs/client/NodeModel.cpp @@ -69,7 +69,7 @@ void NodeModel::remove_port(SharedPtr<PortModel> port) { // FIXME: slow - for (PortModelList::iterator i = _ports.begin(); i != _ports.end(); ++i) { + for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { if ((*i) == port) { _ports.erase(i); break; @@ -83,7 +83,7 @@ void NodeModel::remove_port(const Path& port_path) { // FIXME: slow - for (PortModelList::iterator i = _ports.begin(); i != _ports.end(); ++i) { + for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { if ((*i)->path() == port_path) { _ports.erase(i); break; @@ -141,7 +141,7 @@ NodeModel::add_port(SharedPtr<PortModel> pm) assert(pm->path().is_child_of(_path)); assert(pm->parent().get() == this); - PortModelList::iterator existing = find(_ports.begin(), _ports.end(), pm); + Ports::iterator existing = find(_ports.begin(), _ports.end(), pm); // Store should have handled this by merging the two assert(existing == _ports.end()); @@ -155,7 +155,7 @@ SharedPtr<PortModel> NodeModel::get_port(const string& port_name) const { assert(port_name.find("/") == string::npos); - for (PortModelList::const_iterator i = _ports.begin(); i != _ports.end(); ++i) + for (Ports::const_iterator i = _ports.begin(); i != _ports.end(); ++i) if ((*i)->path().name() == port_name) return (*i); return SharedPtr<PortModel>(); @@ -211,8 +211,10 @@ void NodeModel::set(SharedPtr<ObjectModel> model) { SharedPtr<NodeModel> node = PtrCast<NodeModel>(model); - if (node) + if (node) { + _plugin_uri = node->_plugin_uri; _plugin = node->_plugin; + } ObjectModel::set(model); } diff --git a/src/libs/client/NodeModel.hpp b/src/libs/client/NodeModel.hpp index a4bcf4d8..03afc17c 100644 --- a/src/libs/client/NodeModel.hpp +++ b/src/libs/client/NodeModel.hpp @@ -50,6 +50,8 @@ class NodeModel : public ObjectModel, virtual public Ingen::Shared::Node public: NodeModel(const NodeModel& copy); virtual ~NodeModel(); + + typedef vector<SharedPtr<PortModel> > Ports; SharedPtr<PortModel> get_port(const string& port_name) const; @@ -58,7 +60,7 @@ public: const string& plugin_uri() const { return _plugin_uri; } const Shared::Plugin* plugin() const { return _plugin.get(); } uint32_t num_ports() const { return _ports.size(); } - const PortModelList& ports() const { return _ports; } + const Ports& ports() const { return _ports; } void port_value_range(SharedPtr<PortModel> port, float& min, float& max); @@ -84,7 +86,7 @@ protected: virtual void clear(); - PortModelList _ports; ///< List of ports (not a Table to preserve order) + Ports _ports; ///< Vector of ports (not a Table to preserve order) string _plugin_uri; ///< Plugin URI (if PluginModel is unknown) SharedPtr<PluginModel> _plugin; ///< The plugin this node is an instance of uint32_t _num_values; ///< Size of _min_values and _max_values @@ -93,9 +95,6 @@ protected: }; -typedef Table<string, SharedPtr<NodeModel> > NodeModelMap; - - } // namespace Client } // namespace Ingen diff --git a/src/libs/client/OSCClientReceiver.hpp b/src/libs/client/OSCClientReceiver.hpp index f1d71dbb..ea5871b3 100644 --- a/src/libs/client/OSCClientReceiver.hpp +++ b/src/libs/client/OSCClientReceiver.hpp @@ -25,18 +25,13 @@ #include "raul/Deletable.hpp" namespace Ingen { - -/** Client library */ namespace Client { -//class NodeModel; - -/* Some boilerplate killing macros... */ +/** Arguments to a liblo handler */ #define LO_HANDLER_ARGS const char* path, const char* types, lo_arg** argv, int argc, lo_message msg -/* Defines a static handler to be passed to lo_add_method, which is a trivial - * wrapper around a non-static method that does the real work. Makes a whoole - * lot of ugly boiler plate go away */ +/** Define a static handler to be passed to lo_add_method, which is a trivial + * wrapper around a non-static method that does the real work. */ #define LO_HANDLER(name) \ int _##name##_cb (LO_HANDLER_ARGS);\ inline static int name##_cb(LO_HANDLER_ARGS, void* osc_listener)\ @@ -62,6 +57,8 @@ public: OSCClientReceiver(int listen_port, SharedPtr<Shared::ClientInterface> target); ~OSCClientReceiver(); + std::string uri() const { return lo_server_thread_get_url(_st); } + void start(bool dump_osc); void stop(); @@ -105,7 +102,6 @@ private: } // namespace Client - } // namespace Ingen #endif // OSCCLIENTRECEIVER_H diff --git a/src/libs/client/OSCEngineSender.hpp b/src/libs/client/OSCEngineSender.hpp index dbb7e8f5..4c92afdb 100644 --- a/src/libs/client/OSCEngineSender.hpp +++ b/src/libs/client/OSCEngineSender.hpp @@ -44,7 +44,7 @@ public: ~OSCEngineSender(); - string engine_url() { return _engine_url; } + std::string uri() const { return _engine_url; } inline int32_t next_id() { int32_t ret = (_id == -1) ? -1 : _id++; return ret; } @@ -148,9 +148,9 @@ public: void request_all_objects(); protected: - string _engine_url; - int _client_port; - int32_t _id; + const string _engine_url; + int _client_port; + int32_t _id; }; diff --git a/src/libs/client/ObjectModel.cpp b/src/libs/client/ObjectModel.cpp index e9a491a6..ede5f822 100644 --- a/src/libs/client/ObjectModel.cpp +++ b/src/libs/client/ObjectModel.cpp @@ -119,21 +119,26 @@ ObjectModel::polyphonic() const * @a model as correct. The paths of the two models MUST be equal. */ void -ObjectModel::set(SharedPtr<ObjectModel> model) +ObjectModel::set(SharedPtr<ObjectModel> o) { - assert(_path == model->path()); - - for (Variables::const_iterator other = model->variables().begin(); - other != model->variables().end(); ++other) { - - Variables::const_iterator mine = _variables.find(other->first); - - if (mine != _variables.end()) { - cerr << "WARNING: " << _path << "Client/Server data mismatch: " << other->first << endl; - } - - _variables[other->first] = other->second; - signal_variable.emit(other->first, other->second); + assert(_path == o->path()); + if (o->_parent) + _parent = o->_parent; + + for (Variables::const_iterator v = o->variables().begin(); v != o->variables().end(); ++v) { + Variables::const_iterator mine = _variables.find(v->first); + if (mine != _variables.end()) + cerr << "WARNING: " << _path << "Client/Server variable mismatch: " << v->first << endl; + _variables[v->first] = v->second; + signal_variable.emit(v->first, v->second); + } + + for (Properties::const_iterator v = o->properties().begin(); v != o->properties().end(); ++v) { + Properties::const_iterator mine = _properties.find(v->first); + if (mine != _properties.end()) + cerr << "WARNING: " << _path << "Client/Server property mismatch: " << v->first << endl; + _properties[v->first] = v->second; + signal_variable.emit(v->first, v->second); } } diff --git a/src/libs/client/PortModel.cpp b/src/libs/client/PortModel.cpp index fa3cb345..c18378db 100644 --- a/src/libs/client/PortModel.cpp +++ b/src/libs/client/PortModel.cpp @@ -51,7 +51,11 @@ PortModel::set(SharedPtr<ObjectModel> model) { SharedPtr<PortModel> port = PtrCast<PortModel>(model); if (port) { + _index = port->_index; + _type = port->_type; + _direction = port->_direction; _current_val = port->_current_val; + _connections = port->_connections; signal_value_changed.emit(_current_val); } diff --git a/src/libs/client/PortModel.hpp b/src/libs/client/PortModel.hpp index a86c9188..a7f52679 100644 --- a/src/libs/client/PortModel.hpp +++ b/src/libs/client/PortModel.hpp @@ -105,8 +105,6 @@ private: size_t _connections; }; -typedef vector<SharedPtr<PortModel> > PortModelList; - } // namespace Client } // namespace Ingen diff --git a/src/libs/client/SigClientInterface.hpp b/src/libs/client/SigClientInterface.hpp index 32a0a43b..7ab32c12 100644 --- a/src/libs/client/SigClientInterface.hpp +++ b/src/libs/client/SigClientInterface.hpp @@ -41,6 +41,8 @@ class SigClientInterface : public Ingen::Shared::ClientInterface, public sigc::t { public: SigClientInterface() : _enabled(true) {} + + bool enabled() const { return _enabled; } std::string uri() const { return "(internal)"; } diff --git a/src/libs/client/ThreadedSigClientInterface.cpp b/src/libs/client/ThreadedSigClientInterface.cpp index 3b7af80c..ef95133b 100644 --- a/src/libs/client/ThreadedSigClientInterface.cpp +++ b/src/libs/client/ThreadedSigClientInterface.cpp @@ -17,7 +17,8 @@ #include "ThreadedSigClientInterface.hpp" #include <iostream> -using std::cerr; using std::endl; + +using namespace std; namespace Ingen { namespace Client { @@ -28,23 +29,19 @@ namespace Client { void ThreadedSigClientInterface::push_sig(Closure ev) { + _attached = true; if (!_enabled) return; bool success = false; - bool first = true; - - // (Very) slow busy-wait if the queue is full - // FIXME: Make this wait on a signal from process_sigs iff this happens while (!success) { - //printf("push %zu\n", _sigs.fill()); success = _sigs.push(ev); if (!success) { - if (first) { - cerr << "[ThreadedSigClientInterface] WARNING: (Client) event queue full. Waiting to try again..." << endl; - first = false; - } - usleep(200000); // 100 milliseconds (2* rate process_sigs is called) + cerr << "WARNING: Client event queue full. Waiting..." << endl; + _mutex.lock(); + _cond.wait(_mutex); + _mutex.unlock(); + cerr << "Queue drained, continuing" << endl; } } } @@ -58,18 +55,21 @@ ThreadedSigClientInterface::push_sig(Closure ev) bool ThreadedSigClientInterface::emit_signals() { - // Process a maximum of queue-size events, to prevent locking the GTK + // Process a limited number of events, to prevent locking the GTK // thread indefinitely while processing continually arriving events - const size_t limit = _sigs.capacity(); + size_t num_processed = 0; - while (!_sigs.empty() && num_processed++ < limit) { - //printf("emit %zu\n", _sigs.fill()); + while (!_sigs.empty() && num_processed++ < (_sigs.capacity() * 3 / 4)) { Closure& ev = _sigs.front(); - _sigs.pop(); ev(); ev.disconnect(); + _sigs.pop(); } + _mutex.lock(); + _cond.broadcast(); + _mutex.unlock(); + return true; } diff --git a/src/libs/client/ThreadedSigClientInterface.hpp b/src/libs/client/ThreadedSigClientInterface.hpp index b3a1b72c..3014c139 100644 --- a/src/libs/client/ThreadedSigClientInterface.hpp +++ b/src/libs/client/ThreadedSigClientInterface.hpp @@ -21,10 +21,12 @@ #include <inttypes.h> #include <string> #include <sigc++/sigc++.h> +#include <glibmm/thread.h> #include "interface/ClientInterface.hpp" #include "SigClientInterface.hpp" -#include <raul/SRSWQueue.hpp> #include <raul/Atom.hpp> +#include <raul/SRSWQueue.hpp> + using std::string; /** Returns nothing and takes no parameters (because they have all been bound) */ @@ -65,12 +67,15 @@ public: , port_activity_slot(signal_port_activity.make_slot()) , program_add_slot(signal_program_add.make_slot()) , program_remove_slot(signal_program_remove.make_slot()) - {} + { + } virtual std::string uri() const { return "(internal)"; } virtual void subscribe(Shared::EngineInterface* engine) { throw; } + bool enabled() const { return _attached; } + void bundle_begin() { push_sig(bundle_begin_slot); } @@ -143,7 +148,11 @@ public: private: void push_sig(Closure ev); + Glib::Mutex _mutex; + Glib::Cond _cond; + Raul::SRSWQueue<Closure> _sigs; + bool _attached; sigc::slot<void> bundle_begin_slot; sigc::slot<void> bundle_end_slot; diff --git a/src/libs/client/client.cpp b/src/libs/client/client.cpp index 8b86e958..32380378 100644 --- a/src/libs/client/client.cpp +++ b/src/libs/client/client.cpp @@ -15,21 +15,37 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <iostream> #include "client.hpp" #include "OSCEngineSender.hpp" +#include "HTTPEngineSender.hpp" + +using namespace std; namespace Ingen { namespace Client { SharedPtr<Ingen::Shared::EngineInterface> -new_osc_interface(const std::string& url) +new_remote_interface(const std::string& url) { - OSCEngineSender* oes = new OSCEngineSender(url); - oes->attach(rand(), true); - return SharedPtr<Shared::EngineInterface>(oes); + const string scheme = url.substr(0, url.find(":")); + cout << "SCHEME: " << scheme << endl; + if (scheme == "osc.udp" || scheme == "osc.tcp") { + OSCEngineSender* oes = new OSCEngineSender(url); + oes->attach(rand(), true); + return SharedPtr<Shared::EngineInterface>(oes); + } else if (scheme == "http") { + HTTPEngineSender* hes = new HTTPEngineSender(url); + hes->attach(rand(), true); + return SharedPtr<Shared::EngineInterface>(hes); + } else { + cerr << "WARNING: Unknown URI scheme '" << scheme << "'" << endl; + return SharedPtr<Shared::EngineInterface>(); + } } + } // namespace Client } // namespace Ingen diff --git a/src/libs/client/client.hpp b/src/libs/client/client.hpp index 931e4c45..82166da5 100644 --- a/src/libs/client/client.hpp +++ b/src/libs/client/client.hpp @@ -30,7 +30,7 @@ namespace Client { extern "C" { - SharedPtr<Shared::EngineInterface> new_osc_interface(const std::string& url); + SharedPtr<Shared::EngineInterface> new_remote_interface(const std::string& url); SharedPtr<Shared::EngineInterface> new_queued_interface(SharedPtr<Ingen::Engine> engine); } |