initial code steps for websocket OSC

This commit is contained in:
Paul Davis 2017-05-20 02:03:25 +02:00
parent 76e23d1675
commit 4febf7f818
5 changed files with 215 additions and 7 deletions

View File

@ -32,6 +32,7 @@
#include <pbd/pthread_utils.h>
#include <pbd/file_utils.h>
#include <pbd/failed_constructor.h>
#include "pbd/i18n.h"
#include "ardour/amp.h"
#include "ardour/session.h"
@ -58,7 +59,7 @@
#include "osc_route_observer.h"
#include "osc_global_observer.h"
#include "osc_cue_observer.h"
#include "pbd/i18n.h"
#include "ws_osc.h"
using namespace ARDOUR;
using namespace std;
@ -81,16 +82,19 @@ static void error_callback(int, const char *, const char *)
}
#endif
OSC::OSC (Session& s, uint32_t port)
OSC::OSC (Session& s, uint32_t port, int32_t ws_port)
: ControlProtocol (s, X_("Open Sound Control (OSC)"))
, AbstractUI<OSCUIRequest> (name())
, local_server (0)
, remote_server (0)
, ws_server (0)
, _port(port)
, _ws_port(ws_port)
, _ok (true)
, _shutdown (false)
, _osc_server (0)
, _osc_unix_server (0)
, _osc_ws_server (0)
, _debugmode (Off)
, address_only (false)
, remote_port ("8000")
@ -220,6 +224,15 @@ OSC::start ()
PBD::info << "OSC @ " << get_server_url () << endmsg;
if (_ws_port > 0) {
try {
_osc_ws_server = new WSOSCServer (this, _ws_port, string(), string());
PBD::info << "OSC-WebSocket @ " << _ws_port << endmsg;
} catch (...) {
_osc_ws_server = 0;
}
}
std::string url_file;
if (find_file (ardour_config_search_path(), "osc_url", url_file)) {
@ -258,6 +271,12 @@ OSC::start ()
return 0;
}
void
OSC::attach (Glib::RefPtr<IOSource> src)
{
src->attach (_main_loop->get_context());
}
void
OSC::thread_init ()
{
@ -580,7 +599,7 @@ OSC::register_callbacks()
REGISTER_CALLBACK (serv, "/select/eq_q", "if", sel_eq_q);
REGISTER_CALLBACK (serv, "/select/eq_shape", "if", sel_eq_shape);
/* These commands require the route index in addition to the arg; TouchOSC (et al) can't use these */
/* These commands require the route index in addition to the arg; TouchOSC (et al) can't use these */
REGISTER_CALLBACK (serv, "/strip/mute", "ii", route_mute);
REGISTER_CALLBACK (serv, "/strip/solo", "ii", route_solo);
REGISTER_CALLBACK (serv, "/strip/solo_iso", "ii", route_solo_iso);
@ -607,7 +626,7 @@ OSC::register_callbacks()
REGISTER_CALLBACK (serv, "/strip/send/enable", "iif", route_set_send_enable);
REGISTER_CALLBACK(serv, "/strip/name", "is", route_rename);
REGISTER_CALLBACK(serv, "/strip/sends", "i", route_get_sends);
REGISTER_CALLBACK(serv, "/strip/receives", "i", route_get_receives);
REGISTER_CALLBACK(serv, "/strip/receives", "i", route_get_receives);
REGISTER_CALLBACK(serv, "/strip/plugin/list", "i", route_plugin_list);
REGISTER_CALLBACK(serv, "/strip/plugin/descriptor", "ii", route_plugin_descriptor);
REGISTER_CALLBACK(serv, "/strip/plugin/reset", "ii", route_plugin_reset);
@ -4530,4 +4549,3 @@ OSC::cue_get_sorted_stripables(boost::shared_ptr<Stripable> aux, uint32_t id, lo
return sorted;
}

View File

@ -66,10 +66,12 @@ struct OSCUIRequest : public BaseUI::BaseRequestObject {
~OSCUIRequest() {}
};
class WSOSCServer;
class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
{
public:
OSC (ARDOUR::Session&, uint32_t port);
OSC (ARDOUR::Session&, uint32_t port, int32_t ws_port = -1);
virtual ~OSC();
static OSC* instance() { return _instance; }
@ -174,21 +176,26 @@ class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
std::string get_remote_port () { return remote_port; }
void set_remote_port (std::string pt) { remote_port = pt; }
void attach (Glib::RefPtr<Glib::IOSource>);
protected:
void thread_init ();
void do_request (OSCUIRequest*);
GSource* local_server;
GSource* remote_server;
GSource* ws_server;
bool osc_input_handler (Glib::IOCondition, lo_server);
private:
uint32_t _port;
int32_t _ws_port;
volatile bool _ok;
volatile bool _shutdown;
lo_server _osc_server;
lo_server _osc_unix_server;
WSOSCServer* _osc_ws_server;
std::string _osc_unix_socket_path;
std::string _osc_url_file;
OSCDebugMode _debugmode;

125
libs/surfaces/osc/ws_osc.cc Normal file
View File

@ -0,0 +1,125 @@
#include <glibmm.h>
#include "osc.h"
#include "ws_osc.h"
using namespace std;
using namespace ArdourSurface;
using namespace Glib;
// 0 for unlimited
#define MAX_BUFFER_SIZE 0
static int callback_main( struct lws *wsi,
enum lws_callback_reasons reason,
void *user,
void *in,
size_t len )
{
#if 0
int fd;
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 + LWS_SEND_BUFFER_POST_PADDING];
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
switch( reason ) {
case LWS_CALLBACK_ESTABLISHED:
self->onConnectWrapper( lws_get_socket_fd( wsi ) );
lws_callback_on_writable( wsi );
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
fd = lws_get_socket_fd( wsi );
while( !self->connections[fd]->buffer.empty( ) )
{
string message = self->connections[fd]->buffer.front( );
int charsSent = lws_write( wsi, (unsigned char*)message.c_str( ), message.length( ), LWS_WRITE_TEXT );
if( charsSent < message.length( ) )
self->onErrorWrapper( fd, string( "Error writing to socket" ) );
else
// Only pop the message if it was sent successfully.
self->connections[fd]->buffer.pop_front( );
}
lws_callback_on_writable( wsi );
break;
case LWS_CALLBACK_RECEIVE:
self->onMessage( lws_get_socket_fd( wsi ), string( (const char *)in ) );
break;
case LWS_CALLBACK_CLOSED:
self->onDisconnectWrapper( lws_get_socket_fd( wsi ) );
break;
default:
break;
}
#endif
return 0;
}
static struct lws_protocols protocols[] = {
{
"/",
callback_main,
0, // user data struct not used
MAX_BUFFER_SIZE,
},{ NULL, NULL, 0, 0 } // terminator
};
WSOSCServer::WSOSCServer (OSC* o, int32_t p, string const & cpath, string const & kpath)
: osc (o)
, port (p)
, cert_path (cpath)
, key_path (kpath)
, context (0)
{
lws_set_log_level( 0, lwsl_emit_syslog ); // We'll do our own logging, thank you.
struct lws_context_creation_info info;
memset( &info, 0, sizeof info );
info.port = port;
info.iface = NULL;
info.protocols = protocols;
if (cert_path.empty( ) && !key_path.empty( ) ) {
info.ssl_cert_filepath = cert_path.c_str( );
info.ssl_private_key_filepath = key_path.c_str( );
} else {
info.ssl_cert_filepath = 0;
info.ssl_private_key_filepath = 0;
}
info.gid = -1;
info.uid = -1;
info.options = 0;
// keep alive
info.ka_time = 60; // 60 seconds until connection is suspicious
info.ka_probes = 10; // 10 probes after ^ time
info.ka_interval = 10; // 10s interval for sending probes
context = lws_create_context( &info );
if (!context) {
}
}
WSOSCServer::~WSOSCServer ()
{
}
bool
WSOSCServer::event_handler (IOCondition, int)
{
return true;
}
void
WSOSCServer::add_fd (int fd)
{
Glib::RefPtr<IOSource> src = IOSource::create (fd, IO_IN|IO_OUT|IO_HUP|IO_ERR);
src->connect (sigc::bind (sigc::mem_fun (*this, &WSOSCServer::event_handler), fd));
osc->attach (src);
GSource* s = src->gobj();
g_source_ref (s);
sources.push_back (src);
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2017 Paul Davis
*
* This program 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.
*
* This program 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 more 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef ardour_wsosc_h
#define ardour_wsosc_h
#include <string>
#include <vector>
#include <stdint.h>
#include <libwebsockets.h>
#include <glibmm.h>
namespace ArdourSurface {
class OSC;
class WSOSCServer
{
public:
WSOSCServer (OSC*, int32_t port, std::string const & cert_path, std::string const & key_path);
~WSOSCServer ();
private:
OSC* osc;
int port;
std::string cert_path;
std::string key_path;
struct lws_context* context;
typedef std::vector<Glib::RefPtr<Glib::IOSource> > Sources;
Sources sources;
void add_fd (int fd);
bool event_handler (Glib::IOCondition, int);
};
} // namespace
#endif // ardour_wsosc_h

View File

@ -23,6 +23,7 @@ def build(bld):
osc_cue_observer.cc
interface.cc
osc_gui.cc
ws_osc.cc
'''
obj.export_includes = ['.']
obj.defines = [ 'PACKAGE="ardour_osc"' ]
@ -30,7 +31,7 @@ def build(bld):
obj.includes = ['.', './osc']
obj.name = 'libardour_osc'
obj.target = 'ardour_osc'
obj.uselib = 'LO GTKMM GTK GDK'
obj.uselib = 'LO GTKMM GTK GDK WEBSOCKETS'
obj.use = 'libardour libardour_cp libgtkmm2ext libpbd'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')