diff options
39 files changed, 819 insertions, 132 deletions
diff --git a/src/common/interface/ClientInterface.hpp b/src/common/interface/ClientInterface.hpp index e7ddfeaf..2d604ced 100644 --- a/src/common/interface/ClientInterface.hpp +++ b/src/common/interface/ClientInterface.hpp @@ -42,6 +42,8 @@ public: virtual void response_ok(int32_t id) = 0; virtual void response_error(int32_t id, const std::string& msg) = 0; + + virtual bool enabled() const = 0; virtual void enable() = 0; diff --git a/src/common/interface/EngineInterface.hpp b/src/common/interface/EngineInterface.hpp index b82bf8c2..a9b2a0c1 100644 --- a/src/common/interface/EngineInterface.hpp +++ b/src/common/interface/EngineInterface.hpp @@ -38,6 +38,8 @@ class EngineInterface : public CommonInterface { public: virtual ~EngineInterface() {} + + virtual std::string uri() const = 0; // Responses virtual void set_next_response_id(int32_t id) = 0; 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); } diff --git a/src/libs/engine/OSCClientSender.hpp b/src/libs/engine/OSCClientSender.hpp index d62dd1d3..c8c8418f 100644 --- a/src/libs/engine/OSCClientSender.hpp +++ b/src/libs/engine/OSCClientSender.hpp @@ -48,6 +48,8 @@ public: virtual ~OSCClientSender() { lo_address_free(_address); } + bool enabled() const { return _enabled; } + void enable() { _enabled = true; } void disable() { _enabled = false; } diff --git a/src/libs/engine/OSCEngineReceiver.cpp b/src/libs/engine/OSCEngineReceiver.cpp index a63c826b..f71bdb83 100644 --- a/src/libs/engine/OSCEngineReceiver.cpp +++ b/src/libs/engine/OSCEngineReceiver.cpp @@ -70,7 +70,7 @@ OSCEngineReceiver::OSCEngineReceiver(Engine& engine, size_t queue_size, uint16_t } // For debugging, print all incoming OSC messages - lo_server_add_method(_server, NULL, NULL, generic_cb, NULL); + //lo_server_add_method(_server, NULL, NULL, generic_cb, NULL); // Set response address for this message. // It's important this is first and returns nonzero. diff --git a/src/libs/engine/QueuedEngineInterface.hpp b/src/libs/engine/QueuedEngineInterface.hpp index 17f8c75a..3aba9c7e 100644 --- a/src/libs/engine/QueuedEngineInterface.hpp +++ b/src/libs/engine/QueuedEngineInterface.hpp @@ -62,12 +62,13 @@ public: QueuedEngineInterface(Engine& engine, size_t queued_size, size_t stamped_size); virtual ~QueuedEngineInterface() {} + std::string uri() const { return "ingen:internal"; } + void set_next_response_id(int32_t id); // Client registration virtual void register_client(ClientInterface* client); virtual void unregister_client(const string& uri); - // Engine commands virtual void load_plugins(); diff --git a/src/libs/gui/ConnectWindow.cpp b/src/libs/gui/ConnectWindow.cpp index 03f8408a..eb095af5 100644 --- a/src/libs/gui/ConnectWindow.cpp +++ b/src/libs/gui/ConnectWindow.cpp @@ -29,6 +29,7 @@ #include "engine/Engine.hpp" #include "engine/QueuedEngineInterface.hpp" #include "client/OSCClientReceiver.hpp" +#include "client/HTTPClientReceiver.hpp" #include "client/OSCEngineSender.hpp" #include "client/ThreadedSigClientInterface.hpp" #include "client/ClientStore.hpp" @@ -143,7 +144,9 @@ ConnectWindow::set_connecting_widget_states() void ConnectWindow::connect(bool existing) { - assert(!_attached); + if (_attached) + _attached = false; + assert(!App::instance().client()); _connect_stage = 0; @@ -153,15 +156,22 @@ ConnectWindow::connect(bool existing) if (_mode == CONNECT_REMOTE) { if (!existing) { - const string url = (_widgets_loaded ? _url_entry->get_text() : "osc.udp://localhost:16180"); + const string url = (_widgets_loaded ? (string)_url_entry->get_text() : world->engine->uri()); world->engine = SharedPtr<EngineInterface>(new OSCEngineSender(url)); } - - // FIXME: static args + SharedPtr<ThreadedSigClientInterface> tsci(new ThreadedSigClientInterface(1024)); - SharedPtr<OSCClientReceiver> client(new OSCClientReceiver(16181, tsci)); - App::instance().attach(tsci, client); + SharedPtr<Raul::Deletable> client; + + const string& uri = world->engine->uri(); + const string& scheme = uri.substr(0, uri.find(":")); + if (scheme == "osc.udp" || scheme == "osc.tcp") + client = SharedPtr<OSCClientReceiver>(new OSCClientReceiver(16181, tsci)); // FIXME: port + else if (scheme == "http") + client = SharedPtr<HTTPClientReceiver>(new HTTPClientReceiver(world, uri, tsci)); + App::instance().attach(tsci, client); + Glib::signal_timeout().connect( sigc::mem_fun(App::instance(), &App::gtk_main_iteration), 40, G_PRIORITY_DEFAULT); @@ -377,7 +387,7 @@ ConnectWindow::gtk_callback() assert(App::instance().client()); App::instance().client()->signal_response_ok.connect( - sigc::mem_fun(this, &ConnectWindow::response_ok_received)); + sigc::mem_fun(this, &ConnectWindow::on_response)); _ping_id = abs(rand()) / 2 * 2; // avoid -1 App::instance().engine()->set_next_response_id(_ping_id); @@ -391,7 +401,7 @@ ConnectWindow::gtk_callback() ++_connect_stage; } else if (_connect_stage == 1) { - if (_attached) { + if (_attached || App::instance().client()->enabled()) { App::instance().engine()->activate(); ++_connect_stage; } else { diff --git a/src/libs/gui/ConnectWindow.hpp b/src/libs/gui/ConnectWindow.hpp index 8410783d..fb75d4b2 100644 --- a/src/libs/gui/ConnectWindow.hpp +++ b/src/libs/gui/ConnectWindow.hpp @@ -53,7 +53,7 @@ public: void set_connected_to(SharedPtr<Shared::EngineInterface> engine); void start(Ingen::Shared::World* world); - void response_ok_received(int32_t id) { if (id == _ping_id) _attached = true; } + void on_response(int32_t id) { _attached = true; } private: enum Mode { CONNECT_REMOTE, LAUNCH_REMOTE, INTERNAL }; diff --git a/src/libs/gui/ControlPanel.cpp b/src/libs/gui/ControlPanel.cpp index 84f1163a..032f5758 100644 --- a/src/libs/gui/ControlPanel.cpp +++ b/src/libs/gui/ControlPanel.cpp @@ -69,7 +69,7 @@ ControlPanel::init(SharedPtr<NodeModel> node, uint32_t poly) _voice_control_box->hide(); } - for (PortModelList::const_iterator i = node->ports().begin(); i != node->ports().end(); ++i) { + for (NodeModel::Ports::const_iterator i = node->ports().begin(); i != node->ports().end(); ++i) { add_port(*i); } diff --git a/src/libs/gui/Makefile.am b/src/libs/gui/Makefile.am index fa956fca..48063d35 100644 --- a/src/libs/gui/Makefile.am +++ b/src/libs/gui/Makefile.am @@ -23,7 +23,8 @@ libingen_gui_la_CXXFLAGS = \ @LIBLO_CFLAGS@ \ @REDLANDMM_CFLAGS@ \ @RAUL_CFLAGS@ \ - @SLV2_CFLAGS@ + @SLV2_CFLAGS@ \ + @SOUP_CFLAGS@ libingen_gui_la_LDFLAGS = -no-undefined -module -avoid-version @@ -40,7 +41,8 @@ libingen_gui_la_LIBADD = \ @LIBLO_LIBS@ \ @REDLANDMM_LIBS@ \ @RAUL_LIBS@ \ - @SLV2_LIBS@ + @SLV2_LIBS@ \ + @SOUP_LIBS@ libingen_gui_la_SOURCES = \ gui.hpp \ diff --git a/src/libs/gui/NodeControlWindow.cpp b/src/libs/gui/NodeControlWindow.cpp index 95a07b2b..293d28f5 100644 --- a/src/libs/gui/NodeControlWindow.cpp +++ b/src/libs/gui/NodeControlWindow.cpp @@ -114,7 +114,7 @@ NodeControlWindow::resize() void NodeControlWindow::on_show() { - for (PortModelList::const_iterator i = _node->ports().begin(); + for (NodeModel::Ports::const_iterator i = _node->ports().begin(); i != _node->ports().end(); ++i) if ((*i)->type().is_control() && (*i)->is_input()) App::instance().engine()->request_port_value((*i)->path()); diff --git a/src/libs/gui/NodeMenu.cpp b/src/libs/gui/NodeMenu.cpp index 05139540..529eb52c 100644 --- a/src/libs/gui/NodeMenu.cpp +++ b/src/libs/gui/NodeMenu.cpp @@ -141,7 +141,7 @@ bool NodeMenu::has_control_inputs() { const NodeModel* const nm = (NodeModel*)_object.get(); - for (PortModelList::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) + for (NodeModel::Ports::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) if ((*i)->is_input() && (*i)->type().is_control()) return true; diff --git a/src/libs/gui/NodeModule.cpp b/src/libs/gui/NodeModule.cpp index 21415be9..b3898b94 100644 --- a/src/libs/gui/NodeModule.cpp +++ b/src/libs/gui/NodeModule.cpp @@ -90,7 +90,7 @@ NodeModule::create(boost::shared_ptr<PatchCanvas> canvas, SharedPtr<NodeModel> n for (GraphObject::Variables::const_iterator m = node->variables().begin(); m != node->variables().end(); ++m) ret->set_variable(m->first, m->second); - for (PortModelList::const_iterator p = node->ports().begin(); p != node->ports().end(); ++p) { + for (NodeModel::Ports::const_iterator p = node->ports().begin(); p != node->ports().end(); ++p) { ret->add_port(*p, false); } @@ -151,7 +151,7 @@ NodeModule::embed_gui(bool embed) if (_gui_widget) { _gui_widget->show_all(); - for (PortModelList::const_iterator p = _node->ports().begin(); + for (NodeModel::Ports::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p) if ((*p)->type().is_control() && (*p)->is_output()) App::instance().engine()->set_property((*p)->path(), "ingen:broadcast", true); @@ -162,7 +162,7 @@ NodeModule::embed_gui(bool embed) FlowCanvas::Module::embed(NULL); _plugin_ui.reset(); - for (PortModelList::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p) + for (NodeModel::Ports::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p) if ((*p)->type().is_control() && (*p)->is_output()) App::instance().engine()->set_property((*p)->path(), "ingen:broadcast", false); } @@ -262,7 +262,7 @@ void NodeModule::initialise_gui_values() { uint32_t index=0; - for (PortModelList::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p) { + for (NodeModel::Ports::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p) { if ((*p)->type().is_control()) value_changed(index, (*p)->value()); ++index; diff --git a/src/libs/gui/NodePropertiesWindow.cpp b/src/libs/gui/NodePropertiesWindow.cpp index 9848d872..ae2c23b5 100644 --- a/src/libs/gui/NodePropertiesWindow.cpp +++ b/src/libs/gui/NodePropertiesWindow.cpp @@ -53,8 +53,6 @@ NodePropertiesWindow::set_node(SharedPtr<NodeModel> node_model) _node_polyphonic_toggle->set_active(node_model->polyphonic()); const PluginModel* pm = dynamic_cast<const PluginModel*>(node_model->plugin()); - assert(pm); - if (pm) { _plugin_type_label->set_text(pm->type_uri()); _plugin_uri_label->set_text(pm->uri()); diff --git a/src/libs/gui/PatchCanvas.cpp b/src/libs/gui/PatchCanvas.cpp index f527041b..5d064124 100644 --- a/src/libs/gui/PatchCanvas.cpp +++ b/src/libs/gui/PatchCanvas.cpp @@ -269,7 +269,7 @@ PatchCanvas::build() } // Create pseudo modules for ports (ports on this canvas, not on our module) - for (PortModelList::const_iterator i = _patch->ports().begin(); + for (NodeModel::Ports::const_iterator i = _patch->ports().begin(); i != _patch->ports().end(); ++i) { add_port(*i); } @@ -590,8 +590,7 @@ PatchCanvas::paste() clipboard.new_patch("/", _patch->poly()); ClashAvoider avoider(*App::instance().store().get(), _patch->path(), clipboard, &clipboard); - parser->parse_string(App::instance().world(), &avoider, str, "/", - boost::optional<Glib::ustring>(), (Glib::ustring)_patch->path()); + parser->parse_string(App::instance().world(), &avoider, str, "/", _patch->path()); for (Store::iterator i = clipboard.begin(); i != clipboard.end(); ++i) { cout << "************ OBJECT: " << i->first << endl; diff --git a/src/libs/gui/PatchTreeWindow.cpp b/src/libs/gui/PatchTreeWindow.cpp index ee831cb3..87393cec 100644 --- a/src/libs/gui/PatchTreeWindow.cpp +++ b/src/libs/gui/PatchTreeWindow.cpp @@ -89,7 +89,7 @@ PatchTreeWindow::add_patch(SharedPtr<PatchModel> pm) Gtk::TreeModel::Row row = *iter; if (pm->path() == "/") { SharedPtr<OSCEngineSender> osc_sender = PtrCast<OSCEngineSender>(App::instance().engine()); - string root_name = osc_sender ? osc_sender->engine_url() : "Internal"; + string root_name = osc_sender ? osc_sender->uri() : "Internal"; // Hack off trailing '/' if it's there (ugly) //if (root_name.substr(root_name.length()-1,1) == "/") // root_name = root_name.substr(0, root_name.length()-1); diff --git a/src/libs/gui/PatchWindow.cpp b/src/libs/gui/PatchWindow.cpp index 125adeea..01f74436 100644 --- a/src/libs/gui/PatchWindow.cpp +++ b/src/libs/gui/PatchWindow.cpp @@ -210,7 +210,7 @@ PatchWindow::set_patch(SharedPtr<PatchModel> patch, SharedPtr<PatchView> view) _menu_view_control_window->property_sensitive() = false; - for (PortModelList::const_iterator p = patch->ports().begin(); + for (NodeModel::Ports::const_iterator p = patch->ports().begin(); p != patch->ports().end(); ++p) { if ((*p)->type().is_control() && (*p)->is_input()) { _menu_view_control_window->property_sensitive() = true; @@ -257,7 +257,7 @@ PatchWindow::patch_port_removed(SharedPtr<PortModel> port) bool found_control = false; - for (PortModelList::const_iterator i = _patch->ports().begin(); i != _patch->ports().end(); ++i) { + for (NodeModel::Ports::const_iterator i = _patch->ports().begin(); i != _patch->ports().end(); ++i) { if ((*i)->type().is_control() && (*i)->is_input()) { found_control = true; break; diff --git a/src/libs/serialisation/Parser.cpp b/src/libs/serialisation/Parser.cpp index cc8b4e4b..79c69648 100644 --- a/src/libs/serialisation/Parser.cpp +++ b/src/libs/serialisation/Parser.cpp @@ -63,7 +63,7 @@ Parser::parse_document( Ingen::Shared::CommonInterface* target, const Glib::ustring& document_uri, Glib::ustring object_uri, - boost::optional<Glib::ustring> engine_base, + Glib::ustring engine_base, boost::optional<Raul::Symbol> symbol, boost::optional<GraphObject::Variables> data) { @@ -74,7 +74,7 @@ Parser::parse_document( else cout << "Parsing " << object_uri << " from " << document_uri << endl; - return parse(world, target, model, document_uri, object_uri, engine_base, symbol, data);; + return parse(world, target, model, document_uri, engine_base, object_uri, symbol, data);; } @@ -84,8 +84,8 @@ Parser::parse_string( Ingen::Shared::CommonInterface* target, const Glib::ustring& str, const Glib::ustring& base_uri, + Glib::ustring engine_base, boost::optional<Glib::ustring> object_uri, - boost::optional<Glib::ustring> engine_base, boost::optional<Raul::Symbol> symbol, boost::optional<GraphObject::Variables> data) { @@ -96,10 +96,11 @@ Parser::parse_string( else cout << "Parsing all objects found in string (base " << base_uri << ")" << endl; - bool ret = parse(world, target, model, base_uri, object_uri, engine_base, symbol, data); + bool ret = parse(world, target, model, base_uri, engine_base, object_uri, symbol, data); if (ret) { const Glib::ustring subject = Glib::ustring("<") + base_uri + Glib::ustring(">"); - parse_connections(world, target, model, base_uri, subject, (engine_base ? (string)engine_base.get() : "/")); + parse_connections(world, target, model, base_uri, subject, + Path((engine_base == "") ? "/" : engine_base)); } return ret; @@ -112,13 +113,16 @@ Parser::parse( Ingen::Shared::CommonInterface* target, Redland::Model& model, Glib::ustring base_uri, + Glib::ustring engine_base, boost::optional<Glib::ustring> object_uri, - boost::optional<Glib::ustring> engine_base, boost::optional<Raul::Symbol> symbol, boost::optional<GraphObject::Variables> data) { const Redland::Node::Type res = Redland::Node::RESOURCE; Glib::ustring query_str; + if (object_uri && object_uri.get()[0] == '/') + object_uri = object_uri.get().substr(1); + if (object_uri) query_str = Glib::ustring("SELECT DISTINCT ?class WHERE { <") + object_uri.get() + "> a ?class . }"; else @@ -132,8 +136,13 @@ Parser::parse( const Redland::Node in_port_class(*world->rdf_world, res, NS_INGEN "InputPort"); const Redland::Node out_port_class(*world->rdf_world, res, NS_INGEN "OutputPort"); - const Redland::Node subject_uri(*world->rdf_world, res, - (object_uri ? object_uri.get() : "http://example.org")); + string subject_str = ((object_uri && object_uri.get() != "") ? object_uri.get() : base_uri); + if (subject_str[0] == '/') + subject_str = subject_str.substr(1); + if (subject_str == "") + subject_str = base_uri; + + const Redland::Node subject_uri(*world->rdf_world, res, subject_str); bool ret = false; @@ -141,7 +150,9 @@ Parser::parse( const Redland::Node subject = (object_uri ? subject_uri : (*i)["subject"]); const Redland::Node rdf_class = (*i)["class"]; if (!object_uri) { - std::string path_str = "/" + uri_relative_to_base(base_uri, subject.to_c_string()); + std::string path_str = uri_relative_to_base(base_uri, subject.to_c_string()); + if (path_str[0] != '/') + path_str = string("/").append(path_str); if (Path(path_str).parent() != "/") continue; } @@ -150,12 +161,13 @@ Parser::parse( rdf_class == in_port_class || rdf_class == out_port_class) { Raul::Path path("/"); if (base_uri != subject.to_c_string()) { - string path_str = string("/") + (string)uri_relative_to_base( - base_uri, subject.to_c_string()); + string path_str = (string)uri_relative_to_base(base_uri, subject.to_c_string()); + if (path_str[0] != '/') + path_str = string("/").append(path_str); if (Path::is_valid(path_str)) { path = path_str; } else { - cerr << "[Parser] ERROR: Invalid path " << path << endl; + cerr << "[Parser] ERROR: Invalid path '" << path << "'" << endl; continue; } } @@ -164,8 +176,8 @@ Parser::parse( continue; if (rdf_class == patch_class) { - ret = parse_patch(world, target, model, base_uri, subject.to_c_string(), - engine_base.get(), data); + ret = parse_patch(world, target, model, base_uri, engine_base, + subject.to_c_string(), data); if (ret) target->set_variable(path, "ingen:document", Atom(base_uri.c_str())); } else if (rdf_class == node_class) { @@ -193,8 +205,8 @@ Parser::parse_patch( Ingen::Shared::CommonInterface* target, Redland::Model& model, const Glib::ustring& base_uri, - const Glib::ustring& object_uri, Glib::ustring engine_base, + const Glib::ustring& object_uri, boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()) { std::set<Path> created; @@ -222,6 +234,7 @@ Parser::parse_patch( if (results.size() == 0) { cerr << "[Parser] ERROR: No polyphony found!" << endl; + cerr << "Query was:" << endl << query.string() << endl; return false; } @@ -237,10 +250,12 @@ Parser::parse_patch( patch_path = "/"; else if (engine_base[engine_base.length()-1] == '/') patch_path = Path(engine_base + symbol); - else + else if (Path::is_valid(engine_base)) patch_path = (Path)engine_base; + else + cerr << "WARNING: Illegal engine base path '" << engine_base << "', loading patch to root" << endl; - if (patch_path != "/") + //if (patch_path != "/") target->new_patch(patch_path, patch_poly); /* Plugin nodes */ diff --git a/src/libs/serialisation/Parser.hpp b/src/libs/serialisation/Parser.hpp index 2e088f51..7b8a35eb 100644 --- a/src/libs/serialisation/Parser.hpp +++ b/src/libs/serialisation/Parser.hpp @@ -44,8 +44,8 @@ public: Ingen::Shared::World* world, Shared::CommonInterface* target, const Glib::ustring& document_uri, + Glib::ustring engine_base, Glib::ustring object_uri, - boost::optional<Glib::ustring> engine_base=boost::optional<Glib::ustring>(), boost::optional<Raul::Symbol> symbol=boost::optional<Raul::Symbol>(), boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()); @@ -54,8 +54,8 @@ public: Shared::CommonInterface* target, const Glib::ustring& str, const Glib::ustring& base_uri, + Glib::ustring engine_base, boost::optional<Glib::ustring> object_uri=boost::optional<Glib::ustring>(), - boost::optional<Glib::ustring> engine_base=boost::optional<Glib::ustring>(), boost::optional<Raul::Symbol> symbol=boost::optional<Raul::Symbol>(), boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()); @@ -68,8 +68,8 @@ private: Shared::CommonInterface* target, Redland::Model& model, Glib::ustring base_uri, + Glib::ustring engine_base, boost::optional<Glib::ustring> object_uri=boost::optional<Glib::ustring>(), - boost::optional<Glib::ustring> engine_base=boost::optional<Glib::ustring>(), boost::optional<Raul::Symbol> symbol=boost::optional<Raul::Symbol>(), boost::optional<GraphObject::Variables> data=boost::optional<GraphObject::Variables>()); @@ -78,8 +78,8 @@ private: Ingen::Shared::CommonInterface* target, Redland::Model& model, const Glib::ustring& base_uri, - const Glib::ustring& object_uri, Glib::ustring engine_base, + const Glib::ustring& object_uri, boost::optional<GraphObject::Variables> data); bool parse_node( diff --git a/src/libs/shared/OSCSender.cpp b/src/libs/shared/OSCSender.cpp index 340786db..3936cf96 100644 --- a/src/libs/shared/OSCSender.cpp +++ b/src/libs/shared/OSCSender.cpp @@ -94,8 +94,8 @@ void OSCSender::send_message(const char* path, lo_message msg) { // FIXME: size? liblo doesn't export this. - // Don't want to exceed max UDP packet size (1500 bytes?) - static const size_t MAX_BUNDLE_SIZE = 1500 - 32*5; + // Don't want to exceed max UDP packet size (good default value?) + static const size_t MAX_BUNDLE_SIZE = 1024; if (!_enabled) return; diff --git a/src/libs/shared/OSCSender.hpp b/src/libs/shared/OSCSender.hpp index 16b6dd22..da91caed 100644 --- a/src/libs/shared/OSCSender.hpp +++ b/src/libs/shared/OSCSender.hpp @@ -27,7 +27,7 @@ namespace Shared { class OSCSender { public: OSCSender(); - ~OSCSender(); + virtual ~OSCSender() {} lo_address address() const { return _address; } diff --git a/src/progs/ingen/main.cpp b/src/progs/ingen/main.cpp index d0efb113..c8adf207 100644 --- a/src/progs/ingen/main.cpp +++ b/src/progs/ingen/main.cpp @@ -133,14 +133,14 @@ main(int argc, char** argv) cerr << "Unable to load client module." << endl; } - /* If we don't have a local engine interface (for GUI), use OSC */ + /* If we don't have a local engine interface (for GUI), use network */ if (client_module && ! engine_interface) { - SharedPtr<Shared::EngineInterface> (*new_osc_interface)(const std::string&) = NULL; + SharedPtr<Shared::EngineInterface> (*new_remote_interface)(const std::string&) = NULL; - if (client_module->get_symbol("new_osc_interface", (void*&)new_osc_interface)) { - engine_interface = new_osc_interface(args.connect_arg); + if (client_module->get_symbol("new_remote_interface", (void*&)new_remote_interface)) { + engine_interface = new_remote_interface(args.connect_arg); } else { - cerr << "Unable to find symbol 'new_osc_interface' in " + cerr << "Unable to find symbol 'new_remote_interface' in " "ingen_client module, aborting." << endl; return -1; } @@ -157,7 +157,7 @@ main(int argc, char** argv) /* Load a patch */ if (args.load_given && engine_interface) { - boost::optional<Glib::ustring> engine_base; + Glib::ustring engine_base = "/"; if (args.path_given) engine_base = string(args.path_arg) + "/"; @@ -185,7 +185,7 @@ main(int argc, char** argv) engine_interface->load_plugins(); - parser->parse_document(world, engine_interface.get(), uri, uri, engine_base); + parser->parse_document(world, engine_interface.get(), uri, engine_base, uri); } else { cerr << "Unable to load serialisation module, aborting." << endl; |