256 lines
8.2 KiB
C++
256 lines
8.2 KiB
C++
/*
|
|
* Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
|
|
* Copyright (C) 2015-2020 Paul Davis <paul@linuxaudiosystems.com>
|
|
*
|
|
* 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.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#ifndef _libardour_port_engine_shared_h_
|
|
#define _libardour_port_engine_shared_h_
|
|
|
|
#include <atomic>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "pbd/natsort.h"
|
|
#include "pbd/rcu.h"
|
|
|
|
#include "ardour/libardour_visibility.h"
|
|
#include "ardour/port_engine.h"
|
|
#include "ardour/types.h"
|
|
|
|
namespace ARDOUR {
|
|
|
|
class PortEngineSharedImpl;
|
|
class PortManager;
|
|
|
|
class BackendPort;
|
|
|
|
typedef std::shared_ptr<BackendPort> BackendPortPtr;
|
|
typedef std::shared_ptr<BackendPort> const & BackendPortHandle;
|
|
|
|
class LIBARDOUR_API BackendPort : public ProtoPort
|
|
{
|
|
protected:
|
|
BackendPort (PortEngineSharedImpl& b, const std::string&, PortFlags);
|
|
|
|
public:
|
|
virtual ~BackendPort ();
|
|
|
|
const std::string& name () const { return _name; }
|
|
const std::string& pretty_name () const { return _pretty_name; }
|
|
const std::string& hw_port_name () const { return _hw_port_name; }
|
|
|
|
int set_name (const std::string& name) {
|
|
_name = name;
|
|
return 0;
|
|
}
|
|
|
|
/* called from PortEngineSharedImpl */
|
|
int set_pretty_name (const std::string& name) {
|
|
_pretty_name = name;
|
|
return 0;
|
|
}
|
|
|
|
/* called from backends only */
|
|
int set_hw_port_name (const std::string& name) {
|
|
_hw_port_name = name;
|
|
return 0;
|
|
}
|
|
|
|
virtual DataType type () const = 0;
|
|
|
|
PortFlags flags () const { return _flags; }
|
|
bool is_input () const { return flags () & IsInput; }
|
|
bool is_output () const { return flags () & IsOutput; }
|
|
bool is_physical () const { return flags () & IsPhysical; }
|
|
bool is_terminal () const { return flags () & IsTerminal; }
|
|
bool is_connected () const { return _connections.size () != 0; }
|
|
|
|
bool is_connected (BackendPortHandle port) const;
|
|
bool is_physically_connected () const;
|
|
|
|
const std::set<BackendPortPtr>& get_connections () const {
|
|
return _connections;
|
|
}
|
|
|
|
int connect (BackendPortHandle port, BackendPortHandle self);
|
|
int disconnect (BackendPortHandle port, BackendPortHandle self);
|
|
void disconnect_all (BackendPortHandle self);
|
|
|
|
virtual void* get_buffer (pframes_t nframes) = 0;
|
|
|
|
const LatencyRange latency_range (bool for_playback) const
|
|
{
|
|
return for_playback ? _playback_latency_range : _capture_latency_range;
|
|
}
|
|
|
|
void set_latency_range (const LatencyRange& latency_range, bool for_playback);
|
|
|
|
void update_connected_latency (bool for_playback);
|
|
|
|
protected:
|
|
PortEngineSharedImpl& _backend;
|
|
|
|
private:
|
|
std::string _name;
|
|
std::string _pretty_name;
|
|
std::string _hw_port_name;
|
|
const PortFlags _flags;
|
|
LatencyRange _capture_latency_range;
|
|
LatencyRange _playback_latency_range;
|
|
std::set<BackendPortPtr> _connections;
|
|
|
|
void store_connection (BackendPortHandle);
|
|
void remove_connection (BackendPortHandle);
|
|
|
|
}; // class BackendPort
|
|
|
|
class LIBARDOUR_API BackendMIDIEvent
|
|
{
|
|
public:
|
|
virtual ~BackendMIDIEvent () {}
|
|
virtual size_t size () const = 0;
|
|
virtual pframes_t timestamp () const = 0;
|
|
virtual const uint8_t* data () const = 0;
|
|
bool operator< (const BackendMIDIEvent &other) const;
|
|
};
|
|
|
|
class LIBARDOUR_API PortEngineSharedImpl
|
|
{
|
|
public:
|
|
PortEngineSharedImpl (PortManager& mgr, std::string const& instance_name);
|
|
virtual ~PortEngineSharedImpl ();
|
|
|
|
/* Discovering physical ports */
|
|
|
|
bool port_is_physical (PortEngine::PortHandle) const;
|
|
void get_physical_outputs (DataType type, std::vector<std::string>&);
|
|
void get_physical_inputs (DataType type, std::vector<std::string>&);
|
|
ChanCount n_physical_outputs () const;
|
|
ChanCount n_physical_inputs () const;
|
|
|
|
uint32_t port_name_size () const;
|
|
|
|
int set_port_name (PortEngine::PortHandle, const std::string&);
|
|
std::string get_port_name (PortEngine::PortHandle) const;
|
|
PortFlags get_port_flags (PortEngine::PortHandle) const;
|
|
PortEngine::PortPtr get_port_by_name (const std::string&) const;
|
|
|
|
int get_port_property (PortEngine::PortHandle, const std::string& key, std::string& value, std::string& type) const;
|
|
int set_port_property (PortEngine::PortHandle, const std::string& key, const std::string& value, const std::string& type);
|
|
|
|
int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>&) const;
|
|
|
|
DataType port_data_type (PortEngine::PortHandle) const;
|
|
|
|
PortEngine::PortPtr register_port (const std::string& shortname, ARDOUR::DataType, ARDOUR::PortFlags);
|
|
virtual void unregister_port (PortEngine::PortHandle);
|
|
|
|
int connect (const std::string& src, const std::string& dst);
|
|
int disconnect (const std::string& src, const std::string& dst);
|
|
int connect (PortEngine::PortHandle, const std::string&);
|
|
int disconnect (PortEngine::PortHandle, const std::string&);
|
|
int disconnect_all (PortEngine::PortHandle);
|
|
|
|
bool connected (PortEngine::PortHandle, bool process_callback_safe);
|
|
bool connected_to (PortEngine::PortHandle, const std::string&, bool process_callback_safe);
|
|
bool physically_connected (PortEngine::PortHandle, bool process_callback_safe);
|
|
int get_connections (PortEngine::PortHandle, std::vector<std::string>&, bool process_callback_safe);
|
|
|
|
protected:
|
|
friend class BackendPort;
|
|
std::string _instance_name;
|
|
|
|
std::vector<BackendPortPtr> _system_inputs;
|
|
std::vector<BackendPortPtr> _system_outputs;
|
|
std::vector<BackendPortPtr> _system_midi_in;
|
|
std::vector<BackendPortPtr> _system_midi_out;
|
|
|
|
struct PortConnectData {
|
|
std::string a;
|
|
std::string b;
|
|
bool c;
|
|
|
|
PortConnectData (const std::string& a, const std::string& b, bool c)
|
|
: a (a) , b (b) , c (c) {}
|
|
};
|
|
|
|
std::vector<PortConnectData *> _port_connection_queue;
|
|
pthread_mutex_t _port_callback_mutex;
|
|
|
|
std::atomic<int> _port_change_flag; /* atomic */
|
|
|
|
void port_connect_callback (const std::string& a, const std::string& b, bool conn) {
|
|
pthread_mutex_lock (&_port_callback_mutex);
|
|
_port_connection_queue.push_back(new PortConnectData(a, b, conn));
|
|
pthread_mutex_unlock (&_port_callback_mutex);
|
|
}
|
|
|
|
void process_connection_queue_locked (PortManager& mgr);
|
|
|
|
void port_connect_add_remove_callback () {
|
|
_port_change_flag.store (1);
|
|
}
|
|
|
|
virtual void update_system_port_latencies ();
|
|
|
|
void clear_ports ();
|
|
|
|
BackendPortPtr add_port (const std::string& shortname, ARDOUR::DataType, ARDOUR::PortFlags);
|
|
void unregister_ports (bool system_only = false);
|
|
|
|
struct SortByPortName {
|
|
bool operator() (BackendPortHandle lhs, BackendPortHandle rhs) const {
|
|
return PBD::naturally_less (lhs->name ().c_str (), rhs->name ().c_str ());
|
|
}
|
|
};
|
|
|
|
typedef std::map<std::string, BackendPortPtr> PortMap; // fast-lookup by name
|
|
typedef std::set<BackendPortPtr, SortByPortName> PortIndex; // name-based
|
|
typedef std::set<BackendPortPtr> PortRegistry; // std::less<>, safe during rename
|
|
|
|
SerializedRCUManager<PortMap> _portmap;
|
|
SerializedRCUManager<PortIndex> _ports;
|
|
SerializedRCUManager<PortRegistry> _portregistry;
|
|
|
|
bool valid_port (BackendPortHandle port) const {
|
|
std::shared_ptr<PortRegistry const> p = _portregistry.reader ();
|
|
return p->find (port) != p->end ();
|
|
}
|
|
|
|
BackendPortPtr find_port (const std::string& port_name) const {
|
|
std::shared_ptr<PortMap const> p = _portmap.reader ();
|
|
PortMap::const_iterator it = p->find (port_name);
|
|
if (it == p->end ()) {
|
|
return BackendPortPtr();
|
|
}
|
|
return (*it).second;
|
|
}
|
|
|
|
virtual BackendPort* port_factory (std::string const& name, ARDOUR::DataType dt, ARDOUR::PortFlags flags) = 0;
|
|
|
|
#ifndef NDEBUG
|
|
void list_ports () const;
|
|
#endif
|
|
};
|
|
|
|
} /* namespace ARDOUR */
|
|
|
|
#endif
|