From a0bef529dd13367ccbbd17f272a209b29da5feab Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov <lyubomir.marinov@jitsi.org> Date: Wed, 19 Dec 2012 20:08:27 +0000 Subject: [PATCH] Attempts to handle timeouts in Pa_CloseStream more gracefully. --- .../protocol/portaudio/PortAudioStream.java | 86 ++++++++++++++----- 1 file changed, 65 insertions(+), 21 deletions(-) diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/portaudio/PortAudioStream.java b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/portaudio/PortAudioStream.java index 0871f2e5..755cfbe9 100644 --- a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/portaudio/PortAudioStream.java +++ b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/portaudio/PortAudioStream.java @@ -104,7 +104,6 @@ public void didPaUpdateAvailableDeviceList() if (deviceIndex != Pa.paNoDevice) { setDeviceIndex(deviceIndex); - if (start) start(); } @@ -481,36 +480,81 @@ synchronized void setDeviceIndex(int deviceIndex) if (stream != 0) { + /* + * For the sake of completeness, attempt to stop this instance + * before disconnecting it. + */ + if (started) + { + try + { + stop(); + } + catch (IOException ioe) + { + /* + * The exception should have already been logged by the + * method #stop(). Additionally and as said above, we + * attempted it out of courtesy. + */ + } + } + + boolean closed = false; + try { Pa.CloseStream(stream); + closed = true; } - catch (PortAudioException paex) + catch (PortAudioException pae) { - logger.error( - "Failed to close " + getClass().getSimpleName(), - paex); + /* + * The function Pa_CloseStream is not supposed to time out + * under normal execution. However, we have modified it to + * do so under exceptional circumstances on Windows at least + * in order to overcome endless loops related to + * hotplugging. In such a case, presume the native PortAudio + * stream closed in order to maybe avoid a crash at the risk + * of a memory leak. + */ + if (pae.getErrorCode() == Pa.paTimedOut) + closed = true; + + if (!closed) + { + logger.error( + "Failed to close " + getClass().getSimpleName(), + pae); - IOException ioex - = new IOException(paex.getLocalizedMessage()); + IOException ioe + = new IOException(pae.getLocalizedMessage()); - ioex.initCause(paex); - throw ioex; + ioe.initCause(pae); + throw ioe; + } } - stream = 0; - if (inputParameters != 0) + finally { - Pa.StreamParameters_free(inputParameters); - inputParameters = 0; - } + if (closed) + { + stream = 0; - /* - * Make sure this AbstractPullBufferStream asks its DataSource - * for the Format in which it is supposed to output audio data - * next time it's opened instead of using its Format from a - * previous open. - */ - this.format = null; + if (inputParameters != 0) + { + Pa.StreamParameters_free(inputParameters); + inputParameters = 0; + } + + /* + * Make sure this AbstractPullBufferStream asks its + * DataSource for the Format in which it is supposed to + * output audio data the next time it is opened instead + * of using its Format from a previous open. + */ + this.format = null; + } + } } } this.deviceIndex = deviceIndex; -- GitLab