/*
* Mobicents Media Gateway
*
* The source code contained in this file is in in the public domain.
* It can be used in any project or product without prior permission,
* license or royalty payments. There is NO WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION,
* THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
* AND DATA ACCURACY. We do not warrant or make any representations
* regarding the use of the software or the results thereof, including
* but not limited to the correctness, accuracy, reliability or
* usefulness of the software.
*/
package org.mobicents.media.server.impl.resource.fft;
import java.io.IOException;
import org.mobicents.media.Format;
import org.apache.log4j.Logger;
import org.mobicents.media.Buffer;
import org.mobicents.media.format.AudioFormat;
import org.mobicents.media.server.impl.AbstractSink;
import org.mobicents.media.server.spi.Endpoint;
/**
*
* @author Oleg Kulikov
*/
public class SpectraAnalyzer extends AbstractSink {
private Endpoint endpoint;
public SpectraAnalyzer(String name) {
super(name);
}
private final static AudioFormat LINEAR_AUDIO = new AudioFormat(AudioFormat.LINEAR, 8000, 16, 1,
AudioFormat.LITTLE_ENDIAN, AudioFormat.SIGNED);
private int offset = 0;
private byte[] localBuffer = new byte[16000];
private FFT fft = new FFT();
private static transient Logger logger = Logger.getLogger(SpectraAnalyzer.class);
private double[] mod(Complex[] x) {
double[] res = new double[x.length];
for (int i = 0; i < res.length; i++) {
res[i] = Math.sqrt(x[i].re() * x[i].re() + x[i].im() * x[i].im());
}
return res;
}
protected void sendEvent(double[] spectra) {
SpectrumEvent evt = new SpectrumEvent(this, spectra);
sendEvent(evt);
}
public void onMediaTransfer(Buffer buffer) throws IOException {
byte[] data = (byte[]) buffer.getData();
int len = Math.min(16000 - offset, buffer.getLength());
System.arraycopy(data, buffer.getOffset(), localBuffer, offset, len);
offset += len;
// buffer full?
if (offset == 16000) {
double[] media = new double[8000];
int j = 0;
for (int i = 0; i < media.length; i++) {
media[i] = (localBuffer[j++] & 0xff) | (localBuffer[j++] << 8);
}
// resampling
Complex[] signal = new Complex[8192];
double k = (double) (media.length - 1) / (double) (signal.length);
for (int i = 0; i < signal.length; i++) {
int p = (int) (k * i);
int q = (int) (k * i) + 1;
double K = (media[q] - media[p]) * media.length;
double dx = (double) i / (double) signal.length - (double) p / (double) media.length;
signal[i] = new Complex(media[p] + K * dx, 0);
}
localBuffer = new byte[16000];
offset = 0;
Complex[] sp = fft.fft(signal);
double[] res = mod(sp);
sendEvent(res);
}
}
/**
* (Non Java-doc.)
*
* @see org.mobicents.media.MediaSink.isAcceptable(Format).
*/
public boolean isAcceptable(Format fmt) {
return fmt.matches(LINEAR_AUDIO);
}
public Format[] getFormats() {
return new Format[]{LINEAR_AUDIO};
}
}