diff options
author | Werner Dittmann <wernerd@java.net> | 2010-05-11 16:44:30 +0000 |
---|---|---|
committer | Werner Dittmann <wernerd@java.net> | 2010-05-11 16:44:30 +0000 |
commit | 1ce520313bbb1ebf3038795f73dda2299036e658 (patch) | |
tree | d2cc4a1c1642e26977b7b4b4f95a348605fe4711 | |
parent | c2bcedcf6aaaa8d1851b356ac01d7f770ee72e49 (diff) | |
download | jitsi-1ce520313bbb1ebf3038795f73dda2299036e658.zip jitsi-1ce520313bbb1ebf3038795f73dda2299036e658.tar.gz jitsi-1ce520313bbb1ebf3038795f73dda2299036e658.tar.bz2 |
Implement finer synchronization granularity for portaudio streams
Use dedicated syncronization object in InputStream and MasterStream to
implement a synchronization policy with finer granularity. This
speeds up processing if SC uses several InputStream, for example several
calls that are not on hold.
2 files changed, 82 insertions, 40 deletions
diff --git a/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/InputPortAudioStream.java b/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/InputPortAudioStream.java index adaaadd..8d49647 100644 --- a/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/InputPortAudioStream.java +++ b/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/InputPortAudioStream.java @@ -66,6 +66,7 @@ public class InputPortAudioStream this.parentStream = parentStream; } + private Object readSync = new Object(); /** * Reads audio data from this <tt>InputPortAudioStream</tt> into a specific * <tt>Buffer</tt> blocking until audio data is indeed available. @@ -82,41 +83,53 @@ public class InputPortAudioStream buffer.setLength(0); return; } - - synchronized (parentStream) + + synchronized (readSync) { - if (bufferData == null) - { - parentStream.read(buffer); - } - else + while (true) { - /* - * If buffer conatins a data area then check if the type and - * length fits. If yes then use it, otherwise allocate a new - * area and set it in buffer. - * - * In case we can re-use the data area: copy the data, don't - * just set the bufferData into buffer because bufferData - * points to a data area in another buffer instance. - */ - Object data = buffer.getData(); - byte[] tmpArray; - if (data instanceof byte[] && ((byte[])data).length >= bufferLength) { - tmpArray = (byte[])data; + if (bufferData == null) { + // parent read returns false if read is already active, wait + // until notified by setBuffer below. + if (!parentStream.read(buffer)) { + try { + readSync.wait(); + } catch (InterruptedException e) { + continue; + } + continue; // bufferData was set by setBuffer + } + // parent read returned true, break loop below } else { - tmpArray = new byte[bufferLength]; - buffer.setData(tmpArray); + /* + * If buffer conatins a data area then check if the type and + * length fits. If yes then use it, otherwise allocate a new + * area and set it in buffer. + * + * In case we can re-use the data area: copy the data, don't + * just set the bufferData into buffer because bufferData + * points to a data area in another buffer instance. + */ + Object data = buffer.getData(); + byte[] tmpArray; + if (data instanceof byte[] && ((byte[])data).length >= bufferLength) { + tmpArray = (byte[])data; + } + else + { + tmpArray = new byte[bufferLength]; + buffer.setData(tmpArray); + } + System.arraycopy(bufferData, 0, tmpArray, 0, bufferLength); + buffer.setFlags(Buffer.FLAG_SYSTEM_TIME); + buffer.setLength(bufferLength); + buffer.setOffset(0); + buffer.setTimeStamp(bufferTimeStamp); } - System.arraycopy(bufferData, 0, tmpArray, 0, bufferLength); - buffer.setFlags(Buffer.FLAG_SYSTEM_TIME); - buffer.setLength(bufferLength); - buffer.setOffset(0); - buffer.setTimeStamp(bufferTimeStamp); + break; } - /* * The bufferData of this InputPortAudioStream has been consumed so * make sure a new piece of audio data will be read the next time. @@ -142,11 +155,12 @@ public class InputPortAudioStream */ void setBuffer(byte[] bufferData, int bufferLength, long bufferTimeStamp) { - synchronized (parentStream) + synchronized (readSync) { this.bufferData = bufferData; this.bufferLength = bufferLength; this.bufferTimeStamp = bufferTimeStamp; + readSync.notifyAll(); } } diff --git a/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/MasterPortAudioStream.java b/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/MasterPortAudioStream.java index 7b51a3e..7ad3a28 100644 --- a/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/MasterPortAudioStream.java +++ b/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/MasterPortAudioStream.java @@ -80,6 +80,10 @@ public class MasterPortAudioStream private long stream = 0; /** + * Whether a read is active. + */ + private boolean readActive = false; + /** * Creates new stream. * @param deviceIndex the device to use. * @param channels the channels to serve. @@ -144,6 +148,8 @@ public class MasterPortAudioStream null); } + private Object readSync = new Object(); + /** * Reads audio data from this <tt>MasterPortAudioStream</tt> into a specific * <tt>Buffer</tt> blocking until audio data is indeed available. @@ -151,14 +157,21 @@ public class MasterPortAudioStream * @param buffer the <tt>Buffer</tt> into which the audio data read from * this <tt>MasterPortAudioStream</tt> is to be returned * @throws PortAudioException if an error occurs while reading - */ - public synchronized void read(Buffer buffer) + */ + public boolean read(Buffer buffer) throws PortAudioException { - if (!started) - { - buffer.setLength(0); - return; + synchronized (readSync) { + if (readActive) + { + return false; + } + readActive = true; + if (!started) + { + buffer.setLength(0); + return true; + } } /* @@ -197,6 +210,11 @@ public class MasterPortAudioStream .get(slaveIndex) .setBuffer(bufferData, bytesPerBuffer, bufferTimeStamp); } + synchronized(readSync) { + readActive = false; + readSync.notify(); + } + return true; } /** @@ -281,11 +299,21 @@ public class MasterPortAudioStream if(slaves.isEmpty()) { - // stop - PortAudio.Pa_CloseStream(stream); - stream = 0; - started = false; - PortAudioManager.getInstance().stoppedInputPortAudioStream(this); + synchronized (readSync) { + while (readActive) + { + try { + readSync.wait(); + } catch (InterruptedException e) { + continue; + } + } + // stop + PortAudio.Pa_CloseStream(stream); + stream = 0; + started = false; + PortAudioManager.getInstance().stoppedInputPortAudioStream(this); + } } } } |