[Summary] Added actions to handle abnormal behavior during stream stop for MIDI and Audio devices.

Made correct error handling for cases we didn't see before.
Removed redundant and experimental code I forgot to remove months ago.
Added debug output which will help in future testing

Conflicts:
	libs/ardour/ardour/audioengine.h
	libs/ardour/engine_state_controller.cc
	libs/backends/wavesaudio/waves_midi_device.cc
This commit is contained in:
Greg Zharun 2015-02-28 18:38:45 +02:00 committed by Paul Davis
parent ce069da682
commit a2f82f8c5d
4 changed files with 99 additions and 105 deletions

View file

@ -104,6 +104,7 @@ class LIBARDOUR_API AudioEngine : public SessionHandlePtr, public PortManager
bool in_process_thread (); bool in_process_thread ();
uint32_t process_thread_count (); uint32_t process_thread_count ();
int backend_reset_requested();
void request_backend_reset(); void request_backend_reset();
void request_device_list_update(); void request_device_list_update();
void launch_device_control_app(); void launch_device_control_app();

View file

@ -394,6 +394,11 @@ AudioEngine::request_backend_reset()
_hw_reset_condition.signal (); _hw_reset_condition.signal ();
} }
int
AudioEngine::backend_reset_requested()
{
return g_atomic_int_get (&_hw_reset_request_count);
}
void void
AudioEngine::do_reset_backend() AudioEngine::do_reset_backend()
@ -409,7 +414,6 @@ AudioEngine::do_reset_backend()
_reset_request_lock.unlock(); _reset_request_lock.unlock();
Glib::Threads::RecMutex::Lock pl (_state_lock); 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);
std::cout << "AudioEngine::RESET::Reset request processing" << std::endl; std::cout << "AudioEngine::RESET::Reset request processing" << std::endl;

View file

@ -124,32 +124,53 @@ WavesMidiDevice::open (PmTimeProcPtr time_proc, void* time_info)
void void
WavesMidiDevice::close () WavesMidiDevice::close ()
{ {
// COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::close ():" << name () << std::endl; DEBUG_TRACE (DEBUG::WavesMIDI, string_compose ("WavesMidiDevice::close (): %1\n", name ()));
WavesMidiEvent *waves_midi_event; WavesMidiEvent *waves_midi_event;
if (_input_pm_stream) {
PmError err = Pm_Close (_input_pm_stream);
if (_input_pm_stream) { if (err != pmNoError) {
Pm_Close (_input_pm_stream); std::cerr << "WavesMidiDevice::close (): Pm_Close () failed for " << _pm_input_id << "-[" << name () << "]!" << std::endl;
while (1 == Pm_Dequeue (_input_queue, &waves_midi_event)) { char* err_msg = new char[256];
delete waves_midi_event; // XXX possible dup free in ~WavesMidiBuffer() (?) Pm_GetHostErrorText(err_msg, 256);
std::cerr << "Error: " << err_msg << std::endl;
std::cerr << "Aborting!" << std::endl;
Pm_Abort (_input_pm_stream);
}
while (1 == Pm_Dequeue (_input_queue, &waves_midi_event)) {
delete waves_midi_event; // XXX possible dup free in ~WavesMidiBuffer() (?)
}
Pm_QueueDestroy (_input_queue);
_input_queue = NULL;
_input_pm_stream = NULL;
_pm_input_id = pmNoDevice;
} }
if ( _output_pm_stream ) {
PmError err = Pm_Close (_output_pm_stream);
Pm_QueueDestroy (_input_queue); if (err != pmNoError) {
_input_queue = NULL; std::cerr << "WavesMidiDevice::close (): Pm_Close () failed for " << _pm_output_id << "-[" << name () << "]!" << std::endl;
_input_pm_stream = NULL; char* err_msg = new char[256];
_pm_input_id = pmNoDevice; Pm_GetHostErrorText(err_msg, 256);
} std::cerr << "Error: " << err_msg << std::endl;
std::cerr << "Aborting!" << std::endl;
Pm_Abort (_output_pm_stream);
}
while (1 == Pm_Dequeue (_output_queue, &waves_midi_event)) {
delete waves_midi_event; // XXX possible dup free in ~WavesMidiBuffer() (?)
}
Pm_QueueDestroy (_output_queue);
if ( _output_pm_stream ) { _output_queue = NULL;
Pm_Close (_output_pm_stream); _output_pm_stream = NULL;
while (1 == Pm_Dequeue (_output_queue, &waves_midi_event)) { _pm_output_id = pmNoDevice;
delete waves_midi_event; // XXX possible dup free in ~WavesMidiBuffer() (?)
} }
Pm_QueueDestroy (_output_queue);
_output_queue = NULL;
_output_pm_stream = NULL;
_pm_output_id = pmNoDevice;
}
} }
void void

