/*
/ Copyright (C) 2009 Risto Känsäkoski- Sesca ISW Ltd
/
/ This file is part of SIP-Applet (www.sesca.com, www.purplescout.com)
/
/ This program is free software; you can redistribute it and/or
/ modify it under the terms of the GNU General Public License
/ as published by the Free Software Foundation; either version 2
/ of the License, or (at your option) any later version.
/
/ This program is distributed in the hope that it will be useful,
/ but WITHOUT ANY WARRANTY; without even the implied warranty of
/ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/ GNU General Public License for more details.
/
/ You should have received a copy of the GNU General Public License
/ along with this program; if not, write to the Free Software
/ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package com.sesca.audio;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;
import com.sesca.misc.Logger;
public class MicrophoneInput extends Thread implements AudioSource{
int BUFFER_SIZE=2560;
//int BUFFER_SIZE=20*320;
boolean running=false;
boolean suspended=false;
AudioFormat format;
TargetDataLine line;
AudioInputStream inputStream;
int frameSize;
byte[] frame;
AudioSourceListener listener;
// for DTMF
double f1=0;
double f2=0;
int toneDurationInMilliS=0;
long index=0;
int hz=8000;
int bitRate=8;
boolean DTMF=false;
public MicrophoneInput(AudioFormat f, int frameSize){
//init(listener, f,frameSize);
}
public void init(AudioSourceListener l, AudioFormat f, int fs) {
listener = l;
format = f;
frameSize = fs;
frame = new byte[fs];
DataLine.Info lineInfo = new DataLine.Info(TargetDataLine.class, format, BUFFER_SIZE); // Tähän
// voi
// liittää
// myös
// buffer
// sizen
if (!AudioSystem.isLineSupported(lineInfo)) {
{
Logger.error("Laitteistossa ei mikrofonitukea");
}
} else {
try {
line = (TargetDataLine) AudioSystem.getLine(lineInfo);
line.open(format); // Tähän voi liittää myös buffer sizen
} catch (LineUnavailableException e) {
e.printStackTrace();
}
if (line.isOpen()) {
line.start();
inputStream = new AudioInputStream(line);
// convert the audio stream to the selected format
// inputStream=AudioSystem.getAudioInputStream(format,inputStream);
} else {
Logger.error("Linja on kiinni");
}
}
}
public void run()
{
if (inputStream==null) return;
running=true;
try
{
while (running)
{
synchronized(this)
{
if (suspended)
{
Logger.debug("Microphoneinput suspended");
wait();
}
}
if (DTMF)
{
generateTonePackets();
}
else
{
int num=inputStream.read(frame,0,frameSize);
if (num==frameSize)
{
listener.onIncomingRawFrame(frame);
}
else if (num!=frameSize)
{
}
else
if (num<0)
{
running=false;
Logger.error("Error reading from InputStream");
}
}
}
}
catch (Exception e)
{
running=false;
e.printStackTrace();
}
}
public void halt()
{
//System.out.println("MicrophpneInput.halt()");
//System.out.println(" stopping line");
//line.stop();
//System.out.println(" line stopped");
//line.flush();
//System.out.println(" line flushed");
//suspended=true;
//System.out.println("MicrophpneInput.halt() exits");
}
public synchronized boolean unhalt()
{
//Logger.debug("Microphoneinput.unhalt");
if (suspended==true){
try {
suspended=false;
line.start();
inputStream.skip(inputStream.available());
notify();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
//Logger.debug("Microphoneinput.unhalt end");
return true;
}
public void go()
{
Logger.debug("Starting MicrophoneInput");
start();
}
public void close()
{
running=false;
halt();
try {
inputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
line.stop();
line.flush();
line.close();
}
byte[] flip(byte b[])
{
byte c[]=new byte[b.length];
int j=0;
for (int i=b.length-1;i>=0;i--)
{
c[j]=b[i];
}
return c;
}
// DTMF generation methods:
public void tone1()
{
f1=1209;
f2=697;
}
public void tone2()
{
f1=1336;
f2=697;
}
public void tone3()
{
f1=1477;
f2=697;
}
public void toneA()
{
f1=1633;
f2=697;
}
public void tone4()
{
f1=1209;
f2=770;
}
public void tone5()
{
f1=1336;
f2=770;
}
public void tone6()
{
f1=1477;
f2=770;
}
public void toneB()
{
f1=1633;
f2=770;
}
public void tone7()
{
f1=1209;
f2=852;
}
public void tone8()
{
f1=1336;
f2=852;
}
public void tone9()
{
f1=1477;
f2=852;
}
public void toneC()
{
f1=1633;
f2=852;
}
public void toneAsterisk()
{
f1=1209;
f2=941;
}
public void tone0()
{
f1=1336;
f2=941;
}
public void toneSharp()
{
f1=1477;
f2=941;
}
public void toneD()
{
f1=1633;
f2=941;
}
public void setToneDuration(int d)
{
// System.out.println("DTMFInput.setToneDuration("+d+")");
if (d<1000)d=1000;
toneDurationInMilliS=d;
}
private void generateTonePackets()
{
// System.out.println("DTMFInput.generateTone()");
//halt();
long bytesPerSecond=hz*bitRate/8;
long satsi=bytesPerSecond*toneDurationInMilliS/1000;
long framesPerSatsi=satsi/frame.length;
satsi = framesPerSatsi*frame.length;
index=0;
//Logger.debug("Satsi="+satsi);
for (int k=0;k<framesPerSatsi;k++){
long t0=System.currentTimeMillis();
for (int i=0;i<frame.length;i+=2){
//double d=128 + 63*Math.sin(index*2*Math.PI*f1/8000) + 63*Math.sin(index*2*Math.PI*f2/8000);
double d1=16383/2*Math.sin(index*2*Math.PI*f1/hz);
double d2=16383/2*Math.sin(index*2*Math.PI*f2/hz);
double d=d2+d1;
int sample=(int)d;
//little endian
frame[i]=(byte) (sample & 0xFF);
frame[i+1]=(byte) (int)((sample >> 8) & 0xFF);
//(byte)((byte)d+(byte)0);
index++;
}
//Logger.debug("k="+k+", framesize="+frame.length);
listener.onIncomingRawFrame(frame);
// sleep here
try {
int num=inputStream.read(frame,0,frameSize);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} // for k ends here
index=0;
DTMF=false;
//unhalt();
}
public void generateTone()
{
// System.out.println("MicrophoneInput.generateTone starts");
DTMF=true;
// System.out.println("MicrophoneInput.generateTone ends");
}
}