[speex-dev] q about jspeex
Ulrich B. Staudinger
us at die-horde.de
Fri Oct 31 06:04:41 PST 2003
hi
tried it with a pipedinputstream and pipedoutputstream but it still blocks.
<p>t.input = (TargetDataLine) AudioSystem.getLine(targetInfo);
AudioInputStream auin=new AudioInputStream(t.input);
PipedOutputStream pout=new PipedOutputStream();
PipedInputStream pin=new PipedInputStream(pout);
pcm2speex=new Pcm2SpeexAudioInputStream(pin, format,
AudioSystem.NOT_SPECIFIED);
[...]
int n=auin.read(frame, 0, frame.length);
System.out.println(""+n+" bytes read.");
pout.write(frame);
int m=pcm2speex.read(frame, 0, frame.length);
System.out.println(""+m+" bytes read - 2.");
<p>output:
root at mainframe:/home/uls/eclipse/avrelay# java TestClient
started.
Opening connection to server.
Connecting ...
Session joined.
Opening mic
Mic opened
Constructing speex encoder.
Speex encoder constructed.
*** Speex info:
Bitrate: 8000
Frame size: 160
Complexity: 3
Mode: 3
Sampling rate: 8000
relative quality: 0.0
*** end of speex info
everything ok in writer
1280 bytes read.
root at mainframe:/home/uls/eclipse/avrelay#
it reads everything correctly, but pcm2speex still blocks ... does it
await a header ? can i pipe over the direct pcm data or does it wait for
some sort header?
<p>thanks,
ulrich
<p>Ulrich B. Staudinger wrote:
> Hi Marc,
> thanks for the quick reply.
>
> Marc Gimpel wrote:
>
>> It would appear the the 'pcm2speex.read(frame, 0, frame.length)'
>> is blocking which means that it is waiting for data from the
>> underlying inputstream (i.e.AudioInputStream(t.input)). If it could
>> read sufficient data it would transcode it. If it recieved an EOF, it
>> should do some zero padding and then transcode it. Are you sure that
>> you are receiving data from the underlying inputstream???
>
>
> Yes, it can recieve data from the underlying input stream.
> If i read directly from the audioinputstream with
>
> auin=new AudioInputStream(t.input);
> //int n=pcm2speex.read(frame, 0, frame.length);
> int n=auin.read(frame, 0, frame.length);
>
> i can read the specified frame length of bytes repetively. What else
> could be the cause for blocking? I am really glad about every hint!
>
>> One point to note though is that is you are receiving 44kHz audio,
>> it will try to encode this as UWB (i.e. pretending it's 32kHz
>> sampling rate), which means that to encode 1 speex packet you are
>> going to need 640 samples, or 1280 bytes (which should compress down
>> to something like 29 bytes because the quality setting should be 3 by
>> default).
>
>
> what about piping the input streams? can't i manually read 640 samples
> from my AudioInputStream (which works) and hand them to a pipe
> (PipedInputStream connected with an PipedOutputStream) which ends in
> an InputStream in the Pcm2Speex constructor?
>
>> Having said this, jspeex does provide an SPI interface so you
>> should be able to ask JavaSound to give you directly a a Speex
>> AudioInputStream. It's coded although I admit that I never got round
>> to testing it so it might not work. It does work for the decoding,
>> that I'm sure of in any case.
>
>
> that's interesting ... i have to look into this, but am not really
> that familiar with SPI ... more with Swing and user interfaces ;-)
>
> I attached my TestClient.java, maybe it's of help ... Just press
> 'join' if you actually start it ...
>
> best regards,
> ulrich
>
>------------------------------------------------------------------------
>
>/*
> * Created on Oct 20, 2003
> *
> * AVRelay
> *
> */
>
>/**
> * write comment here
> *
> * @author uls
> */
>
>import java.awt.GridLayout;
>import java.awt.event.ActionEvent;
>import java.awt.event.ActionListener;
>import java.io.DataInputStream;
>import java.io.DataOutputStream;
>import java.io.PipedInputStream;
>import java.io.PipedOutputStream;
>import java.net.Socket;
>import java.util.Random;
>import java.util.Vector;
>
>import javax.sound.sampled.AudioFormat;
>import javax.sound.sampled.AudioSystem;
>import javax.sound.sampled.AudioInputStream;
>import javax.sound.sampled.DataLine;
>import javax.sound.sampled.SourceDataLine;
>import javax.sound.sampled.TargetDataLine;
>import javax.swing.JButton;
>import javax.swing.JFrame;
>import javax.swing.JLabel;
>import javax.swing.JTextField;
>
>
>import org.xiph.speex.*;
>import org.xiph.speex.spi.*;
>
>public class TestClient {
>
>
> public SourceDataLine output=null;
> public TargetDataLine input=null;
>
> public Vector playbackBuffer=new Vector();
> public Vector recordBuffer=new Vector();
>
> public double amplevel=2;
>
> //44100 khz * 2 byte * 2 channels (stereo) = x bytes per second
>
> public int bufferlength=44100;
> public int framelength=1280;
> int frameduration=1000;
>
> //public int bufferlength=320;
>
>
> JTextField nickname, channel;
>
> TestClient(){
>
> System.out.println("started.");
> JFrame f=new JFrame("Test Client");
>
> f.getContentPane().setLayout(new GridLayout(5,5));
>
> f.getContentPane().add(new JLabel("nick"));
> nickname=new JTextField("Guest"+((int)Math.random()*100));
> f.getContentPane().add(nickname);
> f.getContentPane().add(new JLabel("channel"));
> channel=new JTextField("jdev at conference.jabber.org");
> f.getContentPane().add(channel);
>
> JButton b=new JButton("Join");
> b.addActionListener(new ActionListener(){
> public void actionPerformed(ActionEvent e){
> connect();
> }
> });
> f.getContentPane().add(b);
> JButton b1=new JButton("leave");
> b1.addActionListener(new ActionListener(){
> public void actionPerformed(ActionEvent e){
> leave();
> }
> });
> f.getContentPane().add(b1);
> f.getContentPane().add(new JLabel("Mute"));
> JTextField mute=new JTextField("nick name to mute");
> f.getContentPane().add(mute);
> JButton b2=new JButton("Mute!");
>
>
> JButton b3=new JButton("amp x 1");
> b3.addActionListener(new ActionListener(){
> public void actionPerformed(ActionEvent e){
> amplevel=1;
> }
> });
> JButton b4=new JButton("amp x 2");
> b4.addActionListener(new ActionListener(){
> public void actionPerformed(ActionEvent e){
> amplevel=1;
> }
> });
> JButton b5=new JButton("amp x 3");
> b5.addActionListener(new ActionListener(){
> public void actionPerformed(ActionEvent e){
> amplevel=1;
> }
> });
>
> f.getContentPane().add(b2);
> f.getContentPane().add(b3);
> f.getContentPane().add(b4);
> f.getContentPane().add(b5);
> f.setSize(300,200);
> f.setVisible(true);
>
> }
>
>
> public void leave(){
> try{
>
>
>
> w.stop();System.out.println(".");
> r.stop();System.out.println(".");
> s.close();System.out.println(".");
>
>
>
> System.out.println("Connection closed.");
> }
> catch(Exception e){
> e.printStackTrace();
> }
> }
>
> Writer w;
> Reader r;
> Socket s;
>
> public void connect(){
> try
> {
>
>
>
> System.out.println("Opening connection to server.");
> //DataLine.Info targetInfo = new DataLine.Info(TargetDataLine.class, format, 44100);
>
> System.out.println("Connecting ... ");
>
> s=new Socket("jabberstudio.org", 9997);
>
> DataOutputStream dout=new DataOutputStream(s.getOutputStream());
> DataInputStream din=new DataInputStream(s.getInputStream());
> dout.writeBytes("SPX:"+framelength+":"+frameduration+"\n");
> dout.writeBytes(channel.getText()+"\n");
> dout.writeBytes("\n");
> String reply=din.readLine();
>
> if(reply.equals("OK")){
>
> PipedInputStream pin=new PipedInputStream();
> PipedOutputStream pout=new PipedOutputStream();
> pin.connect(pout);
> //Loop l=new Loop();
> //l.start();
>
> //Writer w=new Writer(this, new DataOutputStream(pout));
> w=new Writer(this, dout);
> w.start();
> //Reader r=new Reader(this, new DataInputStream(pin));
>// r=new Reader(this, din);
>// r.start();
> System.out.println("Session joined. ");
>
> }
> else{
> System.out.println("ERROR: "+reply);
> }
>
> }
> catch (Exception e)
> {
> e.printStackTrace();
> }
>
> }
>
> public static void main(String[] args) {
> TestClient tp=new TestClient();
> }
>}
>
>
>class Writer extends Thread{
> TestClient t;
> public DataOutputStream dos; // the pipe to write to
>
> public static final String VERSION = "slay! ulrich staudinger - based on jspeex";
>
> public static int mode = 0;
> public static int quality = 8;
> public static int complexity = 3;
> public static int bitrate = -1;
> public static int nframes = 1;
> public static int sampleRate = 44100;
> public static float vbr_quality = -1;
> public static boolean vbr = false;
> public static boolean vad = false;
> public static boolean dtx = false;
> public static int channels = 1;
>
> //speex
> Pcm2SpeexAudioInputStream pcm2speex;
>
> /**
> * CONSTRUCTOR
> * @param t
> * @param dos
> */
> Writer(TestClient t, DataOutputStream dos){
>
> this.t=t;
> this.dos=dos;
>
> }
>
> public void run(){
>
> try{
> System.out.println("Opening mic");
>
> AudioInput ai=new AudioInput(t);
> ai.start();
>
> if(t.input==null){
> AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);
> DataLine.Info targetInfo = new DataLine.Info(TargetDataLine.class, format, 44100);
>
> t.input = (TargetDataLine) AudioSystem.getLine(targetInfo);
>
> t.input.open(format,44100);
> System.out.println(" Mic opened");
>
> t.input.start();
> AudioInputStream auin=new AudioInputStream(t.input);
> System.out.println("Constructing speex encoder.");
> pcm2speex=new Pcm2SpeexAudioInputStream(auin, format, AudioSystem.NOT_SPECIFIED);
> System.out.println("Speex encoder constructed.");
> System.out.println("*** Speex info: ");
> System.out.println("Bitrate: "+pcm2speex.getEncoder().getBitRate());
> System.out.println("Frame size: "+pcm2speex.getEncoder().getFrameSize());
> System.out.println("Complexity: "+pcm2speex.getEncoder().getComplexity());
> System.out.println("Mode: "+pcm2speex.getEncoder().getMode());
> System.out.println("Sampling rate: "+pcm2speex.getEncoder().getSamplingRate());
> System.out.println("relative quality: "+pcm2speex.getEncoder().getRelativeQuality());
> System.out.println("*** end of speex info");
>
> System.out.println("everything ok in writer");
>
>
>
> //byte[] buffer=new byte[t.bufferlength];
>
>
> double ratio=t.bufferlength/t.framelength;
>
> byte[] frame=new byte[t.framelength];
>
> while(true){
>
> int n=pcm2speex.read(frame, 0, frame.length);
> //int n=auin.read(frame, 0, frame.length);
> System.out.println(""+n+" bytes read.");
>
>
> /*
>
> //convert the byte array to an int array
> int[] iarray=new int[buffer.length/2];
> for(int i=0;i<iarray.length/2;i++){
> iarray[i]=0;
> iarray[i]+=buffer[i*2]*256;
> iarray[i]+=buffer[(i*2)+1];
>
> //compressed[(int)((double)i/ratio)]=(byte)(2*(buffer[i]));
> }
> //this int array contains 44100 (16bit) stereo samples
> //convert to mono
> int[] monoarray=new int[iarray.length/2];
> for(int i=0;i<monoarray.length;i++){
> monoarray[i]=(iarray[i]+iarray[i+2])/2;
> }
> //now we have a 44100 int array, we now have to downgrade to 8000
> //we just do a very straight forward downgrade
> int[] eightK=new int[8000];
> for(int i=0;i<eightK.length;i++){
> eightK[i]=monoarray[i*5];
> eightK[i]=monoarray[(i*5)+1];
> eightK[i]=monoarray[(i*5)+2];
> eightK[i]=monoarray[(i*5)+3];
> eightK[i]=monoarray[(i*5)+4];
> eightK[i]/=5;
> }
> //now we have a 8k int[] mono buffer
>
> //coder.
>
> */
>
> //buffer contains 44100 16 bit stereo,
> //we have to downgrade to 8000 16 bit mono
> //byte[] compressed=new byte[t.framelength+1];
> //for(int i=0;i<t.bufferlength;i++){
> //compressed[(int)((double)i/ratio)]=(byte)(2*(buffer[i]));
> //}
>
> //compress
>
>
>
> /*//do post recording amplifying
> for(int j=0;j<compressed.length;j++){
> compressed[j]=(byte)( ((int)compressed[j])*t.amplevel );
> byte b=compressed[j];
> int b1=b;
> System.out.println(""+b1);
> }*/
>
> t.recordBuffer.addElement(frame);
> }
> }
> }
> catch(Exception e){
> e.printStackTrace();
> }
>
> }
>
>}
>
>class Reader extends Thread{
> TestClient t;
> //DirectSoundWriter waveWriter;
> //SpeexDecoder speexDecoder;
>
> /**
> * speex parameters
> */
>
> public static Random random = new Random();
> public static boolean ogg = true;
> public static boolean enhanced = true;
> public static int mode = 0;
> public static int quality = 8;
> public static int complexity = 3;
> public static int bitrate = -1;
> public static int nframes = 1;
> public static int sampleRate = -1;
> public static float vbr_quality = -1;
> public static boolean vbr = false;
> public static int channels = 1;
> public static int loss = 0;
>
> DataInputStream dis;
> Reader(TestClient t, DataInputStream dis){
> this.t=t;
> this.dis=dis;
> }
>
> public void run(){
> try{
>
> if(t.output==null){
>
> System.out.println("Opening output line");
> AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);
>
> DataLine.Info sourceInfo = new DataLine.Info(SourceDataLine.class, format, 44100);
>
> t.output = (SourceDataLine) AudioSystem.getLine(sourceInfo);
>
> t.output.open(format,44100);
> System.out.println("Output line opened.");
>
>
> t.output.start();
>
> System.out.println("everything ok");
> }
>
> //byte[] buffer=new byte[t.bufferlength];
> double ratio=t.bufferlength/t.framelength;
> byte[] compressed=new byte[t.framelength+1];
>
> AudioOutput ao=new AudioOutput(t);
> ao.start();
>
>
>
>
> while(true){
>
> dis.read(compressed);
>
> //now we have an 8k 16 bit mono int array
>
>
> byte[] buffer=new byte[t.bufferlength];
>
> //decompress
>
> for(int i=0;i<t.bufferlength;i++){
> buffer[i]=compressed[(int)((double)i/ratio)];
> }
>
>
> //plaback decompressed buffer
> t.playbackBuffer.add(buffer);
>
> System.out.println("Buffer recieved."+compressed.length+" decompressed to "+buffer.length + " ... "+ao.isAlive() +" : "+t.playbackBuffer.size());
>
>// }
>
> }
>
> }
> catch(Exception e){
> e.printStackTrace();
> }
> }
>
> /**
> * from jspeexdec
> * @param packet
> * @param offset
> * @param bytes
> * @return
> */
> private boolean readSpeexHeader(byte[] packet, int offset, int bytes)
> {
> if (bytes!=80) {
> return false;
> }
> if (!"Speex ".equals(new String(packet, 0, 8))) {
> return false;
> }
> mode = packet[40+offset] & 0xFF;
> sampleRate = bytestoint(packet, offset+36);
> channels = bytestoint(packet, offset+48);
> nframes = bytestoint(packet, offset+64);
> //return speexDecoder.init(mode, sampleRate, channels, enhanced);
> return true;
> }
>
> /**
> * Converts the bytes from the given array to an integer
> * @param a - the array
> * @param i - the offset
> */
> private static int bytestoint(byte[] a, int i)
> {
> return ((a[i+3] & 0xFF) << 24) | ((a[i+2] & 0xFF) << 16) | ((a[i+1] & 0xFF) << 8) | (a[i] & 0xFF);
> }
>
>}
>
>class AudioInput extends Thread{
> TestClient t;
> AudioInput(TestClient t){
> this.t=t;
>
> }
>
> public void run(){
> while(true){
> try{
> if(t.recordBuffer.size()>0){
> byte[] buffer=(byte[])t.recordBuffer.elementAt(0);
> //t.output.write(buffer,0,buffer.length);
> t.w.dos.write(buffer,0,buffer.length);
> t.w.dos.flush();
> t.recordBuffer.removeElementAt(0);
> System.out.println("Buffersize after write: "+t.recordBuffer.size());
> }
> else{
> //System.out.println("Buffer zero! ");
> sleep(5*t.frameduration);
> }
>
> }
> catch(Exception e){
> e.printStackTrace();
> }
> }
>
> }
>}
>
>class AudioOutput extends Thread{
>
> TestClient t;
> AudioOutput(TestClient t){
> this.t=t;
> }
>
> public void run(){
> while(true){
> //System.out.println("Running ... ");
> try{
> if(t.playbackBuffer.size()>0){
> byte[] buffer=(byte[])t.playbackBuffer.elementAt(0);
> t.output.write(buffer,0,buffer.length);
>
> //t.output.flush();
> System.out.println("Buffersize after play: "+t.playbackBuffer.size());
> t.playbackBuffer.removeElementAt(0);
> }
> if(t.playbackBuffer.size()==0){
> //System.out.println("Buffer zero! ");
> sleep(50);
> }
> //while(t.output.isActive()){
> //sleep(t.frameduration);
> //sleep(10);
> //}
> }
> catch(Exception e){
> e.printStackTrace();
> }
> }
> }
>
>}
>
>class Loop extends Thread{
>
> Loop(){
>
> }
> public void run(){
> try{
> System.out.println("run");
> AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);
> DataLine.Info targetInfo = new DataLine.Info(TargetDataLine.class, format, 44100);
> DataLine.Info sourceInfo = new DataLine.Info(SourceDataLine.class, format, 44100);
> System.out.println("2");
> TargetDataLine input = (TargetDataLine) AudioSystem.getLine(targetInfo);
> SourceDataLine output = (SourceDataLine) AudioSystem.getLine(sourceInfo);
> System.out.println("3");
> input.open(format,44100);
> System.out.println("4");
> output.open(format,44100);
> System.out.println("5");
>
> input.start();
> output.start();
>
> int bufferlength=44100;
> int framelength=2757;
> System.out.println("everything ok");
> byte[] buffer=new byte[bufferlength];
> double ratio=(double)bufferlength/(double)framelength;
> byte[] compressed=new byte[framelength];
> while(true){
>
> int n=input.read(buffer, 0, buffer.length);
>
> System.out.println("compressing");
>
>
> for(int i=0;i<bufferlength;i++){
> compressed[(int)((double)i/ratio)]=(byte)(2*(buffer[i]));
> }
> System.out.println("now decompressing ");
> for(int i=0;i<bufferlength;i++){
> buffer[i]=compressed[(int)((double)i/(ratio))];
> }
>
> output.write(buffer,0,buffer.length);
>
> }
>
> }
> catch(Exception e){
>
> }
>
> }
>}
>
>
<p>
--
Ulrich B. Staudinger
http://www.die-horde.de
email: us at die-horde.de
jid: uls at jabber.org
current project: REDHORN
http://redhorn.sourceforge.net
Blog: uls at jabber.org">http://jabber.linux.it/jogger/user.php?jid=uls@jabber.org</a>
<p>--- >8 ----
List archives: http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'speex-dev-request at xiph.org'
containing only the word 'unsubscribe' in the body. No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.
More information about the Speex-dev
mailing list