View file

@ -605,7 +605,8 @@ WTErr WCMRPortAudioDevice::SetCurrentSamplingRate (int newRate)
//make the change... //make the change...
m_CurrentSamplingRate = newRate; m_CurrentSamplingRate = newRate;
PaError paErr = PaAsio_SetStreamSampleRate (m_PortAudioStream, m_CurrentSamplingRate); PaError paErr = PaAsio_SetStreamSampleRate (m_PortAudioStream, m_CurrentSamplingRate);
std::cout << "Sleeping after sample rate change " << std::endl;
Pa_Sleep(PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS); // sleep some time to make sure the change has place Pa_Sleep(PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS); // sleep some time to make sure the change has place
if (paErr != paNoError) if (paErr != paNoError)
@ -655,14 +656,6 @@ WTErr WCMRPortAudioDevice::SetCurrentBufferSize (int newSize)
WTErr retVal = eNoErr; WTErr retVal = eNoErr;
std::vector<int>::iterator intIter; std::vector<int>::iterator intIter;
//changes the status.
int oldSize = CurrentBufferSize();
bool oldActive = Active();
//same size, nothing to do.
if (oldSize == newSize)
return (retVal);
if (Streaming()) if (Streaming())
{ {
//Can't change, perhaps use an "in use" type of error //Can't change, perhaps use an "in use" type of error
@ -670,44 +663,17 @@ WTErr WCMRPortAudioDevice::SetCurrentBufferSize (int newSize)
return (retVal); return (retVal);
} }
std::cout << "Setting buffer: " << newSize << std::endl; // Buffer size for ASIO devices can be changed from the control panel only
// We have driver driven logi here
//see if this is one of our supported rates... if (m_CurrentBufferSize != newSize )
intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
if (intIter == m_BufferSizes.end())
{ {
//Sample rate proposed by client is not supported any more // we have only one aloved buffer size which is preffered by PA
if (m_BufferSizes.size() == 1) // this is the only value which could be set
{ newSize = m_BufferSizes[0];
// we have only one aloved buffer size which is preffered by PA int bufferSize = newSize;
// this is the only value which could be set // notify client to update buffer size
newSize = m_BufferSizes[0]; m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
int bufferSize = newSize; return retVal;
// notify client to update sample rate after us
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
return retVal;
} else {
// more then one buffer size value is available
//Can't change, perhaps use an "invalid param" type of error
retVal = eCommandLineParameter;
return (retVal);
}
}
if (oldActive)
{
//Deactivate it for the change...
SetActive (false);
}
//make the change...
m_CurrentBufferSize = newSize;
//reactivate it.
if (oldActive)
{
retVal = SetActive (true);
} }
return (retVal); return (retVal);
@ -751,17 +717,6 @@ 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);
}
PaStreamParameters inputParameters, outputParameters; PaStreamParameters inputParameters, outputParameters;
PaStreamParameters *pInS = NULL, *pOutS = NULL; PaStreamParameters *pInS = NULL, *pOutS = NULL;
@ -786,27 +741,20 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
if (outputParameters.channelCount) if (outputParameters.channelCount)
pOutS = &outputParameters; pOutS = &outputParameters;
// try opening stream with current buffer and the rest if not successful std::cout << "API::Device " << m_DeviceName << " Opening device stream " << std::endl;
std::list<long>::const_iterator bufferIter = buffersSizes.begin(); std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << m_CurrentBufferSize << std::endl;
for (; bufferIter != buffersSizes.end(); ++bufferIter) { paErr = Pa_OpenStream(&m_PortAudioStream,
pInS,
std::cout << "API::Device" << m_DeviceName << " Opening device stream " << std::endl; pOutS,
std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << *bufferIter << std::endl; m_CurrentSamplingRate,
paErr = Pa_OpenStream(&m_PortAudioStream, m_CurrentBufferSize,
pInS, paDitherOff,
pOutS, WCMRPortAudioDevice::TheCallback,
m_CurrentSamplingRate, this);
m_CurrentBufferSize,
paDitherOff,
WCMRPortAudioDevice::TheCallback,
this);
if(paErr == paNoError) if(paErr != paNoError)
{ {
break; std::cout << "Cannot open streamm with buffer: "<< m_CurrentBufferSize << " Error: " << Pa_GetErrorText (paErr) << std::endl;
}
std::cout << "Cannot open streamm with buffer: "<< *bufferIter << " Error: " << Pa_GetErrorText (paErr) << std::endl;
if (paErr == paUnanticipatedHostError) if (paErr == paUnanticipatedHostError)
std::cout << "Error details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl; std::cout << "Error details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl;
@ -814,11 +762,16 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
if(paErr == paNoError) if(paErr == paNoError)
{ {
std::cout << "Stream has been opened! "<< std::endl;
// check for possible changes
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);
std::cout << "Checked if buffer size changed "<< std::endl;
if (paErr == paNoError && m_CurrentBufferSize != preferredSize) if (paErr == paNoError && m_CurrentBufferSize != preferredSize)
{ {
std::cout << "Buffer size has changed "<< std::endl;
m_CurrentBufferSize = preferredSize; m_CurrentBufferSize = preferredSize;
m_BufferSizes.clear(); m_BufferSizes.clear();
m_BufferSizes.push_back(preferredSize); m_BufferSizes.push_back(preferredSize);
@ -837,6 +790,7 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
m_ResetReported = 0; m_ResetReported = 0;
m_ResyncRequested = 0; m_ResyncRequested = 0;
m_ResyncReported = 0; m_ResyncReported = 0;
std::cout << "Installing new mesage hook "<< std::endl;
PaAsio_SetMessageHook (StaticASIOMessageHook, this); PaAsio_SetMessageHook (StaticASIOMessageHook, this);
} }
m_IsActive = true; m_IsActive = true;
@ -855,6 +809,8 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
} }
std::cout << "Activation is DONE "<< std::endl;
if (callerIsWaiting) if (callerIsWaiting)
SetEvent(m_hActivationDone); SetEvent(m_hActivationDone);
} }
@ -987,7 +943,7 @@ void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/)
std::cout << "API::Device " << m_DeviceName << " Stopping device stream" << std::endl; std::cout << "API::Device " << m_DeviceName << " Stopping device stream" << std::endl;
paErr = Pa_StopStream( m_PortAudioStream ); paErr = Pa_StopStream( m_PortAudioStream );
if(paErr == paNoError) if(paErr == paNoError || paErr == paStreamIsStopped)
{ {
// if the stream was stopped successfully // if the stream was stopped successfully
m_IsStreaming = false; m_IsStreaming = false;
@ -995,9 +951,23 @@ void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/)
} }
else else
{ {
std::cout << "Failed to stop PA stream: " << Pa_GetErrorText (paErr) << std::endl; std::cout << "Failed to stop PA stream normaly! Aborting the stream. Error:" << Pa_GetErrorText (paErr) << std::endl;
DEBUG_MSG( "Failed to stop PA stream " << Pa_GetErrorText (paErr) ); DEBUG_MSG( "Failed to stop PA stream normaly! Aborting the stream. Error:" << Pa_GetErrorText (paErr) );
m_lastErr = eGenericErr; Pa_Sleep(PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS); // sleep some time to make sure the change has place
PaError abortionError = Pa_AbortStream( m_PortAudioStream );
if(abortionError == paNoError || abortionError == paStreamIsStopped)
{
// if the stream was stopped successfully
m_IsStreaming = false;
m_pInputData = NULL;
}
else
{
std::cout << "Failed to stop PA stream: " << Pa_GetErrorText (paErr) << std::endl;
DEBUG_MSG( "Failed to stop PA stream " << Pa_GetErrorText (paErr) );
m_lastErr = eGenericErr;
}
} }
} }
@ -1019,8 +989,6 @@ void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/)
//********************************************************************************************** //**********************************************************************************************
void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ ) void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ )
{ {
std::cout << "API::Device" << m_DeviceName << "Reseting device" << std::endl;
PaError paErr = paNoError; PaError paErr = paNoError;
// Keep device sates // Keep device sates