
org.jitsi.impl.neomedia.portaudio.Pa Maven / Gradle / Ivy
/*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.impl.neomedia.portaudio;
import java.lang.reflect.*;
import java.nio.charset.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.libjitsi.*;
import org.jitsi.util.OSUtils;
import org.jitsi.utils.logging.*;
/**
* Provides the interface to the native PortAudio library.
*
* @author Lyubomir Marinov
* @author Damian Minkov
* @author Sebastien Vincent
*/
public final class Pa
{
/**
* Enumerates the unchanging unique identifiers of each of the supported
* host APIs. The type is used in the PaHostApiInfo structure. The
* values are guaranteed to be unique and to never change, thus allowing
* code to be written that conditionally uses host API specific extensions.
*/
public static enum HostApiTypeId
{
paInDevelopment(0, "In Development") /* use while developing support for a new host API */,
paDirectSound(1, "DirectSound"),
paMME(2, "MME"),
paASIO(3, "ASIO"),
paSoundManager(4, "SoundManager"),
paCoreAudio(5, "CoreAudio"),
paOSS(7, "OSS"),
paALSA(8, "ALSA"),
paAL(9, "AL"),
paBeOS(10, "Be OS"),
paWDMKS(11, "WDMKS"),
paJACK(12, "JACK"),
paWASAPI(13, "WASAPI"),
paAudioScienceHPI(14, "Audio Science HPI");
/**
* Returns the PaHostApiTypeId which has a specific value or
* null if there is no such representation.
*
* @param value
* @return the PaHostApiTypeId which has the specified
* value or null if there is no such representation
*/
public static HostApiTypeId valueOf(int value)
{
for (HostApiTypeId hati : values())
{
if (hati.value == value)
return hati;
}
return null;
}
private final int value;
private final String name;
HostApiTypeId(int value, String name)
{
this.value = value;
this.name = name;
}
public String getApiName()
{
return name;
}
}
/**
* The number of milliseconds to be read from or written to a native
* PortAudio stream in a single transfer of data.
*/
public static final int DEFAULT_MILLIS_PER_BUFFER = 20;
/**
* The default value for the sample rate of the input and the output
* PortAudio streams with which they are to be opened if no other specific
* sample rate is specified to the PortAudio DataSource or
* PortAudioRenderer that they represent.
*/
public static final double DEFAULT_SAMPLE_RATE = 44100;
private static Runnable devicesChangedCallback;
/**
* Can be passed as the framesPerBuffer parameter to
* Pa_OpenStream() or Pa_OpenDefaultStream() to indicate
* that the stream callback will accept buffers of any size.
*/
public static final long FRAMES_PER_BUFFER_UNSPECIFIED = 0;
/**
* Used when creating new stream parameters for suggested latency to use
* high input/output value.
*/
public static final double LATENCY_HIGH = -1d;
/**
* Used when creating new stream parameters for suggested latency to use low
* input/default value.
*/
public static final double LATENCY_LOW = -2d;
/**
* Used when creating new stream parameters for suggested latency to use
* default value.
*/
public static final double LATENCY_UNSPECIFIED = 0d;
/**
* The Logger used by the Pa class for logging output.
*/
private static final Logger logger = Logger.getLogger(Pa.class);
/**
* The constant defined by Windows Multimedia and utilized by PortAudio's
* wmme host API to signal that no device driver is present.
*/
public static final int MMSYSERR_NODRIVER = 6;
/**
* The constant defined by the native PortAudio library to signal that no
* device is specified.
*/
public static final int paNoDevice = -1;
/**
* The PaErrorCode value defined by the native PortAudio library to
* signal that no error is detected/reported.
*/
public static final int paNoError = 0;
/**
* The PaErrorCode value defined by the native PortAudio library to
* signal that a timeout has occurred.
*/
public static final int paTimedOut = -9987;
/**
* The PaErrorCode value defined by the native PortAudio library to
* signal that an unanticipated error has been detected by a host API.
*/
public static final int paUnanticipatedHostError = -9999;
/**
* The name of the double property which determines the suggested
* latency to be used when opening PortAudio streams.
*/
private static final String PROP_SUGGESTED_LATENCY
= "net.java.sip.communicator.impl.neomedia.portaudio.suggestedLatency";
/**
* A type used to specify one or more sample formats. The standard format
* paFloat32.
*/
public static final long SAMPLE_FORMAT_FLOAT32 = 0x00000001;
/**
* A type used to specify one or more sample formats. The standard format
* paInt16.
*/
public static final long SAMPLE_FORMAT_INT16 = 0x00000008;
/**
* A type used to specify one or more sample formats. The standard format
* paInt24.
*/
public static final long SAMPLE_FORMAT_INT24 = 0x00000004;
/**
* A type used to specify one or more sample formats. The standard format
* paInt32.
*/
public static final long SAMPLE_FORMAT_INT32 = 0x00000002;
/**
* A type used to specify one or more sample formats. The standard format
* paInt8.
*/
public static final long SAMPLE_FORMAT_INT8 = 0x00000010;
/**
* A type used to specify one or more sample formats. The standard format
* paUInt8.
*/
public static final long SAMPLE_FORMAT_UINT8 = 0x00000020;
/** Disables default clipping of out of range samples. */
public static final long STREAM_FLAGS_CLIP_OFF = 0x00000001;
/** Disables default dithering. */
public static final long STREAM_FLAGS_DITHER_OFF = 0x00000002;
/**
* Flag requests that where possible a full duplex stream will not discard
* overflowed input samples without calling the stream callback. This flag
* is only valid for full duplex callback streams and only when used in
* combination with the paFramesPerBufferUnspecified (0)
* framesPerBuffer parameter. Using this flag incorrectly results in a
* paInvalidFlag error being returned from Pa_OpenStream
* and Pa_OpenDefaultStream.
*/
public static final long STREAM_FLAGS_NEVER_DROP_INPUT = 0x00000004;
/**
* Flags used to control the behavior of a stream. They are passed as
* parameters to Pa_OpenStream or Pa_OpenDefaultStream.
*/
public static final long STREAM_FLAGS_NO_FLAG = 0;
/** A mask specifying the platform specific bits. */
public static final long STREAM_FLAGS_PLATFORM_SPECIFIC_FLAGS = 0xFFFF0000;
/**
* Call the stream callback to fill initial output buffers, rather than the
* default behavior of priming the buffers with zeros (silence). This flag
* has no effect for input-only and blocking read/write streams.
*/
public static final long
STREAM_FLAGS_PRIME_OUTPUT_BUFFERS_USING_STREAM_CALLBACK
= 0x00000008;
static
{
OSUtils.loadLibrary("jnportaudio", Pa.class);
try
{
Initialize();
}
catch (PortAudioException paex)
{
logger.error("Failed to initialize the PortAudio library.", paex);
throw new UndeclaredThrowableException(paex);
}
}
/**
* Terminates audio processing immediately without waiting for pending
* buffers to complete.
*
* @param stream the steam pointer.
* @throws PortAudioException
*/
public static native void AbortStream(long stream)
throws PortAudioException;
/**
* Closes an audio stream. If the audio stream is active it discards any
* pending buffers as if Pa_AbortStream() had been called.
*
* @param stream the steam pointer.
* @throws PortAudioException
*/
public static native void CloseStream(long stream)
throws PortAudioException;
/**
* Returns defaultHighInputLatency for the device.
*
* @param deviceInfo device info pointer.
* @return defaultHighInputLatency for the device.
*/
public static native double DeviceInfo_getDefaultHighInputLatency(
long deviceInfo);
/**
* Returns defaultHighOutputLatency for the device.
*
* @param deviceInfo device info pointer.
* @return defaultHighOutputLatency for the device.
*/
public static native double DeviceInfo_getDefaultHighOutputLatency(
long deviceInfo);
/**
* Returns defaultLowInputLatency for the device.
*
* @param deviceInfo device info pointer.
* @return defaultLowInputLatency for the device.
*/
public static native double DeviceInfo_getDefaultLowInputLatency(
long deviceInfo);
/**
* Returns defaultLowOutputLatency for the device.
*
* @param deviceInfo device info pointer.
* @return defaultLowOutputLatency for the device.
*/
public static native double DeviceInfo_getDefaultLowOutputLatency(
long deviceInfo);
/**
* The default sample rate for the device.
*
* @param deviceInfo device info pointer.
* @return the default sample rate for the device.
*/
public static native double DeviceInfo_getDefaultSampleRate(
long deviceInfo);
/**
* Device UID for the device (persistent across boots).
*
* @param deviceInfo device info pointer.
* @return The device UID.
*/
public static String DeviceInfo_getDeviceUID(long deviceInfo)
{
return newString(DeviceInfo_getDeviceUIDBytes(deviceInfo));
}
/**
* Device UID for the device (persistent across boots).
*
* @param deviceInfo device info pointer.
* @return The device UID.
*/
public static native byte[] DeviceInfo_getDeviceUIDBytes(long deviceInfo);
/**
* The host api of the device.
*
* @param deviceInfo device info pointer.
* @return The host api of the device.
*/
public static native int DeviceInfo_getHostApi(long deviceInfo);
/**
* Maximum input channels for the device.
*
* @param deviceInfo device info pointer.
* @return Maximum input channels for the device.
*/
public static native int DeviceInfo_getMaxInputChannels(long deviceInfo);
/**
* Maximum output channels for the device.
*
* @param deviceInfo device info pointer.
* @return Maximum output channels for the device.
*/
public static native int DeviceInfo_getMaxOutputChannels(long deviceInfo);
/**
* Gets the human-readable name of the PaDeviceInfo specified by a
* pointer to it.
*
* @param deviceInfo the pointer to the PaDeviceInfo to get the
* human-readable name of
* @return the human-readable name of the PaDeviceInfo pointed to
* by deviceInfo
*/
public static String DeviceInfo_getName(long deviceInfo)
{
return newString(DeviceInfo_getNameBytes(deviceInfo));
}
/**
* Gets the name as a byte array of the PortAudio device specified
* by the pointer to its PaDeviceInfo instance.
*
* @param deviceInfo the pointer to the PaDeviceInfo instance to
* get the name of
* @return the name as a byte array of the PortAudio device
* specified by the PaDeviceInfo instance pointed to by
* deviceInfo
*/
private static native byte[] DeviceInfo_getNameBytes(long deviceInfo);
/**
* Transport type for the device: BuiltIn, USB, BLuetooth, etc.
*
* @param deviceInfo device info pointer.
* @return The transport type identifier.
*/
public static String DeviceInfo_getTransportType(long deviceInfo)
{
return newString(DeviceInfo_getTransportTypeBytes(deviceInfo));
}
/**
* Transport type for the device: BuiltIn, USB, BLuetooth, etc.
*
* @param deviceInfo device info pointer.
* @return The transport type identifier.
*/
public static native byte[] DeviceInfo_getTransportTypeBytes(
long deviceInfo);
/**
* Implements a callback which gets called by the native PortAudio
* counterpart to notify the Java counterpart that the list of PortAudio
* devices has changed.
*/
public static void devicesChangedCallback()
{
Runnable devicesChangedCallback = Pa.devicesChangedCallback;
if (devicesChangedCallback != null)
devicesChangedCallback.run();
}
private static native void free(long ptr);
/**
* Retrieve the index of the default input device.
*
* @return The default input device index for the default host API, or
* paNoDevice if no default input device is available or an error
* was encountered.
*/
public static native int GetDefaultInputDevice();
/**
* Retrieve the index of the default output device.
*
* @return The default input device index for the default host API, or
* paNoDevice if no default input device is available or an error
* was encountered.
*/
public static native int GetDefaultOutputDevice();
/**
* Retrieve the number of available devices. The number of available devices
* may be zero.
*
* @return the number of devices.
* @throws PortAudioException
*/
public static native int GetDeviceCount()
throws PortAudioException;
/**
* Returns the PortAudio index of the device identified by a specific
* deviceID or {@link Pa#paNoDevice} if no such device exists. The
* deviceID is either a deviceUID or a (PortAudio device)
* name depending, for example, on operating system/API availability. Since
* at least names may not be unique, the PortAudio device to return the
* index of may be identified more specifically by the minimal numbers of
* channels to be required from the device for input and output.
*
* @param deviceID a String identifying the PortAudio device to
* retrieve the index of. It is either a deviceUID or a (PortAudio
* device) name.
* @param minInputChannels
* @param minOutputChannels
* @return the PortAudio index of the device identified by the specified
* deviceID or Pa.paNoDevice if no such device exists
*/
public static int getDeviceIndex(
String deviceID,
int minInputChannels, int minOutputChannels)
{
if(deviceID != null)
{
int deviceCount = 0;
try
{
deviceCount = Pa.GetDeviceCount();
}
catch(PortAudioException paex)
{
/*
* A deviceCount equal to 0 will eventually result in a return
* value equal to paNoDevice.
*/
}
for(int deviceIndex = 0; deviceIndex < deviceCount; ++deviceIndex)
{
long deviceInfo = Pa.GetDeviceInfo(deviceIndex);
/* The deviceID is either the deviceUID or the name. */
String deviceUID = Pa.DeviceInfo_getDeviceUID(deviceInfo);
int hostApiIndex = Pa.DeviceInfo_getHostApi(deviceInfo);
long hostApiInfo = Pa.GetHostApiInfo(hostApiIndex);
String hostApiName = null;
if (hostApiInfo != 0)
{
int hostApiTypeValue = Pa.HostApiInfo_getType(hostApiInfo);
HostApiTypeId hostApiTypeId =
HostApiTypeId.valueOf(hostApiTypeValue);
if (hostApiTypeId != null)
{
hostApiName = hostApiTypeId.getApiName();
}
}
if(deviceID.equals(
((deviceUID == null) || (deviceUID.length() == 0))
? hostApiName + ": " + Pa.DeviceInfo_getName(deviceInfo)
: hostApiName + "_" + deviceUID))
{
/*
* Resolve deviceID clashes by further identifying the
* device through the numbers of channels that it supports
* for input and output.
*/
if ((minInputChannels > 0)
&& (Pa.DeviceInfo_getMaxInputChannels(deviceInfo)
< minInputChannels))
continue;
if ((minOutputChannels > 0)
&& (Pa.DeviceInfo_getMaxOutputChannels(deviceInfo)
< minOutputChannels))
continue;
return deviceIndex;
}
}
}
// No corresponding device was found.
return Pa.paNoDevice;
}
/**
* Retrieve a pointer to a PaDeviceInfo structure containing information
* about the specified device.
*
* @param deviceIndex the device index
* @return pointer to device info structure.
*/
public static native long GetDeviceInfo(int deviceIndex);
/**
* Retrieve a pointer to a structure containing information about a specific
* host Api.
*
* @param hostApiIndex host api index.
* @return A pointer to an immutable PaHostApiInfo structure describing a
* specific host API.
*/
public static native long GetHostApiInfo(int hostApiIndex);
/**
* Gets the native PaSampleFormat with a specific size in bits.
*
* @param sampleSizeInBits the size in bits of the native
* PaSampleFormat to get
* @return the native PaSampleFormat with the specified size in
* bits
*/
public static long getPaSampleFormat(int sampleSizeInBits)
{
switch (sampleSizeInBits)
{
case 8:
return SAMPLE_FORMAT_INT8;
case 24:
return SAMPLE_FORMAT_INT24;
case 32:
return SAMPLE_FORMAT_INT32;
default:
return SAMPLE_FORMAT_INT16;
}
}
/**
* Retrieve the size of a given sample format in bytes.
*
* @param format the format.
* @return The size in bytes of a single sample in the specified format, or
* paSampleFormatNotSupported if the format is not supported.
*/
public static native int GetSampleSize(long format);
/**
* Retrieve the number of frames that can be read from the stream without
* waiting.
*
* @param stream pointer to the stream.
* @return returns a non-negative value representing the maximum number of
* frames that can be read from the stream without blocking or busy waiting
* or, a PaErrorCode (which are always negative) if PortAudio is
* not initialized or an error is encountered.
*/
public static native long GetStreamReadAvailable(long stream);
/**
* Retrieve the number of frames that can be written to the stream
* without waiting.
*
* @param stream pointer to the stream.
* @return returns a non-negative value representing the maximum number of
* frames that can be written to the stream without blocking or busy waiting
* or, a PaErrorCode (which are always negative) if PortAudio is not
* initialized or an error is encountered.
*/
public static native long GetStreamWriteAvailable(long stream);
/**
* Gets the suggested latency to be used when opening PortAudio streams.
*
* @return the suggested latency to be used when opening PortAudio streams
*/
public static double getSuggestedLatency()
{
ConfigurationService cfg = LibJitsi.getConfigurationService();
if (cfg != null)
{
String suggestedLatencyString
= cfg.getString(PROP_SUGGESTED_LATENCY);
if (suggestedLatencyString != null)
{
try
{
double suggestedLatency
= Double.parseDouble(suggestedLatencyString);
if (suggestedLatency != LATENCY_UNSPECIFIED)
return suggestedLatency;
}
catch (NumberFormatException nfe)
{
logger.error(
"Failed to parse configuration property "
+ PROP_SUGGESTED_LATENCY
+ " value as a double",
nfe);
}
}
}
if (OSUtils.IS_MAC || OSUtils.IS_LINUX)
return LATENCY_HIGH;
else if (OSUtils.IS_WINDOWS)
return 0.1d;
else
return LATENCY_UNSPECIFIED;
}
/**
* The default input device for this host API.
*
* @param hostApiInfo pointer to host API info structure.
* @return The default input device for this host API.
*/
public static native int HostApiInfo_getDefaultInputDevice(
long hostApiInfo);
/**
* The default output device for this host API.
*
* @param hostApiInfo pointer to host API info structure.
* @return The default output device for this host API.
*/
public static native int HostApiInfo_getDefaultOutputDevice(
long hostApiInfo);
/**
* The number of devices belonging to this host API.
*
* @param hostApiInfo pointer to host API info structure.
* @return The number of devices belonging to this host API.
*/
public static native int HostApiInfo_getDeviceCount(long hostApiInfo);
/**
* The well known unique identifier of this host API.
*
* @param hostApiInfo pointer to host API info structure.
* @return The well known unique identifier of this host API.
* Enumerator:
* paInDevelopment
* paDirectSound
* paMME
* paASIO
* paSoundManager
* paCoreAudio
* paOSS
* paALSA
* paAL
* paBeOS
* paWDMKS
* paJACK
* paWASAPI
* paAudioScienceHPI
*/
public static native int HostApiInfo_getType(long hostApiInfo);
/**
* Initializes the native PortAudio library.
*
* @throws PortAudioException
*/
private static native void Initialize()
throws PortAudioException;
/**
* Determine whether it would be possible to open a stream
* with the specified parameters.
*
* @param inputParameters A structure that describes the input parameters
* used to open a stream.
* @param outputParameters A structure that describes the output parameters
* used to open a stream.
* @param sampleRate The required sampleRate.
* @return returns 0 if the format is supported, and an error code
* indicating why the format is not supported otherwise. The constant
* paFormatIsSupported is provided to compare with the return value for
* success.
*/
public static native boolean IsFormatSupported(
long inputParameters,
long outputParameters,
double sampleRate);
/**
* Opens a stream for either input, output or both.
*
* @param inputParameters the input parameters or 0 if absent.
* @param outputParameters the output parameters or 0 if absent.
* @param sampleRate The desired sampleRate.
* @param framesPerBuffer The number of frames passed to the stream callback
* function, or the preferred block granularity for a blocking read/write
* stream
* @param streamFlags Flags which modify the behavior of the streaming
* process.
* @param streamCallback A pointer to a client supplied function that is
* responsible for processing and filling input and output buffers. If
* null, the stream will be opened in 'blocking read/write' mode.
* @return pointer to the opened stream.
* @throws PortAudioException
*/
public static native long OpenStream(
long inputParameters,
long outputParameters,
double sampleRate,
long framesPerBuffer,
long streamFlags,
PortAudioStreamCallback streamCallback)
throws PortAudioException;
/**
* Read samples from an input stream. The function doesn't return until
* the entire buffer has been filled - this may involve waiting for
* the operating system to supply the data.
*
* @param stream pointer to the stream.
* @param buffer a buffer of sample frames.
* @param frames The number of frames to be read into buffer.
* @throws PortAudioException
*/
public static native void ReadStream(
long stream, byte[] buffer, long frames)
throws PortAudioException;
/**
* Sets the indicator which determines whether a specific (input) PortAudio
* stream is to have denoise performed on the audio data it provides.
*
* @param stream the (input) PortAudio stream for which denoise is to be
* enabled or disabled
* @param denoise true if denoise is to be performed on the audio
* data provided by stream; otherwise, false
*/
public static native void setDenoise(long stream, boolean denoise);
public static void setDevicesChangedCallback(
Runnable devicesChangedCallback)
{
Pa.devicesChangedCallback = devicesChangedCallback;
}
/**
* Sets the number of milliseconds of echo to be canceled in the audio data
* provided by a specific (input) PortAudio stream.
*
* @param stream the (input) PortAudio stream for which the number of
* milliseconds of echo to be canceled is to be set
* @param echoFilterLengthInMillis the number of milliseconds of echo to be
* canceled in the audio data provided by stream
*/
public static native void setEchoFilterLengthInMillis(
long stream,
long echoFilterLengthInMillis);
/**
* Commences audio processing.
*
* @param stream pointer to the stream
* @throws PortAudioException
*/
public static native void StartStream(long stream)
throws PortAudioException;
/**
* Terminates audio processing. It waits until all pending audio buffers
* have been played before it returns.
*
* @param stream pointer to the stream
* @throws PortAudioException
*/
public static native void StopStream(long stream)
throws PortAudioException;
/**
* Free StreamParameters resources specified by a pointer to it.
*
* @param streamParameters the pointer to the PaStreamParameters
* to free
*/
public static void StreamParameters_free(long streamParameters)
{
free(streamParameters);
}
/**
* Creates parameters used for opening streams.
*
* @param deviceIndex the device.
* @param channelCount the channels to be used.
* @param sampleFormat the sample format.
* @param suggestedLatency the suggested latency in milliseconds:
* LATENCY_UNSPECIFIED -
* use default(default high input/output latency)
* LATENCY_HIGH - use default high input/output latency
* LATENCY_LOW - use default low input/output latency
* ... - any other value in milliseconds (e.g. 0.1 is acceptable)
* @return pointer to the params used for Pa_OpenStream.
*/
public static native long StreamParameters_new(
int deviceIndex,
int channelCount,
long sampleFormat,
double suggestedLatency);
public static native void UpdateAvailableDeviceList();
/**
* Writes samples to an output stream. Does not return until the specified
* samples have been consumed - this may involve waiting for the operating
* system to consume the data.
*
* Provides better efficiency than achieved through multiple consecutive
* calls to {@link #WriteStream(long, byte[], long)} with one and the
* same buffer because the JNI access to the bytes of the buffer which is
* likely to copy the whole buffer is only performed once.
*
* @param stream the pointer to the PortAudio stream to write the samples to
* @param buffer the buffer containing the samples to be written
* @param offset the byte offset in buffer at which the samples to
* be written start
* @param frames the number of frames from buffer starting at
* offset are to be written with a single write
* @param numberOfWrites the number of writes each writing frames
* number of frames to be performed
* @throws PortAudioException if anything goes wrong while writing
*/
public static native void WriteStream(
long stream,
byte[] buffer,
int offset,
long frames,
int numberOfWrites)
throws PortAudioException;
/**
* Write samples to an output stream. This function doesn't return until
* the entire buffer has been consumed - this may involve waiting for the
* operating system to consume the data.
*
* @param stream pointer to the stream
* @param buffer A buffer of sample frames.
* @param frames The number of frames to be written from buffer.
* @throws PortAudioException
*/
public static void WriteStream(long stream, byte[] buffer, long frames)
throws PortAudioException
{
WriteStream(stream, buffer, 0, frames, 1);
}
/**
* Prevents the initialization of Pa instances.
*/
private Pa()
{
}
private static String newString(byte[] bytes)
{
if (bytes == null || bytes.length == 0)
{
return null;
}
else
{
return new String(bytes, StandardCharsets.UTF_8);
}
}
}