diff --git a/lib/native/windows-64/jnportaudio.dll b/lib/native/windows-64/jnportaudio.dll index ea27a7b85161c13abb76064a89582ae7676c0c8d..308e4f2ee1d9d40a0cd81ea2e08ad7af4bc8457b 100644 Binary files a/lib/native/windows-64/jnportaudio.dll and b/lib/native/windows-64/jnportaudio.dll differ diff --git a/lib/native/windows/jnportaudio.dll b/lib/native/windows/jnportaudio.dll index 45b1c9724678c59fe7aac5e9a01b7ec81f03b5c8..5655a2206f16935a4d350b8273682b14941d32d7 100644 Binary files a/lib/native/windows/jnportaudio.dll and b/lib/native/windows/jnportaudio.dll differ diff --git a/src/native/portaudio/org_jitsi_impl_neomedia_portaudio_Pa.c b/src/native/portaudio/org_jitsi_impl_neomedia_portaudio_Pa.c index 1d3914950f392452d7e2c5c23969b36208be7fca..c2b22f54772a9ea55e64d3a9c9e7c815505fea32 100644 --- a/src/native/portaudio/org_jitsi_impl_neomedia_portaudio_Pa.c +++ b/src/native/portaudio/org_jitsi_impl_neomedia_portaudio_Pa.c @@ -1237,28 +1237,31 @@ PortAudio_throwException(JNIEnv *env, PaError err) */ if (clazz) { - /* - * We may be able to provide further details in the case of - * paUnanticipatedHostError by means of PaHostErrorInfo. - */ - if (paUnanticipatedHostError == err) + jmethodID methodID + = (*env)->GetMethodID( + env, + clazz, + "<init>", + "(Ljava/lang/String;JI)V"); + + if (methodID) { - const PaHostErrorInfo* hostErr = Pa_GetLastHostErrorInfo(); + const char *message; + jstring jmessage; + jlong errorCode; + jint hostApiType; - if (hostErr) + /* + * We may be able to provide further details in the case of + * paUnanticipatedHostError by means of PaHostErrorInfo. + */ + if (paUnanticipatedHostError == err) { - jmethodID methodID - = (*env)->GetMethodID( - env, - clazz, - "<init>", - "(Ljava/lang/String;JI)V"); + const PaHostErrorInfo* hostErr = Pa_GetLastHostErrorInfo(); - if (methodID) + if (hostErr) { - const char *message = hostErr->errorText; - jstring jmessage; - + message = hostErr->errorText; /* * PaHostErrorInfo's errorText is documented to possibly be * an empty string. In such a case, the (detailed) message @@ -1267,54 +1270,65 @@ PortAudio_throwException(JNIEnv *env, PaError err) */ if (!message || !strlen(message)) message = Pa_GetErrorText(err); - - if (message) - { - jmessage = (*env)->NewStringUTF(env, message); - if (!jmessage) - { - /* - * XXX An exception has already been thrown and the - * current thread may no longer utilize JNIEnv - * methods. - */ - return; - } - } - else - jmessage = 0; - - if (jmessage) - { - jobject t - = (*env)->NewObject( - env, - clazz, - methodID, - jmessage, - (jlong) (hostErr->errorCode), - (jint) (hostErr->hostApiType)); - - if (t) - (*env)->Throw(env, (jthrowable) t); - /* - * XXX If there is no t, an exception has already been - * thrown and the current thread may no longer utilize - * JNIEnv methods. - */ - return; - } + errorCode = hostErr->errorCode; + hostApiType = hostErr->hostApiType; } else + { + message = Pa_GetErrorText(err); + errorCode = err; + hostApiType = -1; + } + } + else + { + message = Pa_GetErrorText(err); + errorCode = err; + hostApiType = -1; + } + + if (message) + { + jmessage = (*env)->NewStringUTF(env, message); + if (!jmessage) { /* - * XXX An exception has already been thrown and the - * current thread may no longer utilize JNIEnv - * methods. + * XXX An exception has already been thrown and the current + * thread may no longer utilize JNIEnv methods. */ return; } } + else + jmessage = 0; + + if (jmessage) + { + jobject t + = (*env)->NewObject( + env, + clazz, + methodID, + jmessage, + errorCode, + hostApiType); + + if (t) + (*env)->Throw(env, (jthrowable) t); + /* + * XXX If there is no t, an exception has already been thrown + * and the current thread may no longer utilize JNIEnv methods. + */ + return; + } + } + else + { + /* + * XXX An exception has already been thrown and the current thread + * may no longer utilize JNIEnv methods. + */ + return; } (*env)->ThrowNew(env, clazz, Pa_GetErrorText(err)); 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 4270a1f3c75b4f6b948603c27b64d741becc44fb..4b75cbbc7ff24e038078516f4352e80ab6c89dcf 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 @@ -225,6 +225,10 @@ private void connect() { AudioFormat format = (AudioFormat) getFormat(); int channels = format.getChannels(); + + if (channels == Format.NOT_SPECIFIED) + channels = 1; + int sampleSizeInBits = format.getSampleSizeInBits(); long sampleFormat = Pa.getPaSampleFormat(sampleSizeInBits); double sampleRate = format.getSampleRate(); @@ -241,7 +245,6 @@ private void connect() channels, sampleFormat, Pa.getSuggestedLatency()); - stream = Pa.OpenStream( inputParameters, @@ -351,16 +354,43 @@ protected Format doGetFormat() public void read(Buffer buffer) throws IOException { + String message; + synchronized (this) { if (stream == 0) - { - buffer.setLength(0); - return; - } + message = "This " + getClass().getName() + " is disconnected."; + else if (!started) + message = "This " + getClass().getName() + " is stopped."; else + { + message = null; streamIsBusy = true; + } } + + /* + * The caller shouldn't call #read(Buffer) if this instance is + * disconnected or stopped. Additionally, if she does, she may be + * persistent. If we do not slow her down, she may hog the CPU. + */ + if (message != null) + { + boolean interrupted = false; + + try + { + Thread.sleep(Pa.DEFAULT_MILLIS_PER_BUFFER); + } + catch (InterruptedException ie) + { + interrupted = true; + } + if (interrupted) + Thread.currentThread().interrupt(); + throw new IOException(message); + } + try { /* diff --git a/src/org/jitsi/impl/neomedia/protocol/PushBufferDataSourceAdapter.java b/src/org/jitsi/impl/neomedia/protocol/PushBufferDataSourceAdapter.java index 89ac42ef12604dc8c534db5441a97fbc116ada47..a2bae4290e9ed95107e747b19debb3d92d1e90a2 100644 --- a/src/org/jitsi/impl/neomedia/protocol/PushBufferDataSourceAdapter.java +++ b/src/org/jitsi/impl/neomedia/protocol/PushBufferDataSourceAdapter.java @@ -437,6 +437,7 @@ else if (bufferIsWritten) private void runInStreamReadThread() { boolean bufferIsWritten; + boolean yield; synchronized (buffer) { @@ -452,6 +453,13 @@ private void runInStreamReadThread() streamReadException = ie; } bufferIsWritten = this.bufferIsWritten; + /* + * If an exception has been thrown by the stream's read method, + * it may be better to give the stream's underlying + * implementation (e.g. PortAudio) a little time to possibly get + * its act together. + */ + yield = (!bufferIsWritten && (streamReadException != null)); } if (bufferIsWritten) @@ -461,6 +469,8 @@ private void runInStreamReadThread() if (transferHandler != null) transferHandler.transferData(this); } + else if (yield) + Thread.yield(); } /**