Fix occasional audio interface deadlock (#4450)

This commit is contained in:
Hyunjin Song
2018-07-10 11:13:56 +09:00
committed by GitHub
parent 0f3b41f590
commit f2d68326a7
10 changed files with 38 additions and 16 deletions

View File

@@ -37,7 +37,6 @@
#include <QtCore/QVector>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QMutexLocker>
#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
@@ -108,7 +107,6 @@ private:
bool m_active;
bool m_stopped;
QMutex m_processingMutex;
MidiJack *m_midiClient;
QVector<jack_port_t *> m_outputPorts;

View File

@@ -145,7 +145,6 @@ private:
int m_outBufSize;
bool m_stopped;
QSemaphore m_stopSemaphore;
} ;

View File

@@ -109,6 +109,8 @@ private:
fpp_t m_outBufFramesTotal;
fpp_t m_outBufFrameIndex;
bool m_stopped;
int m_disconnectErr;
void onBackendDisconnect(int err);

View File

@@ -66,6 +66,12 @@ public:
return( element );
}
void waitUntilRead()
{
m_writer_sem.acquire( m_size );
m_writer_sem.release( m_size );
}
bool available()
{
return( m_reader_sem.available() );

View File

@@ -640,7 +640,7 @@ void Mixer::storeAudioDevice()
void Mixer::restoreAudioDevice()
{
if( m_oldAudioDev != NULL )
if( m_oldAudioDev && m_audioDev != m_oldAudioDev )
{
stopProcessing();
delete m_audioDev;
@@ -648,9 +648,9 @@ void Mixer::restoreAudioDevice()
m_audioDev = m_oldAudioDev;
emit sampleRateChanged();
m_oldAudioDev = NULL;
startProcessing();
}
m_oldAudioDev = NULL;
}
@@ -1127,7 +1127,9 @@ void Mixer::fifoWriter::run()
write( buffer );
}
// Let audio backend stop processing
write( NULL );
m_fifo->waitUntilRead();
}

View File

@@ -201,7 +201,6 @@ bool AudioJack::initJackClient()
void AudioJack::startProcessing()
{
QMutexLocker m( &m_processingMutex );
m_stopped = false;
if( m_active || m_client == NULL )
@@ -254,7 +253,6 @@ void AudioJack::startProcessing()
void AudioJack::stopProcessing()
{
QMutexLocker m( &m_processingMutex );
m_stopped = true;
}
@@ -342,7 +340,6 @@ void AudioJack::renamePort( AudioPort * _port )
int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata )
{
QMutexLocker m( &m_processingMutex );
// do midi processing first so that midi input can
// add to the following sound processing
@@ -406,6 +403,7 @@ int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata )
m_framesDoneInCurBuf = 0;
if( !m_framesToDoInCurBuf )
{
m_stopped = true;
break;
}
}

View File

@@ -57,8 +57,7 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, Mixer * _mixer ) :
m_paStream( NULL ),
m_wasPAInitError( false ),
m_outBuf( new surroundSampleFrame[mixer()->framesPerPeriod()] ),
m_outBufPos( 0 ),
m_stopSemaphore( 1 )
m_outBufPos( 0 )
{
_success_ful = false;
@@ -167,8 +166,6 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, Mixer * _mixer ) :
printf( "Input device: '%s' backend: '%s'\n", Pa_GetDeviceInfo( inDevIdx )->name, Pa_GetHostApiInfo( Pa_GetDeviceInfo( inDevIdx )->hostApi )->name );
printf( "Output device: '%s' backend: '%s'\n", Pa_GetDeviceInfo( outDevIdx )->name, Pa_GetHostApiInfo( Pa_GetDeviceInfo( outDevIdx )->hostApi )->name );
m_stopSemaphore.acquire();
// TODO: debug Mixer::pushInputFrames()
//m_supportsCapture = true;
@@ -181,7 +178,6 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, Mixer * _mixer ) :
AudioPortAudio::~AudioPortAudio()
{
stopProcessing();
m_stopSemaphore.release();
if( !m_wasPAInitError )
{
@@ -212,8 +208,7 @@ void AudioPortAudio::stopProcessing()
{
if( m_paStream && Pa_IsStreamActive( m_paStream ) )
{
m_stopSemaphore.acquire();
m_stopped = true;
PaError err = Pa_StopStream( m_paStream );
if( err != paNoError )
@@ -283,7 +278,6 @@ int AudioPortAudio::process_callback(
if( !frames )
{
m_stopped = true;
m_stopSemaphore.release();
memset( _outputBuffer, 0, _framesPerBuffer *
channels() * sizeof(float) );
return paComplete;

View File

@@ -103,6 +103,7 @@ void AudioPulseAudio::startProcessing()
void AudioPulseAudio::stopProcessing()
{
m_quit = true;
stopProcessingThread( this );
}

View File

@@ -168,6 +168,7 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len )
const fpp_t frames = getNextBuffer( m_outBuf );
if( !frames )
{
m_stopped = true;
memset( _buf, 0, _len );
return;
}

View File

@@ -49,6 +49,7 @@ AudioSoundIo::AudioSoundIo( bool & outSuccessful, Mixer * _mixer ) :
m_disconnectErr = 0;
m_outBufFrameIndex = 0;
m_outBufFramesTotal = 0;
m_stopped = true;
m_soundio = soundio_create();
if (!m_soundio)
@@ -210,15 +211,18 @@ void AudioSoundIo::startProcessing()
m_outBuf = new surroundSampleFrame[m_outBufSize];
m_stopped = false;
int err;
if ((err = soundio_outstream_start(m_outstream)))
{
m_stopped = true;
fprintf(stderr, "soundio unable to start stream: %s\n", soundio_strerror(err));
}
}
void AudioSoundIo::stopProcessing()
{
m_stopped = true;
if (m_outstream)
{
soundio_outstream_destroy(m_outstream);
@@ -244,6 +248,7 @@ void AudioSoundIo::underflowCallback()
void AudioSoundIo::writeCallback(int frameCountMin, int frameCountMax)
{
if (m_stopped) {return;}
const struct SoundIoChannelLayout *layout = &m_outstream->layout;
SoundIoChannelArea *areas;
int bytesPerSample = m_outstream->bytes_per_sample;
@@ -265,11 +270,27 @@ void AudioSoundIo::writeCallback(int frameCountMin, int frameCountMax)
if (!frameCount)
break;
if (m_stopped)
{
for (int channel = 0; channel < layout->channel_count; ++channel)
{
memset(areas[channel].ptr, 0, bytesPerSample * frameCount);
areas[channel].ptr += areas[channel].step * frameCount;
}
continue;
}
for (int frame = 0; frame < frameCount; frame += 1)
{
if (m_outBufFrameIndex >= m_outBufFramesTotal)
{
m_outBufFramesTotal = getNextBuffer(m_outBuf);
if (m_outBufFramesTotal == 0)
{
m_stopped = true;
break;
}
m_outBufFrameIndex = 0;
}