Skip to content
Snippets Groups Projects
Commit 774c0c4c authored by Lyubomir Marinov's avatar Lyubomir Marinov
Browse files

Works on improving the acoustic echo cancellation (AEC) of Windows Audio Session API (WASAPI).

parent 34d9464e
No related branches found
No related tags found
No related merge requests found
......@@ -33,6 +33,15 @@ public class WASAPISystem
*/
private static String audioSessionGuid;
/**
* The default duration of audio data in milliseconds to be read from
* <tt>WASAPIStream</tt> in an invocation of
* {@link WASAPIStream#read(Buffer)} or to be processed by
* <tt>WASAPIRenderer</tt> in an invocation of
* {@link WASAPIRenderer#process(Buffer)}.
*/
public static final long DEFAULT_BUFFER_DURATION = 20;
/**
* The default interval in milliseconds between periodic processing passes
* by the audio engine.
......@@ -971,7 +980,10 @@ public long initializeAEC()
* endpoint device identified by the specified <tt>locator</tt>
* @param streamFlags
* @param eventHandle
* @param hnsBufferDuration
* @param hnsBufferDuration the base of the duration in milliseconds of the
* buffer that the audio application will share with the audio engine. If
* {@link Format#NOT_SPECIFIED}, the method uses the default interval
* between periodic passes by the audio engine.
* @param formats an array of alternative <tt>AudioFormat</tt>s with which
* initialization of a new <tt>IAudioClient</tt> instance is to be
* attempted. The first element of the <tt>formats</tt> array which is
......@@ -1107,12 +1119,24 @@ public long initializeIAudioClient(
if (eventHandle != 0)
streamFlags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
if (hnsBufferDuration == Format.NOT_SPECIFIED)
{
hnsBufferDuration
= IAudioClient_GetDefaultDevicePeriod(iAudioClient)
/ 10000;
if (hnsBufferDuration <= 1)
{
hnsBufferDuration
= WASAPISystem.DEFAULT_DEVICE_PERIOD;
}
}
int hresult
= IAudioClient_Initialize(
iAudioClient,
shareMode,
streamFlags,
hnsBufferDuration,
3 * hnsBufferDuration * 10000,
/* hnsPeriodicity */ 0,
waveformatex,
audioSessionGuid);
......
......@@ -19,7 +19,6 @@
import org.jitsi.impl.neomedia.control.*;
import org.jitsi.util.*;
// disambiguation
/**
* Facilitates the implementations of the <tt>CaptureDevice</tt> and
......
......@@ -33,12 +33,6 @@
*/
public class AudioCaptureClient
{
/**
* The default duration of the audio data in milliseconds to be read from
* <tt>WASAPIStream</tt> in an invocation of {@link #read(Buffer)}.
*/
static final long DEFAULT_BUFFER_DURATION = 20;
/**
* The <tt>Logger</tt> used by the <tt>AudioCaptureClient</tt> class and its
* instances to log debug information.
......@@ -46,6 +40,20 @@ public class AudioCaptureClient
private static final Logger logger
= Logger.getLogger(AudioCaptureClient.class);
/**
* The internal buffer of this instance in which audio data is read from the
* associated <tt>IAudioCaptureClient</tt> by the instance and awaits to be
* read out of this instance via {@link #read(byte[], int, int)}.
*/
private byte[] available;
/**
* The number of bytes in {@link #available} which represent valid audio
* data read from the associated <tt>IAudioCaptureClient</tt> by this
* instance.
*/
private int availableLength;
/**
* The number of audio frames to be filled in a <tt>byte[]</tt> in an
* invocation of {@link #read(byte[], int, int)}. The method
......@@ -134,20 +142,6 @@ public class AudioCaptureClient
*/
final AudioFormat outFormat;
/**
* The internal buffer of this instance in which audio data is read from the
* associated <tt>IAudioCaptureClient</tt> by the instance and awaits to be
* read out of this instance via {@link #read(byte[], int, int)}.
*/
private byte[] remainder;
/**
* The number of bytes in {@link #remainder} which represent valid audio
* data read from the associated <tt>IAudioCaptureClient</tt> by this
* instance.
*/
private int remainderLength;
/**
* The number of channels with which {@link #iAudioClient} has been
* initialized.
......@@ -194,6 +188,10 @@ public class AudioCaptureClient
* written on that render endpoint device
* @param streamFlags zero or more of the <tt>AUDCLNT_STREAMFLAGS_XXX</tt>
* flags defined by the <tt>WASAPI</tt> class
* @param hnsBufferDuration the base of the duration in milliseconds of the
* buffer that the audio application will share with the audio engine. If
* {@link Format#NOT_SPECIFIED}, the method uses the default interval
* between periodic passes by the audio engine.
* @param outFormat the <tt>AudioFormat</tt> of the data to be made
* available by the new instance. Eventually, the
* <tt>IAudioCaptureClient</tt> to be represented by the new instance may be
......@@ -210,6 +208,7 @@ public AudioCaptureClient(
MediaLocator locator,
AudioSystem.DataFlow dataFlow,
int streamFlags,
long hnsBufferDuration,
AudioFormat outFormat,
BufferTransferHandler transferHandler)
throws Exception
......@@ -227,7 +226,6 @@ public AudioCaptureClient(
* WASAPIRenderer and WASAPIStream. There is no particular
* reason/requirement to do so.
*/
long hnsBufferDuration = 3 * DEFAULT_BUFFER_DURATION * 10000;
long iAudioClient
= audioSystem.initializeIAudioClient(
locator,
......@@ -304,6 +302,8 @@ public AudioCaptureClient(
= WASAPISystem.DEFAULT_DEVICE_PERIOD;
}
this.devicePeriod = devicePeriod;
if (hnsBufferDuration == Format.NOT_SPECIFIED)
hnsBufferDuration = devicePeriod;
srcChannels = inFormat.getChannels();
srcSampleSize
......@@ -315,12 +315,11 @@ public AudioCaptureClient(
dstFrameSize = dstSampleSize * dstChannels;
bufferFrames
= (int)
(DEFAULT_BUFFER_DURATION * sampleRate / 1000);
= (int) (hnsBufferDuration * sampleRate / 1000);
bufferSize = dstFrameSize * bufferFrames;
remainder = new byte[numBufferFrames * dstFrameSize];
remainderLength = 0;
available = new byte[numBufferFrames * dstFrameSize];
availableLength = 0;
this.eventHandle = eventHandle;
eventHandle = 0;
......@@ -381,8 +380,8 @@ public void close()
eventHandle = 0;
}
remainder = null;
remainderLength = 0;
available = null;
availableLength = 0;
started = false;
}
......@@ -408,7 +407,7 @@ private int doRead(
int length)
throws IOException
{
int toRead = Math.min(length, remainderLength);
int toRead = Math.min(length, availableLength);
int read;
if (toRead == 0)
......@@ -418,30 +417,46 @@ private int doRead(
if (iMediaBuffer == null)
{
read = toRead;
System.arraycopy(remainder, 0, buffer, offset, toRead);
System.arraycopy(available, 0, buffer, offset, toRead);
}
else
read = iMediaBuffer.push(remainder, 0, toRead);
popFromRemainder(read);
read = iMediaBuffer.push(available, 0, toRead);
popFromAvailable(read);
}
return read;
}
/**
* Pops a specific number of bytes from {@link #remainder}. For example,
* because such a number of bytes have been read from <tt>remainder</tt> and
* Gets the number of bytes of audio samples which have been read from the
* associated <tt>IAudioCaptureClient</tt> by this instance and are
* available to be read out of this instance via
* {@link #read(byte[], int, int)}.
*
* @return the number of bytes of audio samples which have been read from
* the associated <tt>IAudioCaptureClient</tt> by this instance and are
* available to be read out of this instance via
* <tt>read(byte[], int, int)</tt>
*/
int getAvailableLength()
{
return availableLength;
}
/**
* Pops a specific number of bytes from {@link #available}. For example,
* because such a number of bytes have been read from <tt>available</tt> and
* written into a <tt>Buffer</tt>.
*
* @param length the number of bytes to pop from <tt>remainder</tt>
* @param length the number of bytes to pop from <tt>available</tt>
*/
private void popFromRemainder(int length)
private void popFromAvailable(int length)
{
remainderLength
= WASAPIRenderer.pop(remainder, remainderLength, length);
availableLength
= WASAPIRenderer.pop(available, availableLength, length);
}
/**
* Reads audio data from this instance into a spcific <tt>byte</tt> array.
* Reads audio data from this instance into a specific <tt>byte</tt> array.
*
* @param buffer the <tt>byte</tt> array into which the audio data read from
* this instance is to be written
......@@ -528,7 +543,7 @@ public int read(IMediaBuffer iMediaBuffer, int length)
}
/**
* Reads from {@link #iAudioCaptureClient} into {@link #remainder} and
* Reads from {@link #iAudioCaptureClient} into {@link #available} and
* returns a non-<tt>null</tt> <tt>BufferTransferHandler</tt> if this
* instance is to push audio data.
*
......@@ -553,30 +568,29 @@ private BufferTransferHandler readInEventHandleCmd()
numFramesInNextPacket = 0; // Silence the compiler.
logger.error("IAudioCaptureClient_GetNextPacketSize", hre);
}
if (numFramesInNextPacket != 0)
{
int toRead = numFramesInNextPacket * dstFrameSize;
/*
* Make sure there is enough room in remainder to accommodate
* Make sure there is enough room in available to accommodate
* toRead.
*/
int toPop = toRead - (remainder.length - remainderLength);
int toPop = toRead - (available.length - availableLength);
if (toPop > 0)
popFromRemainder(toPop);
popFromAvailable(toPop);
try
{
int read
= IAudioCaptureClient_Read(
iAudioCaptureClient,
remainder, remainderLength, toRead,
available, availableLength, toRead,
srcSampleSize, srcChannels,
dstSampleSize, dstChannels);
remainderLength += read;
availableLength += read;
}
catch (HResultException hre)
{
......@@ -584,7 +598,7 @@ private BufferTransferHandler readInEventHandleCmd()
}
}
return (remainderLength >= bufferSize) ? transferHandler : null;
return (availableLength >= bufferSize) ? transferHandler : null;
}
/**
......@@ -727,7 +741,7 @@ public synchronized void start()
IAudioClient_Start(iAudioClient);
started = true;
remainderLength = 0;
availableLength = 0;
if ((eventHandle != 0) && (this.eventHandleCmd == null))
{
Runnable eventHandleCmd
......@@ -798,7 +812,7 @@ public synchronized void stop()
started = false;
waitWhileEventHandleCmd();
remainderLength = 0;
availableLength = 0;
}
catch (HResultException hre)
{
......
......@@ -32,12 +32,6 @@
public class WASAPIRenderer
extends AbstractAudioRenderer<WASAPISystem>
{
/**
* The default base of the endpoint buffer capacity in milliseconds to
* initialize new <tt>IAudioClient</tt> instances with.
*/
private static final long DEFAULT_BUFFER_DURATION = 60;
/**
* The <tt>Logger</tt> used by the <tt>WASAPIRenderer</tt> class and its
* instances to log debug information.
......@@ -316,14 +310,13 @@ public synchronized void open()
try
{
long hnsBufferDuration = DEFAULT_BUFFER_DURATION * 10000;
long iAudioClient
= audioSystem.initializeIAudioClient(
locator,
dataFlow,
/* streamFlags */ 0,
eventHandle,
hnsBufferDuration,
WASAPISystem.DEFAULT_BUFFER_DURATION,
formats);
if (iAudioClient == 0)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment