Previously the port-engine was a LIFO. Changes were pushed back
and then popped-back. This causes issues when re-connecting
Transport Masters.
The GUI does the following when changing connections:
1. disconnect all
2. connect to new port
which lead to TransportMaster::connection_handler being called
in reverse order: connect, disconnect, and the transport
master was assumed to not be connected.
--
Now connections queue is a FIFO and code was consolidated.
(Note, we cannot use a std::deque because it does not support
memory pre-allocation with ::reserve)
In case of internal backends this allows to retrieve the
Device name for a given (hashed unique) port-name.
As opposed to "pretty-name" (which defaults to hw-port-name),
this cannot be changed by the user.
It is intended to be used when probing for control surfaces.
This is mostly a simple lexical search+replace but the absence of operator< for
std::weak_ptr<T> leads to some complications, particularly with Evoral::Sequence
and ExportPortChannel.
PortIndex is sorted by name, and uses port-name as unique identifier.
Ports can be re-named concurrently with processing.
::set_port_name() updates the RCU in the background. The engine
may concurrently process with an old RCU reader value.
In this case valid_port() failed in the process-callback.
and ::get_buffer() returned NULL
In all years of using these assert()s never triggered. Besides
there are valid_port() tests in other strategic locations that
are not periodically hit in realtime context.
The set uses a custom sort-by-name comparator.
Previously it was possible to have an inconsistent set iterator.
std::set::find() did not find a given port while std::find() did.
This fixes using std::set::find() on the PortIndex set.
If connecting ports using the port-engine fails,
ardour forgets the connection.
Internal backends only produced an error if a port was already
connected, when using ::connect (handle, other), but
ignore already existing connection when using port-names.
Various ports are connected twice when the engine connects
at session load. This worked fine for as long as the engine
was never stopped (saving the session asks the port-engine),
but failed when the engine went away and internal representation
is used.
"While 'atomic' has a volatile qualifier, this is a historical
artifact and the pointer passed to it should not be volatile."
Furthermore "It is very important that all accesses to a
particular integer or pointer be performed using only this API"
(from https://developer.gnome.org/glib/2.68/glib-Atomic-Operations.html)
Hence initialization of atomic variables is changed to also use
this API, instead of directly initializing the value.
This also fixes a few cases where atomic variables were
accessed directly.
see also libs/pbd/pbd/g_atomic_compat.h
The backend holds `_port_callback_mutex` while disconnecting ports.
In some cases disconnecting a port can drop the last reference
resulting in a port-deletion from the connection handler.
This in turn will eventually aquire the `_port_callback_mutex`
and deadlock.
This is now circumvented by using atomic operations instead of
taking a lock to set the `_port_change_flag`.
The flag is also used to trigger a latency update in some cases,
atomic is preferable to taking a lock to set this flag.
--
Full bt: https://paste.debian.net/1184056/
Short:
#1 in pthread_mutex_lock ()
#2 in ARDOUR::PortEngineSharedImpl::port_connect_add_remove_callback()
#3 in ARDOUR::BackendPort::~BackendPort()
#4 in ARDOUR::DummyPort::~DummyPort()
#6 in ARDOUR::DummyAudioPort::~DummyAudioPort()
#7 in boost::checked_delete<ARDOUR::BackendPort>(ARDOUR::BackendPort*)
#12 in boost::shared_ptr<ARDOUR::ProtoPort>::reset()
#13 in ARDOUR::Port::drop()
#14 in ARDOUR::Port::~Port()
#15 in ARDOUR::AudioPort::~AudioPort()
#17 in ARDOUR::AudioEngine::add_pending_port_deletion(ARDOUR::Port*)
#20 in boost::detail::sp_counted_base::release()
#37 in ARDOUR::PortManager::connect_callback() at libs/ardour/port_manager.cc:788
#38 in ARDOUR::DummyAudioBackend::main_process_thread() at libs/backends/dummy/dummy_audiobackend.cc:1018
This allow to restore original engine port-names as set
by the backend. ALSA MIDI, CoreAudio, CoreMIDI and PortAudio
drivers can provide human readable physical port names for
some devices.
When the engine is restarted, ports are re-established,
and previously queued port-connections need to be cleared.
This caused a bug:
* when the engine is stopped all ports are disconnected.
_port_connection_queue contains all disconnections
* engine is stopped so _port_connection_queue is not processed
* engine-restart re-etablishes ports and appends those connections
to _port_connection_queue
* process-callback processes the list in **reverse** order
```
while (!_port_connection_queue.empty ()) {
_port_connection_queue.pop_back ();
}
```
* ARDOUR::PortManager::connect_callback() is first called
with connected() and the disconnected()
* All ports are assumed to not be connected
Port::_externally_connected == 0 for all ports
Result:
* vari-speed playback resampling does not work (only external
I/O is reampled), split cycles processing (looping) fails
since AudioPort::get_audio_buffer() does not apply the
_global_port_buffer_offset
Ardour's "pbd/i18n.h" needs to be included last,
after any include that may indirectly pull in getext or libintl.
For that reason "pbd/i18n.h" must not be used in header files either.