/*
* @(#)AudioFormat.java 1.40 02/08/21
*
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved.
*/
package javax.media.format;
import javax.media.Format;
/**
* Encapsulates format information for audio data.
* The attributes of an <code>AudioFormat</code> include the sample rate,
* bits per sample, and number of channels.
* @since JMF 2.0
*/
public class AudioFormat extends Format {
public static final int BIG_ENDIAN = 1;
public static final int LITTLE_ENDIAN = 0;
public static final int SIGNED = 1;
public static final int UNSIGNED = 0;
protected double sampleRate = NOT_SPECIFIED;
protected int sampleSizeInBits = NOT_SPECIFIED;
protected int channels = NOT_SPECIFIED;
protected int endian = NOT_SPECIFIED;
protected int signed = NOT_SPECIFIED;
protected double frameRate = NOT_SPECIFIED;
protected int frameSizeInBits = NOT_SPECIFIED;
// Standard audio encoding strings
// public static final String LINEAR = "linear";
public static final String LINEAR = "LINEAR";
// public static final String ULAW = "ulaw";
public static final String ULAW = "ULAW";
public static final String ULAW_RTP = "ULAW/rtp";
public static final String ALAW = "alaw";
public static final String IMA4 = "ima4";
public static final String IMA4_MS = "ima4/ms";
public static final String MSADPCM = "msadpcm";
public static final String DVI = "dvi";
public static final String DVI_RTP = "dvi/rtp";
public static final String G723 = "g723";
public static final String G723_RTP = "g723/rtp";
public static final String G728 = "g728";
public static final String G728_RTP = "g728/rtp";
public static final String G729 = "g729";
public static final String G729_RTP = "g729/rtp";
public static final String G729A = "g729a";
public static final String G729A_RTP = "g729a/rtp";
public static final String GSM = "gsm";
public static final String GSM_MS = "gsm/ms";
public static final String GSM_RTP = "gsm/rtp";
public static final String MAC3 = "MAC3";
public static final String MAC6 = "MAC6";
public static final String TRUESPEECH = "truespeech";
public static final String MSNAUDIO = "msnaudio";
public static final String MPEGLAYER3 = "mpeglayer3";
public static final String VOXWAREAC8 = "voxwareac8";
public static final String VOXWAREAC10 = "voxwareac10";
public static final String VOXWAREAC16 = "voxwareac16";
public static final String VOXWAREAC20 = "voxwareac20";
public static final String VOXWAREMETAVOICE = "voxwaremetavoice";
public static final String VOXWAREMETASOUND = "voxwaremetasound";
public static final String VOXWARERT29H = "voxwarert29h";
public static final String VOXWAREVR12 = "voxwarevr12";
public static final String VOXWAREVR18= "voxwarevr18";
public static final String VOXWARETQ40= "voxwaretq40";
public static final String VOXWARETQ60 = "voxwaretq60";
public static final String MSRT24 = "msrt24";
public static final String MPEG = "mpegaudio";
public static final String MPEG_RTP = "mpegaudio/rtp";
public static final String DOLBYAC3 = "dolbyac3";
/**
* Constructs an <CODE>AudioFormat</CODE> with the specified encoding type.
* @param encoding The audio encoding type.
*/
public AudioFormat(String encoding) {
super(encoding);
}
/**
* Constructs an <CODE>AudioFormat</CODE> with the specified attributes.
*
* @param encoding A <CODE>String</CODE> that describes the encoding type
* for this <CODE>AudioFormat</CODE>.
* @param sampleRate The sample rate.
* @param sampleSizeInBits The sample size in bits.
* @param channels The number of channels as an integer.
* For example, 1 for mono, 2 for stereo.
*/
public AudioFormat(String encoding, double sampleRate,
int sampleSizeInBits, int channels) {
this(encoding);
this.sampleRate = sampleRate;
this.sampleSizeInBits = sampleSizeInBits;
this.channels = channels;
}
/**
* Constructs an <CODE>AudioFormat</CODE> with the specified attributes.
* @param encoding A <CODE>String</CODE> that describes the encoding
* type for this <CODE>AudioFormat</CODE>.
* @param sampleRate The sample rate.
* @param sampleSizeInBits The sample size in bits.
* @param channels The number of channels.
* @param endian The sample byte ordering used for this
* <code>AudioFormat</code>--<CODE>BIG_ENDIAN</CODE> or <CODE>LITTLE_ENDIAN</CODE>.
* @param signed Indicates whether the samples are stored in a signed or unsigned
* format. Specify <CITE><CODE>true</CODE></CITE>
* if the <code>AudioFormat</code> is signed, <CODE>false</CODE> if the
* <code>AudioFormat</code> is unsigned.
*/
public AudioFormat(String encoding, double sampleRate,
int sampleSizeInBits, int channels,
int endian, int signed) {
this(encoding, sampleRate, sampleSizeInBits, channels);
this.endian = endian;
this.signed = signed;
}
/**
* Constructs an <CODE>AudioFormat</CODE> with the specified attributes.
* @param encoding A <CODE>String</CODE> that describes the encoding type
* for this <CODE>AudioFormat</CODE>.
* @param sampleRate The sample rate.
* @param sampleSizeInBits The sample size.
* @param channels The number of channels.
* @param endian The sample byte ordering used for this
* <code>AudioFormat</code>--<CODE>BIG_ENDIAN</CODE> or <CODE>LITTLE_ENDIAN</CODE>.
* @param signed Indicates whether the samples are stored in a signed or unsigned
* format. Specify <CITE><CODE>true</CODE></CITE>
* if the <code>AudioFormat</code> is signed, <CODE>false</CODE> if the
* <code>AudioFormat</code> is unsigned.
* @param frameSizeInBits The frame size.
* @param frameRate The frame rate.
* @param dataType The type of the data. For example, byte array.
*/
public AudioFormat(String encoding, double sampleRate,
int sampleSizeInBits, int channels,
int endian, int signed,
int frameSizeInBits, double frameRate, Class dataType) {
this(encoding, sampleRate, sampleSizeInBits, channels, endian, signed);
this.frameSizeInBits = frameSizeInBits;
this.frameRate = frameRate;
this.dataType = dataType;
}
/**
* Gets the audio sample rate.
* @return The sample rate.
*/
public double getSampleRate() {
return sampleRate;
}
/**
* Gets the size of a sample.
* @return The sample size in bits.
*/
public int getSampleSizeInBits() {
return sampleSizeInBits;
}
/**
* Gets the number of channels.
* @return The number of channels as an integer.
*/
public int getChannels() {
return channels;
}
/**
* Gets an integer that indicates whether the sample byte order is big endian
* or little endian.
* @return The sample byte order of this <code>AudioFormat</code>,
* <CODE>BIG_ENDIAN</CODE> or <CODE>LITTLE_ENDIAN</CODE>.
*/
public int getEndian() {
return endian;
}
/**
* Gets a boolean that indicates whether the samples are stored in signed format
* or an unsigned format.
* @return <CODE>SIGNED</CODE> if this <CODE>VideoFormat</CODE> is signed,
* <CODE>UNSIGNED</CODE> if it is not.
*/
public int getSigned() {
return signed;
}
/**
* Gets the frame size of this <code>AudioFormat</code>. This method is
* used primarily for compressed audio.
* @return The frame size of this <code>AudioFormat</code> in bits.
*/
public int getFrameSizeInBits() {
return frameSizeInBits;
}
/**
* Gets the frame rate of this <code>AudioFormat</code>.
* @return The frame rate.
*/
public double getFrameRate() {
return frameRate;
}
/**
* For computing the duration of the sample.
*/
double multiplier = -1f;
int margin = 0;
boolean init = false;
/**
* Returns the duration of the media based on the given length
* of the data.
* @param length length of the data in this format.
* @return the duration in nanoseconds computed from the length of
* the data in this format. Returns -1 if the duration cannot be
* computed.
*/
public long computeDuration(long length) {
if (init) {
// We don't know how to compute this format
if (multiplier < 0)
return -1;
return (long)((length - margin) * multiplier) * 1000;
}
if (encoding == null) {
init = true;
return -1;
} else if (encoding.equalsIgnoreCase(AudioFormat.LINEAR) ||
encoding.equalsIgnoreCase(AudioFormat.ULAW)) {
if (sampleSizeInBits > 0 && channels > 0 && sampleRate > 0)
multiplier = (1000000 * 8)/sampleSizeInBits/channels/sampleRate;
} else if (encoding.equalsIgnoreCase(AudioFormat.ULAW_RTP)) {
if (sampleSizeInBits > 0 && channels > 0 && sampleRate > 0)
multiplier = (1000000 * 8)/sampleSizeInBits/channels/sampleRate;
} else if (encoding.equalsIgnoreCase(AudioFormat.DVI_RTP)) {
if (sampleSizeInBits > 0 && sampleRate > 0)
multiplier = (1000000 * 8)/sampleSizeInBits/sampleRate;
margin = 4;
} else if (encoding.equalsIgnoreCase(AudioFormat.GSM_RTP)) {
if (sampleRate > 0)
multiplier = (160 * 1000000 / 33) / sampleRate;
} else if (encoding.equalsIgnoreCase(AudioFormat.G723_RTP)) {
if (sampleRate > 0)
multiplier = (240/24 * 1000000) / sampleRate;
} else if (frameSizeInBits != Format.NOT_SPECIFIED &&
frameRate != Format.NOT_SPECIFIED) {
// We don't know this codec, but we can compute the
// rate by using the frame rate and size.
if (frameSizeInBits > 0 && frameRate > 0)
multiplier = (1000000 * 8)/frameSizeInBits/frameRate;
}
init = true;
if (multiplier > 0)
return (long)((length - margin) * multiplier) * 1000;
else
return -1;
}
/**
* Gets a <CODE>String</CODE> representation of the attributes of this
* <code>AudioFormat</code>. For example: "PCM, 44.1 KHz, Stereo, Signed".
* @return A <CODE>String</CODE> that describes the <code>AudioFormat</code>
* attributes.
*/
public String toString() {
String strChannels = "";
String strEndian = "";
if (channels == 1)
strChannels = ", Mono";
else if (channels == 2)
strChannels = ", Stereo";
else if (channels != NOT_SPECIFIED)
strChannels = ", " + channels + "-channel";
if (sampleSizeInBits > 8) {
if (endian == BIG_ENDIAN)
strEndian = ", BigEndian";
else if (endian == LITTLE_ENDIAN)
strEndian = ", LittleEndian";
}
return getEncoding() +
( (sampleRate != NOT_SPECIFIED) ? (", " + sampleRate + " Hz")
: ", Unknown Sample Rate" )+
( (sampleSizeInBits != NOT_SPECIFIED) ? (", " + sampleSizeInBits + "-bit")
: "" ) +
strChannels +
strEndian +
( (signed != NOT_SPECIFIED) ? ((signed == SIGNED ? ", Signed"
: ", Unsigned"))
: "" ) +
( (frameRate != NOT_SPECIFIED) ? (", " + frameRate + " frame rate")
: "" )+
( (frameSizeInBits != NOT_SPECIFIED) ? (", FrameSize=" + frameSizeInBits + " bits")
: "" )+
( (dataType != Format.byteArray && dataType != null) ? ", " + dataType
: "");
}
/**
* Compares the specified <CODE>Format</CODE> with this <code>AudioFormat</code>.
* Returns <CODE>true</CODE>
* only if the specified <CODE>Format</CODE> is an <CODE>AudioFormat</CODE> and
* all of its attributes are
* identical to this <code>AudioFormat</code>.
* @param format The <CODE>Format</CODE> to compare with this one.
* @return <CODE>true</CODE> if the specified <CODE>Format</CODE> is the same,
* <CODE>false</CODE> if it is not.
*/
public boolean equals(Object format) {
if (format instanceof AudioFormat) {
AudioFormat other = (AudioFormat) format;
return super.equals(format) &&
sampleRate == other.sampleRate &&
sampleSizeInBits == other.sampleSizeInBits &&
channels == other.channels &&
endian == other.endian &&
signed == other.signed &&
frameSizeInBits == other.frameSizeInBits &&
frameRate == other.frameRate;
}
return false;
}
/**
* Checks whether or not the specified <CODE>Format</CODE> <EM>matches</EM>
* this <CODE>AudioFormat</CODE>.
* Matches only compares the attributes that are defined in the specified
* <CODE>Format</CODE>, unspecified attributes are ignored.
* <p>
* The two <CODE>Format</CODE> objects do not have to be of the same class to
* match. For example, if "A" are "B" are being compared, a
* match is possible if "A" is derived from "B"
* or "B" is derived from "A". (The compared attributes must still match, or
* <CODE>matches</CODE> fails.)
* @param format The <CODE>Format</CODE> to compare with this one.
* @return <CODE>true</CODE> if the specified <CODE>Format</CODE> matches this one,
* <CODE>false</CODE> if it does not.
*/
public boolean matches(Format format) {
if (!super.matches(format))
return false;
if (!(format instanceof AudioFormat))
return true;
AudioFormat other = (AudioFormat) format;
return
(sampleRate == NOT_SPECIFIED || other.sampleRate == NOT_SPECIFIED ||
sampleRate == other.sampleRate) &&
(sampleSizeInBits == NOT_SPECIFIED || other.sampleSizeInBits == NOT_SPECIFIED ||
sampleSizeInBits == other.sampleSizeInBits) &&
(channels == NOT_SPECIFIED || other.channels == NOT_SPECIFIED ||
channels == other.channels) &&
(endian == NOT_SPECIFIED || other.endian == NOT_SPECIFIED ||
endian == other.endian) &&
(signed == NOT_SPECIFIED || other.signed == NOT_SPECIFIED ||
signed == other.signed) &&
(frameSizeInBits == NOT_SPECIFIED || other.frameSizeInBits == NOT_SPECIFIED ||
frameSizeInBits == other.frameSizeInBits) &&
(frameRate == NOT_SPECIFIED || other.frameRate == NOT_SPECIFIED ||
frameRate == other.frameRate);
}
/**
* Finds the attributes shared by two matching <CODE>Format</CODE> objects.
* If the specified <CODE>Format</CODE> does not match this one, the result is
* undefined.
* @param The matching <CODE>Format</CODE> to intersect with this
* <CODE>AudioFormat</CODE>.
* @return A <CODE>Format</CODE> object
* with its attributes set to those attributes common to both
* <CODE>Format</CODE> objects.
* @see #matches
*/
public Format intersects(Format format) {
Format fmt;
if ((fmt = super.intersects(format)) == null)
return null;
if (!(fmt instanceof AudioFormat))
return fmt;
AudioFormat other = (AudioFormat)format;
AudioFormat res = (AudioFormat)fmt;
res.sampleRate = (sampleRate != NOT_SPECIFIED ?
sampleRate : other.sampleRate);
res.sampleSizeInBits = (sampleSizeInBits != NOT_SPECIFIED ?
sampleSizeInBits : other.sampleSizeInBits);
res.channels = (channels != NOT_SPECIFIED ?
channels : other.channels);
res.endian = (endian != NOT_SPECIFIED ?
endian : other.endian);
res.signed = (signed != NOT_SPECIFIED ?
signed : other.signed);
res.frameSizeInBits = (frameSizeInBits != NOT_SPECIFIED ?
frameSizeInBits : other.frameSizeInBits);
res.frameRate = (frameRate != NOT_SPECIFIED ?
frameRate : other.frameRate);
return res;
}
/**
* Creates a clone of this <code>AudioFormat</code> by copying each
* field to the clone.
* @return A clone of this <code>AudioFormat</code>.
*/
public Object clone() {
AudioFormat f = new AudioFormat(encoding);
f.copy(this);
return f;
}
/**
* Copies the attributes from the specified
* <CODE>Format</CODE> into this <CODE>AudioFormat</CODE>.
* @param f The <CODE>Format</CODE> to copy the attributes from.
*/
protected void copy(Format f) {
super.copy(f);
AudioFormat other = (AudioFormat) f;
sampleRate = other.sampleRate;
sampleSizeInBits = other.sampleSizeInBits;
channels = other.channels;
endian = other.endian;
signed = other.signed;
frameSizeInBits = other.frameSizeInBits;
frameRate = other.frameRate;
}
}
|