[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