[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,11 +124,21 @@ 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) { if (_input_pm_stream) {
Pm_Close (_input_pm_stream); PmError err = Pm_Close (_input_pm_stream);
if (err != pmNoError) {
std::cerr << "WavesMidiDevice::close (): Pm_Close () failed for " << _pm_input_id << "-[" << name () << "]!" << std::endl;
char* err_msg = new char[256];
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)) { while (1 == Pm_Dequeue (_input_queue, &waves_midi_event)) {
delete waves_midi_event; // XXX possible dup free in ~WavesMidiBuffer() (?) delete waves_midi_event; // XXX possible dup free in ~WavesMidiBuffer() (?)
} }
@ -141,10 +151,21 @@ WavesMidiDevice::close ()
if ( _output_pm_stream ) { if ( _output_pm_stream ) {
Pm_Close (_output_pm_stream); PmError err = Pm_Close (_output_pm_stream);
if (err != pmNoError) {
std::cerr << "WavesMidiDevice::close (): Pm_Close () failed for " << _pm_output_id << "-[" << name () << "]!" << std::endl;
char* err_msg = new char[256];
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)) { while (1 == Pm_Dequeue (_output_queue, &waves_midi_event)) {
delete waves_midi_event; // XXX possible dup free in ~WavesMidiBuffer() (?) delete waves_midi_event; // XXX possible dup free in ~WavesMidiBuffer() (?)
} }
Pm_QueueDestroy (_output_queue); Pm_QueueDestroy (_output_queue);
_output_queue = NULL; _output_queue = NULL;
_output_pm_stream = NULL; _output_pm_stream = NULL;

View file

@ -606,6 +606,7 @@ 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
if (m_BufferSizes.size() == 1)
{ {
// 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
newSize = m_BufferSizes[0]; newSize = m_BufferSizes[0];
int bufferSize = newSize; int bufferSize = newSize;
// notify client to update sample rate after us // notify client to update buffer size
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize); m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
return retVal; 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,12 +741,8 @@ 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::list<long>::const_iterator bufferIter = buffersSizes.begin();
for (; bufferIter != buffersSizes.end(); ++bufferIter) {
std::cout << "API::Device " << m_DeviceName << " Opening device stream " << std::endl; std::cout << "API::Device " << m_DeviceName << " Opening device stream " << std::endl;
std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << *bufferIter << std::endl; std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << m_CurrentBufferSize << std::endl;
paErr = Pa_OpenStream(&m_PortAudioStream, paErr = Pa_OpenStream(&m_PortAudioStream,
pInS, pInS,
pOutS, pOutS,
@ -801,12 +752,9 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
WCMRPortAudioDevice::TheCallback, WCMRPortAudioDevice::TheCallback,
this); 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,20 @@ 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
m_IsStreaming = false;
m_pInputData = NULL;
}
else
{
std::cout << "Failed to stop PA stream normaly! Aborting the stream. Error:" << Pa_GetErrorText (paErr) << std::endl;
DEBUG_MSG( "Failed to stop PA stream normaly! Aborting the stream. Error:" << Pa_GetErrorText (paErr) );
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 // if the stream was stopped successfully
m_IsStreaming = false; m_IsStreaming = false;
@ -1000,6 +969,7 @@ void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/)
m_lastErr = eGenericErr; m_lastErr = eGenericErr;
} }
} }
}
if (callerIsWaiting) if (callerIsWaiting)
SetEvent(m_hStopStreamingDone); SetEvent(m_hStopStreamingDone);
@ -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