mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-17 20:26:30 +01:00
[Summary] Improved backend workflow, added synchronization for cases when device reset happens on device parameter change
This commit is contained in:
parent
295f361f5e
commit
91fcacd150
12 changed files with 348 additions and 299 deletions
|
|
@ -116,6 +116,7 @@ TracksControlPanel::init ()
|
||||||
EngineStateController::instance()->OutputConfigChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_audio_output_configuration_changed, this), gui_context());
|
EngineStateController::instance()->OutputConfigChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_audio_output_configuration_changed, this), gui_context());
|
||||||
EngineStateController::instance()->MIDIInputConfigChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_midi_input_configuration_changed, this), gui_context());
|
EngineStateController::instance()->MIDIInputConfigChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_midi_input_configuration_changed, this), gui_context());
|
||||||
EngineStateController::instance()->MIDIOutputConfigChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_midi_output_configuration_changed, this), gui_context());
|
EngineStateController::instance()->MIDIOutputConfigChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_midi_output_configuration_changed, this), gui_context());
|
||||||
|
EngineStateController::instance()->DeviceError.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_device_error, this), gui_context());
|
||||||
|
|
||||||
/* Global configuration parameters update */
|
/* Global configuration parameters update */
|
||||||
Config->ParameterChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_parameter_changed, this, _1), gui_context());
|
Config->ParameterChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_parameter_changed, this, _1), gui_context());
|
||||||
|
|
|
||||||
|
|
@ -329,6 +329,12 @@ class LIBARDOUR_API AudioBackend : public PortEngine {
|
||||||
*/
|
*/
|
||||||
virtual int stop () = 0;
|
virtual int stop () = 0;
|
||||||
|
|
||||||
|
/** Reset device.
|
||||||
|
*
|
||||||
|
* Return zero if successful, negative values on error
|
||||||
|
*/
|
||||||
|
virtual int reset_device() = 0;
|
||||||
|
|
||||||
/** While remaining connected to the device, and without changing its
|
/** While remaining connected to the device, and without changing its
|
||||||
* configuration, start (or stop) calling the process_callback() of @param engine
|
* configuration, start (or stop) calling the process_callback() of @param engine
|
||||||
* without waiting for the device. Once process_callback() has returned, it
|
* without waiting for the device. Once process_callback() has returned, it
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ public:
|
||||||
bool running() const { return _running; }
|
bool running() const { return _running; }
|
||||||
|
|
||||||
Glib::Threads::Mutex& process_lock() { return _process_lock; }
|
Glib::Threads::Mutex& process_lock() { return _process_lock; }
|
||||||
|
Glib::Threads::RecMutex& state_lock() { return _state_lock; }
|
||||||
|
|
||||||
int request_buffer_size (pframes_t samples) {
|
int request_buffer_size (pframes_t samples) {
|
||||||
return set_buffer_size (samples);
|
return set_buffer_size (samples);
|
||||||
|
|
@ -168,6 +169,10 @@ public:
|
||||||
|
|
||||||
PBD::Signal1<void, pframes_t> BufferSizeChanged;
|
PBD::Signal1<void, pframes_t> BufferSizeChanged;
|
||||||
|
|
||||||
|
/* this signal is emitted if the device cannot operate properly */
|
||||||
|
|
||||||
|
PBD::Signal0<void> DeviceError;
|
||||||
|
|
||||||
/* this signal is emitted if the device list changed */
|
/* this signal is emitted if the device list changed */
|
||||||
|
|
||||||
PBD::Signal0<void> DeviceListChanged;
|
PBD::Signal0<void> DeviceListChanged;
|
||||||
|
|
@ -218,6 +223,7 @@ public:
|
||||||
static AudioEngine* _instance;
|
static AudioEngine* _instance;
|
||||||
|
|
||||||
Glib::Threads::Mutex _process_lock;
|
Glib::Threads::Mutex _process_lock;
|
||||||
|
Glib::Threads::RecMutex _state_lock;
|
||||||
Glib::Threads::Cond session_removed;
|
Glib::Threads::Cond session_removed;
|
||||||
bool session_remove_pending;
|
bool session_remove_pending;
|
||||||
frameoffset_t session_removal_countdown;
|
frameoffset_t session_removal_countdown;
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,8 @@ public:
|
||||||
PBD::Signal0<void> BufferSizeChanged;
|
PBD::Signal0<void> BufferSizeChanged;
|
||||||
/* this signal is emitted if the device list changes */
|
/* this signal is emitted if the device list changes */
|
||||||
PBD::Signal1<void, bool> DeviceListChanged;
|
PBD::Signal1<void, bool> DeviceListChanged;
|
||||||
|
/* this signal is emitted if the device cannot operate properly */
|
||||||
|
PBD::Signal0<void> DeviceError;
|
||||||
|
|
||||||
//ENGINE STATE SIGNALS
|
//ENGINE STATE SIGNALS
|
||||||
/* this signal is emitted when the engine is started */
|
/* this signal is emitted when the engine is started */
|
||||||
|
|
@ -260,11 +262,13 @@ private:
|
||||||
void _on_engine_running();
|
void _on_engine_running();
|
||||||
void _on_engine_halted();
|
void _on_engine_halted();
|
||||||
void _on_engine_stopped();
|
void _on_engine_stopped();
|
||||||
|
void _on_device_error();
|
||||||
void _on_sample_rate_change(ARDOUR::framecnt_t);
|
void _on_sample_rate_change(ARDOUR::framecnt_t);
|
||||||
void _on_buffer_size_change(ARDOUR::pframes_t);
|
void _on_buffer_size_change(ARDOUR::pframes_t);
|
||||||
void _on_device_list_change();
|
void _on_device_list_change();
|
||||||
void _on_parameter_changed (const std::string&);
|
void _on_parameter_changed (const std::string&);
|
||||||
void _on_ports_registration_update ();
|
void _on_ports_registration_update ();
|
||||||
|
void _on_session_loaded();
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
|
@ -284,10 +288,10 @@ private:
|
||||||
|
|
||||||
// Engine connections stuff
|
// Engine connections stuff
|
||||||
PBD::ScopedConnectionList update_connections;
|
PBD::ScopedConnectionList update_connections;
|
||||||
|
PBD::ScopedConnectionList session_connections;
|
||||||
PBD::ScopedConnection running_connection;
|
PBD::ScopedConnection running_connection;
|
||||||
PBD::ScopedConnection halt_connection;
|
PBD::ScopedConnection halt_connection;
|
||||||
PBD::ScopedConnection stopped_connection;
|
PBD::ScopedConnection stopped_connection;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDOUR
|
} // namespace ARDOUR
|
||||||
|
|
|
||||||
|
|
@ -384,27 +384,34 @@ AudioEngine::do_reset_backend()
|
||||||
|
|
||||||
_reset_request_lock.unlock();
|
_reset_request_lock.unlock();
|
||||||
|
|
||||||
|
Glib::Threads::RecMutex::Lock pl (_state_lock);
|
||||||
|
|
||||||
g_atomic_int_dec_and_test (&_hw_reset_request_count);
|
g_atomic_int_dec_and_test (&_hw_reset_request_count);
|
||||||
|
|
||||||
// backup the device name
|
// backup the device name
|
||||||
std::string name = _backend->device_name ();
|
std::string name = _backend->device_name ();
|
||||||
|
|
||||||
|
std::cout << "RESET::Stoping" << std::endl;
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
|
std::cout << "RESET::HALT" << std::endl;
|
||||||
if (_session) {
|
if (_session) {
|
||||||
// it's not a halt, but should be handled the same way:
|
// it's not a halt, but should be handled the same way:
|
||||||
// disable record, stop transport and I/O processign but save the data.
|
// disable record, stop transport and I/O processign but save the data.
|
||||||
_session->engine_halted ();
|
//_session->engine_halted ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// "hard reset" the device
|
std::cout << "RESET::Reseting" << std::endl;
|
||||||
_backend->drop_device ();
|
if ( 0 == _backend->reset_device () ) {
|
||||||
_backend->set_device_name (name);
|
|
||||||
|
|
||||||
|
std::cout << "RESET::Starting" << std::endl;
|
||||||
start ();
|
start ();
|
||||||
|
|
||||||
// inform about possible changes
|
// inform about possible changes
|
||||||
SampleRateChanged (_backend->sample_rate() );
|
|
||||||
BufferSizeChanged (_backend->buffer_size() );
|
BufferSizeChanged (_backend->buffer_size() );
|
||||||
|
} else {
|
||||||
|
DeviceError();
|
||||||
|
}
|
||||||
|
|
||||||
_reset_request_lock.lock();
|
_reset_request_lock.lock();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ EngineStateController::EngineStateController()
|
||||||
AudioEngine::instance()->SampleRateChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_sample_rate_change, this, _1) );
|
AudioEngine::instance()->SampleRateChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_sample_rate_change, this, _1) );
|
||||||
AudioEngine::instance()->BufferSizeChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_buffer_size_change, this, _1) );
|
AudioEngine::instance()->BufferSizeChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_buffer_size_change, this, _1) );
|
||||||
AudioEngine::instance()->DeviceListChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_device_list_change, this) );
|
AudioEngine::instance()->DeviceListChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_device_list_change, this) );
|
||||||
|
AudioEngine::instance()->DeviceError.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_device_error, this) );
|
||||||
|
|
||||||
/* Global configuration parameters update */
|
/* Global configuration parameters update */
|
||||||
Config->ParameterChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_parameter_changed, this, _1) );
|
Config->ParameterChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_parameter_changed, this, _1) );
|
||||||
|
|
@ -81,7 +82,8 @@ EngineStateController::~EngineStateController()
|
||||||
|
|
||||||
|
|
||||||
XMLNode&
|
XMLNode&
|
||||||
EngineStateController::serialize_audio_midi_settings() {
|
EngineStateController::serialize_audio_midi_settings()
|
||||||
|
{
|
||||||
|
|
||||||
XMLNode* root = new XMLNode ("AudioMidiSettings");
|
XMLNode* root = new XMLNode ("AudioMidiSettings");
|
||||||
|
|
||||||
|
|
@ -93,7 +95,8 @@ EngineStateController::serialize_audio_midi_settings() {
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
EngineStateController::save_audio_midi_settings() {
|
EngineStateController::save_audio_midi_settings()
|
||||||
|
{
|
||||||
Config->add_extra_xml (serialize_audio_midi_settings() );
|
Config->add_extra_xml (serialize_audio_midi_settings() );
|
||||||
Config->save_state ();
|
Config->save_state ();
|
||||||
}
|
}
|
||||||
|
|
@ -1182,7 +1185,7 @@ EngineStateController::_on_sample_rate_change(framecnt_t new_sample_rate)
|
||||||
framecnt_t sample_rate_to_set = new_sample_rate;
|
framecnt_t sample_rate_to_set = new_sample_rate;
|
||||||
if (AudioEngine::instance()->session() ) {
|
if (AudioEngine::instance()->session() ) {
|
||||||
// and we have current session we should restore it back to the one tracks uses
|
// and we have current session we should restore it back to the one tracks uses
|
||||||
framecnt_t sample_rate_to_set = _current_state->sample_rate;
|
sample_rate_to_set = _current_state->sample_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( set_new_sample_rate_in_controller (sample_rate_to_set) ) {
|
if ( set_new_sample_rate_in_controller (sample_rate_to_set) ) {
|
||||||
|
|
@ -1192,7 +1195,8 @@ EngineStateController::_on_sample_rate_change(framecnt_t new_sample_rate)
|
||||||
// if sample rate can't be set
|
// if sample rate can't be set
|
||||||
// switch to NONE device
|
// switch to NONE device
|
||||||
set_new_device_as_current ("None");
|
set_new_device_as_current ("None");
|
||||||
DeviceListChanged(true);
|
DeviceListChanged(false);
|
||||||
|
DeviceError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1467,6 +1471,16 @@ EngineStateController::_on_engine_halted ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
EngineStateController::_on_device_error()
|
||||||
|
{
|
||||||
|
set_new_device_as_current ("None");
|
||||||
|
push_current_state_to_backend(true);
|
||||||
|
DeviceListChanged(false);
|
||||||
|
DeviceError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
EngineStateController::_on_parameter_changed (const std::string& parameter_name)
|
EngineStateController::_on_parameter_changed (const std::string& parameter_name)
|
||||||
{
|
{
|
||||||
|
|
@ -1504,6 +1518,7 @@ EngineStateController::push_current_state_to_backend(bool start)
|
||||||
|
|
||||||
bool was_running = AudioEngine::instance()->running();
|
bool was_running = AudioEngine::instance()->running();
|
||||||
|
|
||||||
|
Glib::Threads::RecMutex::Lock sl (AudioEngine::instance()->state_lock() );
|
||||||
if (state_changed) {
|
if (state_changed) {
|
||||||
|
|
||||||
if (was_running) {
|
if (was_running) {
|
||||||
|
|
@ -1512,20 +1527,31 @@ EngineStateController::push_current_state_to_backend(bool start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
{
|
||||||
std::cout << "EngineStateController::Setting device: " << _current_state->device_name << std::endl;
|
std::cout << "EngineStateController::Setting device: " << _current_state->device_name << std::endl;
|
||||||
if ((_current_state->device_name != backend->device_name()) && backend->set_device_name (_current_state->device_name)) {
|
if ((_current_state->device_name != backend->device_name()) && (result = backend->set_device_name (_current_state->device_name)) ) {
|
||||||
error << string_compose (_("Cannot set device name to %1"), get_current_device_name()) << endmsg;
|
error << string_compose (_("Cannot set device name to %1"), get_current_device_name()) << endmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "EngineStateController::Setting device sample rate " << _current_state->sample_rate << std::endl;
|
std::cout << "EngineStateController::Setting device sample rate " << _current_state->sample_rate << std::endl;
|
||||||
if (backend->set_sample_rate (_current_state->sample_rate )) {
|
if (!result && (result = backend->set_sample_rate (_current_state->sample_rate)) ) {
|
||||||
error << string_compose (_("Cannot set sample rate to %1"), get_current_sample_rate()) << endmsg;
|
error << string_compose (_("Cannot set sample rate to %1"), get_current_sample_rate()) << endmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "EngineStateController::Setting device buffer size " << _current_state->buffer_size << std::endl;
|
std::cout << "EngineStateController::Setting device buffer size " << _current_state->buffer_size << std::endl;
|
||||||
if (backend->set_buffer_size (_current_state->buffer_size )) {
|
if (!result && (result = backend->set_buffer_size (_current_state->buffer_size)) ) {
|
||||||
error << string_compose (_("Cannot set buffer size to %1"), get_current_buffer_size()) << endmsg;
|
error << string_compose (_("Cannot set buffer size to %1"), get_current_buffer_size()) << endmsg;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) // error during device setup
|
||||||
|
{
|
||||||
|
//switch to None device and notify about hte issue
|
||||||
|
set_new_device_as_current ("None");
|
||||||
|
DeviceListChanged(false);
|
||||||
|
DeviceError();
|
||||||
|
}
|
||||||
|
|
||||||
//if (backend->set_input_channels (get_input_channels())) {
|
//if (backend->set_input_channels (get_input_channels())) {
|
||||||
// error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
|
// error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
|
||||||
|
|
@ -1568,10 +1594,5 @@ EngineStateController::set_desired_sample_rate(framecnt_t session_desired_sr)
|
||||||
}
|
}
|
||||||
|
|
||||||
_desired_sample_rate = session_desired_sr;
|
_desired_sample_rate = session_desired_sr;
|
||||||
|
|
||||||
// if we swithced to new desired sample rate successfuly - push the new state to the backend
|
|
||||||
if (set_new_sample_rate_in_controller (session_desired_sr) ) {
|
|
||||||
push_current_state_to_backend(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -436,6 +436,10 @@ WavesAudioBackend::set_buffer_size (uint32_t buffer_size)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if call to set buffer is successful but device buffer size differs from the value we tried to set
|
||||||
|
// this means we are driven by device for buffer size
|
||||||
|
buffer_size = _device->CurrentBufferSize ();
|
||||||
|
|
||||||
_buffer_size_change(buffer_size);
|
_buffer_size_change(buffer_size);
|
||||||
|
|
||||||
if (device_needs_restart) {
|
if (device_needs_restart) {
|
||||||
|
|
@ -462,9 +466,9 @@ WavesAudioBackend::set_sample_format (SampleFormat sample_format)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
WavesAudioBackend::_reset_device (uint32_t buffer_size, float sample_rate)
|
WavesAudioBackend::reset_device ()
|
||||||
{
|
{
|
||||||
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_reset_device (" << buffer_size <<", " << sample_rate << "):" << std::endl;
|
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_reset_device ():" << std::endl;
|
||||||
|
|
||||||
WTErr retVal = eNoErr;
|
WTErr retVal = eNoErr;
|
||||||
|
|
||||||
|
|
@ -473,95 +477,7 @@ WavesAudioBackend::_reset_device (uint32_t buffer_size, float sample_rate)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool device_needs_restart = _device->Streaming ();
|
return _device->ResetDevice();
|
||||||
|
|
||||||
if (device_needs_restart) {
|
|
||||||
retVal = _device->SetStreaming (false);
|
|
||||||
// COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetStreaming (false);"<< std::endl;
|
|
||||||
if (retVal != eNoErr) {
|
|
||||||
std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName () << "]->SetStreaming (false) failed (" << retVal << ") !" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
retVal = _device->SetActive (false);
|
|
||||||
// COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetActive (false);"<< std::endl;
|
|
||||||
if (retVal != eNoErr) {
|
|
||||||
std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName () << "]->SetActive (false) failed (" << retVal << ") !" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
retVal = _device->UpdateDeviceInfo ();
|
|
||||||
if (retVal != eNoErr) {
|
|
||||||
std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName() << "]->UpdateDeviceInfo () failed (" << retVal << ") !" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer_size != 0)
|
|
||||||
{
|
|
||||||
retVal = _device->SetCurrentBufferSize (buffer_size);
|
|
||||||
|
|
||||||
if (retVal != eNoErr) {
|
|
||||||
std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName() << "]->SetCurrentBufferSize (" << buffer_size << ") failed (" << retVal << ") !" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_buffer_size = buffer_size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint32_t current_buffer_size = _device->CurrentBufferSize();
|
|
||||||
// COMMENTED DBG LOGS */ std::cout << "\t\tcurrent_buffer_size: " << current_buffer_size << std::endl;
|
|
||||||
// COMMENTED DBG LOGS */ std::cout << "\t\t _buffer_size: " << _buffer_size << std::endl;
|
|
||||||
if(_buffer_size != current_buffer_size)
|
|
||||||
{
|
|
||||||
_buffer_size = current_buffer_size;
|
|
||||||
engine.buffer_size_change (_buffer_size);
|
|
||||||
// COMMENTED DBG LOGS */ std::cout << "\t\tengine.buffer_size_change (" << buffer_size <<")" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sample_rate > 0.0)
|
|
||||||
{
|
|
||||||
retVal = _device->SetCurrentSamplingRate ((int)sample_rate);
|
|
||||||
|
|
||||||
if (retVal != eNoErr) {
|
|
||||||
std::cerr << "WavesAudioBackend::set_sample_rate (): [" << _device->DeviceName() << "]->SetCurrentSamplingRate ((int)" << sample_rate << ") failed (" << retVal << ") !" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
_sample_rate = sample_rate;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float current_sample_rate = _device->CurrentSamplingRate();
|
|
||||||
// COMMENTED DBG LOGS */ std::cout << "\t\tcurrent_sample_rate: " << current_sample_rate << std::endl;
|
|
||||||
// COMMENTED DBG LOGS */ std::cout << "\t\t _sample_rate: " << _sample_rate << std::endl;
|
|
||||||
if(_sample_rate != current_sample_rate)
|
|
||||||
{
|
|
||||||
_sample_rate = current_sample_rate;
|
|
||||||
engine.sample_rate_change (_sample_rate);
|
|
||||||
// COMMENTED DBG LOGS */ std::cout << "\t\tengine.sample_rate_change (" << _sample_rate <<")" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_init_dsp_load_history();
|
|
||||||
|
|
||||||
if (device_needs_restart) {
|
|
||||||
// COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetActive (true);"<< std::endl;
|
|
||||||
retVal = _device->SetActive (true);
|
|
||||||
if (retVal != eNoErr) {
|
|
||||||
std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName () << "]->SetActive (true) failed (" << retVal << ") !" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetStreaming (true);"<< std::endl;
|
|
||||||
_call_thread_init_callback = true;
|
|
||||||
retVal = _device->SetStreaming (true);
|
|
||||||
if (retVal != eNoErr) {
|
|
||||||
std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName () << "]->SetStreaming (true) failed (" << retVal << ") !" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,8 @@ class WavesMidiPort;
|
||||||
|
|
||||||
virtual int set_systemic_output_latency (uint32_t);
|
virtual int set_systemic_output_latency (uint32_t);
|
||||||
|
|
||||||
|
virtual int reset_device ();
|
||||||
|
|
||||||
virtual std::string device_name () const;
|
virtual std::string device_name () const;
|
||||||
|
|
||||||
virtual float sample_rate () const;
|
virtual float sample_rate () const;
|
||||||
|
|
@ -324,7 +326,6 @@ class WavesMidiPort;
|
||||||
pframes_t sample_time,
|
pframes_t sample_time,
|
||||||
uint64_t cycle_start_time_nanos);
|
uint64_t cycle_start_time_nanos);
|
||||||
|
|
||||||
int _reset_device (uint32_t buffer_size, float sample_rate);
|
|
||||||
void _changed_midi_devices ();
|
void _changed_midi_devices ();
|
||||||
|
|
||||||
// DO change sample rate and buffer size
|
// DO change sample rate and buffer size
|
||||||
|
|
|
||||||
|
|
@ -344,6 +344,28 @@ WTErr WCMRAudioDevice::SetStreaming (bool newState)
|
||||||
return (eNoErr);
|
return (eNoErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WTErr WCMRAudioDevice::ResetDevice ()
|
||||||
|
{
|
||||||
|
// Keep device sates
|
||||||
|
bool wasStreaming = Streaming();
|
||||||
|
bool wasActive = Active();
|
||||||
|
|
||||||
|
WTErr err = SetStreaming(false);
|
||||||
|
|
||||||
|
if (err == eNoErr)
|
||||||
|
SetActive(false);
|
||||||
|
|
||||||
|
if (err == eNoErr && wasActive)
|
||||||
|
SetActive(true);
|
||||||
|
|
||||||
|
if (err == eNoErr && wasStreaming)
|
||||||
|
SetStreaming(true);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// IsProcessActive - returns true if process code is running.
|
// IsProcessActive - returns true if process code is running.
|
||||||
// A normal audio device should return the Streaming() value
|
// A normal audio device should return the Streaming() value
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,8 @@ public:
|
||||||
virtual bool Streaming();///<Streaming Status?
|
virtual bool Streaming();///<Streaming Status?
|
||||||
virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts!
|
virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts!
|
||||||
|
|
||||||
|
virtual WTErr ResetDevice ();
|
||||||
|
|
||||||
virtual bool IsProcessActive();
|
virtual bool IsProcessActive();
|
||||||
|
|
||||||
virtual WTErr DoIdle();///<Do Idle Processing
|
virtual WTErr DoIdle();///<Do Idle Processing
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,16 @@
|
||||||
#include "UMicroseconds.h"
|
#include "UMicroseconds.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <list>
|
||||||
using namespace wvNS;
|
using namespace wvNS;
|
||||||
#include "IncludeWindows.h"
|
#include "IncludeWindows.h"
|
||||||
#include <MMSystem.h>
|
#include <MMSystem.h>
|
||||||
#include "pa_asio.h"
|
#include "pa_asio.h"
|
||||||
#include "asio.h"
|
#include "asio.h"
|
||||||
|
|
||||||
#define PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS 200
|
#define PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS 500
|
||||||
#define PROPERTY_CHANGE_TIMEOUT_SECONDS 2
|
#define PROPERTY_CHANGE_TIMEOUT_SECONDS 2
|
||||||
|
#define PROPERTY_CHANGE_RETRIES 3
|
||||||
|
|
||||||
///< Supported Sample rates
|
///< Supported Sample rates
|
||||||
static const double gAllSampleRates[] =
|
static const double gAllSampleRates[] =
|
||||||
|
|
@ -307,14 +309,12 @@ void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
|
||||||
//update name.
|
//update name.
|
||||||
m_DeviceName = pDeviceInfo->name;
|
m_DeviceName = pDeviceInfo->name;
|
||||||
|
|
||||||
std::cout << "API::Device " << m_DeviceName << " Getting device info " << std::endl;
|
|
||||||
|
|
||||||
//following parameters are needed opening test stream and for sample rates validation
|
//following parameters are needed opening test stream and for sample rates validation
|
||||||
PaStreamParameters inputParameters, outputParameters;
|
PaStreamParameters inputParameters, outputParameters;
|
||||||
PaStreamParameters *pInS = NULL, *pOutS = NULL;
|
PaStreamParameters *pInS = NULL, *pOutS = NULL;
|
||||||
|
|
||||||
inputParameters.device = m_DeviceID;
|
inputParameters.device = m_DeviceID;
|
||||||
inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
|
inputParameters.channelCount = pDeviceInfo->maxInputChannels;
|
||||||
inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
|
inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
|
||||||
inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
|
inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
|
||||||
inputParameters.hostApiSpecificStreamInfo = 0;
|
inputParameters.hostApiSpecificStreamInfo = 0;
|
||||||
|
|
@ -323,7 +323,7 @@ void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
|
||||||
pInS = &inputParameters;
|
pInS = &inputParameters;
|
||||||
|
|
||||||
outputParameters.device = m_DeviceID;
|
outputParameters.device = m_DeviceID;
|
||||||
outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
|
outputParameters.channelCount = pDeviceInfo->maxOutputChannels;
|
||||||
outputParameters.sampleFormat = paFloat32;
|
outputParameters.sampleFormat = paFloat32;
|
||||||
outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
|
outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
|
||||||
outputParameters.hostApiSpecificStreamInfo = 0;
|
outputParameters.hostApiSpecificStreamInfo = 0;
|
||||||
|
|
@ -331,7 +331,6 @@ void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
|
||||||
if (outputParameters.channelCount)
|
if (outputParameters.channelCount)
|
||||||
pOutS = &outputParameters;
|
pOutS = &outputParameters;
|
||||||
|
|
||||||
std::cout << "API::Device" << m_DeviceName << " Updating sample rates " << std::endl;
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
//update list of supported SRs...
|
//update list of supported SRs...
|
||||||
m_SamplingRates.clear();
|
m_SamplingRates.clear();
|
||||||
|
|
@ -347,38 +346,16 @@ void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "API::Device" << m_DeviceName << " Updating buffer sizes" << std::endl;
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
//update buffer sizes
|
//update buffer sizes
|
||||||
m_BufferSizes.clear();
|
m_BufferSizes.clear();
|
||||||
bool useDefaultBuffers = true;
|
bool useDefaultBuffers = true;
|
||||||
PaError paErr = paNoError;
|
|
||||||
|
|
||||||
//sometimes devices change buffer size if sample rate changes
|
|
||||||
//it updates buffer size during stream opening
|
|
||||||
//we need to find out how device would behave with current sample rate
|
|
||||||
//try opening test stream to load device driver for current sample rate and buffer size
|
|
||||||
//(skip this step if the device is Active)
|
|
||||||
if ( !Active() )
|
|
||||||
{
|
|
||||||
if (paNoError != testStateValidness(m_CurrentSamplingRate, m_CurrentBufferSize) )
|
|
||||||
{
|
|
||||||
//buffer size did change
|
|
||||||
Pa_Terminate();
|
|
||||||
Pa_Initialize();
|
|
||||||
|
|
||||||
// test validness with current sample rate and device prefered buffer size
|
|
||||||
paErr = testStateValidness(m_CurrentSamplingRate, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (paErr == paNoError)
|
|
||||||
{
|
|
||||||
// In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
|
// In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
|
||||||
long minSize, maxSize, preferredSize, granularity;
|
long minSize, maxSize, preferredSize, granularity;
|
||||||
paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
|
PaError err = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
|
||||||
|
|
||||||
if (paErr == paNoError)
|
if (err == paNoError)
|
||||||
{
|
{
|
||||||
std::cout << "API::Device " << m_DeviceName << " Buffers: " << minSize << " " << maxSize << " " << preferredSize << std::endl;
|
std::cout << "API::Device " << m_DeviceName << " Buffers: " << minSize << " " << maxSize << " " << preferredSize << std::endl;
|
||||||
|
|
||||||
|
|
@ -389,11 +366,6 @@ void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
|
||||||
{
|
{
|
||||||
std::cout << "API::Device" << m_DeviceName << " Preffered buffer size is not supported" << std::endl;
|
std::cout << "API::Device" << m_DeviceName << " Preffered buffer size is not supported" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cout << "API::Device" << m_DeviceName << " Device does not start with sample rate: "<< m_CurrentSamplingRate << " and default buffer size" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useDefaultBuffers)
|
if (useDefaultBuffers)
|
||||||
{
|
{
|
||||||
|
|
@ -475,18 +447,18 @@ PaError WCMRPortAudioDevice::testStateValidness(int sampleRate, int bufferSize)
|
||||||
PaStreamParameters *pInS = NULL, *pOutS = NULL;
|
PaStreamParameters *pInS = NULL, *pOutS = NULL;
|
||||||
|
|
||||||
inputParameters.device = m_DeviceID;
|
inputParameters.device = m_DeviceID;
|
||||||
inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
|
inputParameters.channelCount = pDeviceInfo->maxInputChannels;
|
||||||
inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
|
inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
|
||||||
inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
|
inputParameters.suggestedLatency = 0;
|
||||||
inputParameters.hostApiSpecificStreamInfo = 0;
|
inputParameters.hostApiSpecificStreamInfo = 0;
|
||||||
|
|
||||||
if (inputParameters.channelCount)
|
if (inputParameters.channelCount)
|
||||||
pInS = &inputParameters;
|
pInS = &inputParameters;
|
||||||
|
|
||||||
outputParameters.device = m_DeviceID;
|
outputParameters.device = m_DeviceID;
|
||||||
outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
|
outputParameters.channelCount = pDeviceInfo->maxOutputChannels;
|
||||||
outputParameters.sampleFormat = paFloat32;
|
outputParameters.sampleFormat = paFloat32;
|
||||||
outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
|
outputParameters.suggestedLatency = 0;
|
||||||
outputParameters.hostApiSpecificStreamInfo = 0;
|
outputParameters.hostApiSpecificStreamInfo = 0;
|
||||||
|
|
||||||
if (outputParameters.channelCount)
|
if (outputParameters.channelCount)
|
||||||
|
|
@ -498,7 +470,7 @@ PaError WCMRPortAudioDevice::testStateValidness(int sampleRate, int bufferSize)
|
||||||
//it updates buffer size during stream opening
|
//it updates buffer size during stream opening
|
||||||
//we need to find out how device would behave with current sample rate
|
//we need to find out how device would behave with current sample rate
|
||||||
//try opening test stream to load device driver for current sample rate and buffer size
|
//try opening test stream to load device driver for current sample rate and buffer size
|
||||||
paErr = Pa_OpenStream (&portAudioStream, pInS, pOutS, m_CurrentSamplingRate, m_CurrentBufferSize, paDitherOff, NULL, NULL);
|
paErr = Pa_OpenStream (&portAudioStream, pInS, pOutS, sampleRate, bufferSize, paDitherOff, NULL, NULL);
|
||||||
|
|
||||||
if (portAudioStream)
|
if (portAudioStream)
|
||||||
{
|
{
|
||||||
|
|
@ -627,35 +599,17 @@ WTErr WCMRPortAudioDevice::SetCurrentSamplingRate (int newRate)
|
||||||
return (retVal);
|
return (retVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldActive)
|
|
||||||
{
|
|
||||||
//Deactivate it for the change...
|
|
||||||
SetActive (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
//make the change...
|
//make the change...
|
||||||
m_CurrentSamplingRate = newRate;
|
m_CurrentSamplingRate = newRate;
|
||||||
|
PaError paErr = PaAsio_SetStreamSampleRate (m_PortAudioStream, m_CurrentSamplingRate);
|
||||||
|
|
||||||
// Before reactivating the device: opening stream we should try getting buffer size update from the device
|
if (paErr != paNoError)
|
||||||
// because for new sampling rate some devices may change buffer size as well
|
|
||||||
int oldBufferSize = m_CurrentBufferSize;
|
|
||||||
|
|
||||||
retVal = ResetDevice();
|
|
||||||
|
|
||||||
//reactivate it.
|
|
||||||
if (oldActive && retVal == eNoErr)
|
|
||||||
{
|
{
|
||||||
retVal = SetActive (true);
|
std::cout << "Sample rate change failed, cannot start with error: " << Pa_GetErrorText (paErr) << std::endl;
|
||||||
}
|
if (paErr == paUnanticipatedHostError)
|
||||||
|
std::cout << "Details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl;
|
||||||
|
|
||||||
if (retVal != eNoErr)
|
retVal = eWrongObjectState;
|
||||||
{
|
|
||||||
//revert changes if the device was not activated
|
|
||||||
m_CurrentSamplingRate = oldRate;
|
|
||||||
m_CurrentBufferSize = oldBufferSize;
|
|
||||||
int bufferSize = m_CurrentBufferSize;
|
|
||||||
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
|
|
||||||
retVal = eCommandLineParameter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (retVal);
|
return (retVal);
|
||||||
|
|
@ -704,6 +658,15 @@ WTErr WCMRPortAudioDevice::SetCurrentBufferSize (int newSize)
|
||||||
if (oldSize == newSize)
|
if (oldSize == newSize)
|
||||||
return (retVal);
|
return (retVal);
|
||||||
|
|
||||||
|
if (Streaming())
|
||||||
|
{
|
||||||
|
//Can't change, perhaps use an "in use" type of error
|
||||||
|
retVal = eGenericErr;
|
||||||
|
return (retVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Setting buffer: " << newSize << std::endl;
|
||||||
|
|
||||||
//see if this is one of our supported rates...
|
//see if this is one of our supported rates...
|
||||||
intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
|
intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
|
||||||
if (intIter == m_BufferSizes.end())
|
if (intIter == m_BufferSizes.end())
|
||||||
|
|
@ -713,10 +676,12 @@ WTErr WCMRPortAudioDevice::SetCurrentBufferSize (int newSize)
|
||||||
{
|
{
|
||||||
// we have only one aloved buffer size which is preffered by PA
|
// we have only one aloved buffer size which is preffered by PA
|
||||||
// this is the only value which could be set
|
// this is the only value which could be set
|
||||||
m_CurrentBufferSize = m_BufferSizes[0];
|
newSize = m_BufferSizes[0];
|
||||||
int bufferSize = m_CurrentBufferSize;
|
int bufferSize = newSize;
|
||||||
// notify client to update sample rate after us
|
// notify client to update sample rate after us
|
||||||
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
|
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
|
||||||
|
return retVal;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// more then one buffer size value is available
|
// more then one buffer size value is available
|
||||||
//Can't change, perhaps use an "invalid param" type of error
|
//Can't change, perhaps use an "invalid param" type of error
|
||||||
|
|
@ -725,13 +690,6 @@ WTErr WCMRPortAudioDevice::SetCurrentBufferSize (int newSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Streaming())
|
|
||||||
{
|
|
||||||
//Can't change, perhaps use an "in use" type of error
|
|
||||||
retVal = eGenericErr;
|
|
||||||
return (retVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldActive)
|
if (oldActive)
|
||||||
{
|
{
|
||||||
//Deactivate it for the change...
|
//Deactivate it for the change...
|
||||||
|
|
@ -788,6 +746,59 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
|
||||||
// if device is not active activate it
|
// if device is not active activate it
|
||||||
if (!Active() )
|
if (!Active() )
|
||||||
{
|
{
|
||||||
|
std::list<long> buffersSizes;
|
||||||
|
buffersSizes.push_back(m_CurrentBufferSize);
|
||||||
|
|
||||||
|
long minSize, maxSize, preferredSize, granularity;
|
||||||
|
PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
|
||||||
|
|
||||||
|
if (paErr == paNoError)
|
||||||
|
{
|
||||||
|
buffersSizes.push_front(preferredSize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
size_t amountOfBuffers = sizeof(gAllBufferSizes)/sizeof(*gAllBufferSizes);
|
||||||
|
for (int i = 0; i < amountOfBuffers; ++i)
|
||||||
|
{
|
||||||
|
if (minSize <= gAllBufferSizes[i] <= maxSize)
|
||||||
|
{
|
||||||
|
buffersSizes.push_back(gAllBufferSizes[i]);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// test validness with current sample rate and device prefered buffer size
|
||||||
|
if (paNoError != (paErr = testStateValidness(m_CurrentSamplingRate, m_CurrentBufferSize) ) )
|
||||||
|
{
|
||||||
|
std::cout << "State has changed, cannot start with error: " << Pa_GetErrorText (paErr) << std::endl;
|
||||||
|
if (paErr == paUnanticipatedHostError)
|
||||||
|
std::cout << "Details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Updating state... " << std::endl;
|
||||||
|
// update device info
|
||||||
|
updateDeviceInfo();
|
||||||
|
|
||||||
|
// pick up buffers we'll need to try
|
||||||
|
long minSize, maxSize, preferredSize, granularity;
|
||||||
|
PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
|
||||||
|
|
||||||
|
if (paErr == paNoError)
|
||||||
|
{
|
||||||
|
buffersSizes.push_front(preferredSize);
|
||||||
|
|
||||||
|
size_t amountOfBuffers = sizeof(gAllBufferSizes)/sizeof(*gAllBufferSizes);
|
||||||
|
for (int i = 0; i < amountOfBuffers; ++i)
|
||||||
|
{
|
||||||
|
if (minSize <= gAllBufferSizes[i] <= maxSize)
|
||||||
|
{
|
||||||
|
buffersSizes.push_back(gAllBufferSizes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "**********Tested VALIDNESS*********** " << Pa_GetErrorText (paErr) << std::endl;*/
|
||||||
|
|
||||||
PaStreamParameters inputParameters, outputParameters;
|
PaStreamParameters inputParameters, outputParameters;
|
||||||
PaStreamParameters *pInS = NULL, *pOutS = NULL;
|
PaStreamParameters *pInS = NULL, *pOutS = NULL;
|
||||||
|
|
||||||
|
|
@ -812,11 +823,12 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
|
||||||
if (outputParameters.channelCount)
|
if (outputParameters.channelCount)
|
||||||
pOutS = &outputParameters;
|
pOutS = &outputParameters;
|
||||||
|
|
||||||
std::cout << "API::Device" << m_DeviceName << " Opening device stream " << std::endl;
|
// try opening stream with current buffer and the rest if not successful
|
||||||
std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << m_CurrentBufferSize << std::endl;
|
std::list<long>::const_iterator bufferIter = buffersSizes.begin();
|
||||||
|
for (; bufferIter != buffersSizes.end(); ++bufferIter) {
|
||||||
|
|
||||||
int tryAgain = ((PROPERTY_CHANGE_TIMEOUT_SECONDS * 1000) / PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS) ;
|
std::cout << "API::Device" << m_DeviceName << " Opening device stream " << std::endl;
|
||||||
while (tryAgain) {
|
std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << *bufferIter << std::endl;
|
||||||
paErr = Pa_OpenStream(&m_PortAudioStream,
|
paErr = Pa_OpenStream(&m_PortAudioStream,
|
||||||
pInS,
|
pInS,
|
||||||
pOutS,
|
pOutS,
|
||||||
|
|
@ -825,20 +837,37 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
|
||||||
paDitherOff,
|
paDitherOff,
|
||||||
WCMRPortAudioDevice::TheCallback,
|
WCMRPortAudioDevice::TheCallback,
|
||||||
this);
|
this);
|
||||||
|
|
||||||
if(paErr == paNoError)
|
if(paErr == paNoError)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Cannot open streamm sleeping for "<< PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS << "msec and trying again" << std::endl;
|
std::cout << "Cannot open streamm with buffer: "<< *bufferIter << " Error: " << Pa_GetErrorText (paErr) << std::endl;
|
||||||
|
|
||||||
// sleep and try again
|
if (paErr == paUnanticipatedHostError)
|
||||||
wvThread::sleep_milliseconds (PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS);
|
std::cout << "Error details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl;
|
||||||
--tryAgain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(paErr == paNoError)
|
if(paErr == paNoError)
|
||||||
{
|
{
|
||||||
|
std::cout << "***************Stream has been opened ****************************"<< std::endl;
|
||||||
|
|
||||||
|
long minSize, maxSize, preferredSize, granularity;
|
||||||
|
PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
|
||||||
|
|
||||||
|
if (paErr == paNoError && m_CurrentBufferSize != preferredSize)
|
||||||
|
{
|
||||||
|
std::cout << "***************Buffer changed ****************************"<< std::endl;
|
||||||
|
m_CurrentBufferSize = preferredSize;
|
||||||
|
m_BufferSizes.clear();
|
||||||
|
m_BufferSizes.push_back(preferredSize);
|
||||||
|
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&preferredSize);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
std::cout << "***************Buffer DIDn't changed ****************************"<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
m_DropsDetected = 0;
|
m_DropsDetected = 0;
|
||||||
m_DropsReported = 0;
|
m_DropsReported = 0;
|
||||||
m_IgnoreThisDrop = true;
|
m_IgnoreThisDrop = true;
|
||||||
|
|
@ -860,8 +889,8 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//failed, do not update device state
|
//failed, do not update device state
|
||||||
std::cout << "Failed to open pa stream " << paErr << std::endl;
|
std::cout << "Failed to open pa stream: " << Pa_GetErrorText (paErr) << std::endl;
|
||||||
DEBUG_MSG( "Failed to open pa stream " << paErr );
|
DEBUG_MSG( "Failed to open pa stream: " << Pa_GetErrorText (paErr) );
|
||||||
m_ConnectionStatus = DeviceErrors;
|
m_ConnectionStatus = DeviceErrors;
|
||||||
m_lastErr = eAsioFailed;
|
m_lastErr = eAsioFailed;
|
||||||
}
|
}
|
||||||
|
|
@ -921,8 +950,8 @@ void WCMRPortAudioDevice::deactivateDevice (bool callerIsWaiting/*=false*/)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//failed, do not update device state
|
//failed, do not update device state
|
||||||
std::cout << "Failed to close pa stream stream " << paErr << std::endl;
|
std::cout << "Failed to close pa stream stream " << Pa_GetErrorText (paErr) << std::endl;
|
||||||
DEBUG_MSG( "Failed to open pa stream stream " << paErr );
|
DEBUG_MSG( "Failed to open pa stream stream " << Pa_GetErrorText (paErr) );
|
||||||
m_ConnectionStatus = DeviceErrors;
|
m_ConnectionStatus = DeviceErrors;
|
||||||
m_lastErr = eAsioFailed;
|
m_lastErr = eAsioFailed;
|
||||||
}
|
}
|
||||||
|
|
@ -953,17 +982,25 @@ void WCMRPortAudioDevice::startStreaming (bool callerIsWaiting/*=false*/)
|
||||||
m_SampleCounter = 0;
|
m_SampleCounter = 0;
|
||||||
|
|
||||||
std::cout << "API::Device" << m_DeviceName << " Starting device stream" << std::endl;
|
std::cout << "API::Device" << m_DeviceName << " Starting device stream" << std::endl;
|
||||||
|
|
||||||
|
//get device info
|
||||||
|
const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
|
||||||
|
|
||||||
|
unsigned int inChannelCount = pDeviceInfo->maxInputChannels;
|
||||||
|
unsigned int outChannelCount = pDeviceInfo->maxOutputChannels;
|
||||||
|
|
||||||
paErr = Pa_StartStream( m_PortAudioStream );
|
paErr = Pa_StartStream( m_PortAudioStream );
|
||||||
|
|
||||||
if(paErr == paNoError)
|
if(paErr == paNoError)
|
||||||
{
|
{
|
||||||
// if the stream was started successfully
|
// if the stream was started successfully
|
||||||
m_IsStreaming = true;
|
m_IsStreaming = true;
|
||||||
|
std::cout << "API::Device" << m_DeviceName << " Device is streaming" << std::endl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout << "Failed to start PA stream: " << paErr << std::endl;
|
std::cout << "Failed to start PA stream: " << Pa_GetErrorText (paErr) << std::endl;
|
||||||
DEBUG_MSG( "Failed to start PA stream: " << paErr );
|
DEBUG_MSG( "Failed to start PA stream: " << Pa_GetErrorText (paErr) );
|
||||||
m_lastErr = eGenericErr;
|
m_lastErr = eGenericErr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1001,8 +1038,8 @@ void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout << "Failed to stop PA stream: " << paErr << std::endl;
|
std::cout << "Failed to stop PA stream: " << Pa_GetErrorText (paErr) << std::endl;
|
||||||
DEBUG_MSG( "Failed to stop PA stream " << paErr );
|
DEBUG_MSG( "Failed to stop PA stream " << Pa_GetErrorText (paErr) );
|
||||||
m_lastErr = eGenericErr;
|
m_lastErr = eGenericErr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1027,6 +1064,8 @@ void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ )
|
||||||
{
|
{
|
||||||
std::cout << "API::Device" << m_DeviceName << "Reseting device" << std::endl;
|
std::cout << "API::Device" << m_DeviceName << "Reseting device" << std::endl;
|
||||||
|
|
||||||
|
PaError paErr = paNoError;
|
||||||
|
|
||||||
// Keep device sates
|
// Keep device sates
|
||||||
bool wasStreaming = Streaming();
|
bool wasStreaming = Streaming();
|
||||||
bool wasActive = Active();
|
bool wasActive = Active();
|
||||||
|
|
@ -1035,31 +1074,50 @@ void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ )
|
||||||
stopStreaming();
|
stopStreaming();
|
||||||
deactivateDevice();
|
deactivateDevice();
|
||||||
|
|
||||||
|
// Cache device buffer size as it might be changed during reset
|
||||||
|
int oldBufferSize = m_CurrentBufferSize;
|
||||||
|
|
||||||
|
// Now, validate the state and update device info if required
|
||||||
|
unsigned int retry = PROPERTY_CHANGE_RETRIES;
|
||||||
|
while (retry-- )
|
||||||
|
{
|
||||||
// Reinitialize PA
|
// Reinitialize PA
|
||||||
Pa_Terminate();
|
Pa_Terminate();
|
||||||
Pa_Initialize();
|
Pa_Initialize();
|
||||||
|
|
||||||
|
std::cout << "Updating device state... " << std::endl;
|
||||||
|
// update device info
|
||||||
updateDeviceInfo();
|
updateDeviceInfo();
|
||||||
|
|
||||||
// Cache device buffer size as it might be changed during reset
|
// take up buffers
|
||||||
int oldBufferSize = m_CurrentBufferSize;
|
|
||||||
|
|
||||||
// In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
|
|
||||||
// Backend should always use preffered buffer size value in this case
|
|
||||||
long minSize, maxSize, preferredSize, granularity;
|
long minSize, maxSize, preferredSize, granularity;
|
||||||
PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
|
PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
|
||||||
|
|
||||||
if (paErr == paNoError)
|
if (paErr != paNoError)
|
||||||
{
|
{
|
||||||
m_CurrentBufferSize = preferredSize;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
m_CurrentBufferSize = preferredSize;
|
||||||
|
|
||||||
|
paErr = testStateValidness(m_CurrentSamplingRate, m_CurrentBufferSize);
|
||||||
|
if (paNoError == paErr)
|
||||||
{
|
{
|
||||||
// if we can't get device buffer sizes, use the first one among supported
|
std::cout << "Device state is valid" << std::endl;
|
||||||
if (m_BufferSizes.size() != 0)
|
break;
|
||||||
m_CurrentBufferSize = m_BufferSizes.front();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << "Cannot start with current state: sr: " << m_CurrentSamplingRate << " bs:" << m_CurrentBufferSize \
|
||||||
|
<< "\nReason: " << Pa_GetErrorText (paErr) << std::endl;
|
||||||
|
if (paErr == paUnanticipatedHostError)
|
||||||
|
std::cout << "Details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Will try again in " << PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS << "msec" << std::endl;
|
||||||
|
|
||||||
|
Pa_Sleep(PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paErr == paNoError)
|
||||||
|
{
|
||||||
// Notify the Application about device setting changes
|
// Notify the Application about device setting changes
|
||||||
if (oldBufferSize != m_CurrentBufferSize)
|
if (oldBufferSize != m_CurrentBufferSize)
|
||||||
{
|
{
|
||||||
|
|
@ -1073,12 +1131,16 @@ void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ )
|
||||||
activateDevice();
|
activateDevice();
|
||||||
|
|
||||||
// Resume streaming if the device was streaming before
|
// Resume streaming if the device was streaming before
|
||||||
if(wasStreaming)
|
if(wasStreaming && m_lastErr == eNoErr && m_ConnectionStatus == DeviceAvailable)
|
||||||
{
|
{
|
||||||
// Notify the Application to prepare for the stream start
|
// Notify the Application to prepare for the stream start
|
||||||
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming);
|
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming);
|
||||||
startStreaming();
|
startStreaming();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
m_ConnectionStatus = DeviceErrors;
|
||||||
|
m_lastErr = eWrongObjectState;
|
||||||
|
}
|
||||||
|
|
||||||
if (callerIsWaiting)
|
if (callerIsWaiting)
|
||||||
SetEvent(m_hResetDone);
|
SetEvent(m_hResetDone);
|
||||||
|
|
@ -1553,6 +1615,8 @@ WTErr WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceI
|
||||||
sampleRates.push_back ((int)gAllSampleRates[sr]);
|
sampleRates.push_back ((int)gAllSampleRates[sr]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return eNoErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1695,6 +1759,12 @@ WTErr WCMRPortAudioDeviceManager::getDeviceSampleRatesImpl(const std::string & d
|
||||||
|
|
||||||
WTErr retVal = eNoErr;
|
WTErr retVal = eNoErr;
|
||||||
|
|
||||||
|
if (m_CurrentDevice && deviceName == m_CurrentDevice->DeviceName() )
|
||||||
|
{
|
||||||
|
sampleRates.assign(m_CurrentDevice->SamplingRates().begin(), m_CurrentDevice->SamplingRates().end() );
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
DeviceInfo devInfo;
|
DeviceInfo devInfo;
|
||||||
retVal = GetDeviceInfoByName(deviceName, devInfo);
|
retVal = GetDeviceInfoByName(deviceName, devInfo);
|
||||||
|
|
||||||
|
|
@ -1715,28 +1785,23 @@ WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & d
|
||||||
{
|
{
|
||||||
WTErr retVal = eNoErr;
|
WTErr retVal = eNoErr;
|
||||||
std::cout << "API::PortAudioDeviceManager::GetBufferSizes: getting buffer size for device: "<< deviceName << std::endl;
|
std::cout << "API::PortAudioDeviceManager::GetBufferSizes: getting buffer size for device: "<< deviceName << std::endl;
|
||||||
|
|
||||||
|
buffers.clear();
|
||||||
|
|
||||||
//first check if the request has been made for None device
|
//first check if the request has been made for None device
|
||||||
if (deviceName == m_NoneDevice->DeviceName() )
|
if (deviceName == m_NoneDevice->DeviceName() )
|
||||||
{
|
{
|
||||||
buffers = m_NoneDevice->BufferSizes();
|
buffers.assign(m_NoneDevice->BufferSizes().begin(), m_NoneDevice->BufferSizes().end() );
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if we have current device initialized and it's PA device, reset it
|
if (m_CurrentDevice && deviceName == m_CurrentDevice->DeviceName() )
|
||||||
//this procedure will reset PA corrently and update info for all PA devices as well
|
{
|
||||||
|
buffers.assign(m_CurrentDevice->BufferSizes().begin(), m_CurrentDevice->BufferSizes().end() );
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
bool paLocalInit = false;
|
|
||||||
WCMRPortAudioDevice* portaudioDevice = dynamic_cast<WCMRPortAudioDevice*>(m_CurrentDevice);
|
|
||||||
if (portaudioDevice)
|
|
||||||
{
|
|
||||||
portaudioDevice->ResetDevice();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//initialize PA to get buffers for the device
|
|
||||||
Pa_Initialize();
|
Pa_Initialize();
|
||||||
paLocalInit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceInfo devInfo;
|
DeviceInfo devInfo;
|
||||||
retVal = GetDeviceInfoByName(deviceName, devInfo);
|
retVal = GetDeviceInfoByName(deviceName, devInfo);
|
||||||
|
|
@ -1755,7 +1820,7 @@ WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & d
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
retVal = eAsioFailed;
|
retVal = eAsioFailed;
|
||||||
std::cout << "API::PortAudioDeviceManager::GetBufferSizes: error: " << paErr << " getting buffer size fo device: "<< deviceName << std::endl;
|
std::cout << "API::PortAudioDeviceManager::GetBufferSizes: error: " << Pa_GetErrorText (paErr) << " getting buffer size fo device: "<< deviceName << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1763,8 +1828,6 @@ WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & d
|
||||||
std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl;
|
std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
//deinitialize PA now
|
|
||||||
if (paLocalInit)
|
|
||||||
Pa_Terminate();
|
Pa_Terminate();
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue