package uk.co.mmscomputing.sound.provider; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.LineUnavailableException; import uk.co.mmscomputing.concurrent.ArrayBlockingQueue; class TargetDataLine extends DataLine implements javax.sound.sampled.TargetDataLine{ private ArrayBlockingQueue queue=new ArrayBlockingQueue(1); TargetDataLine(){ super(); } // TargetDataLine Interface public void open()throws LineUnavailableException{ open(Mixer.format); } public void open(AudioFormat format)throws LineUnavailableException{ open(format,getBufferSize()); } public void open(AudioFormat format, int bufferSize)throws LineUnavailableException{ super.open(); if(!format.matches(Mixer.format)){ throw new IllegalArgumentException( getClass().getName()+".open(AudioFormat format, int bufferSize) :\n\t." +"format does not match Mixer format" ); } if(bufferSize<getBufferSize()){ // make sure there is space for whole queue buffer throw new IllegalArgumentException( getClass().getName()+".open(AudioFormat format, int bufferSize) :\n\t." +"parameter bufferSize too small ["+bufferSize+" < "+getBufferSize()+"]" ); } } public void drain(){ // if(!isOpen()){ return; } flush(); } public void flush(){ // discard buffers queue.clear(); } public void start(){ flush(); super.start(); // activate } public void close(){ super.close(); // close flush(); queue.offer(new byte[0]); // release blocked read } public int read(byte[] buf, int off, int len){ if(!isOpen()){ throw new IllegalStateException(getClass().getName()+".read(byte[] buf, int off, int len): Line is not open."); } if(buf==null){ throw new NullPointerException(getClass().getName()+".read(byte[] buf, int off, int len): b is null"); } if((off<0)||(len<0)||(buf.length<(off+len))){ throw new IndexOutOfBoundsException(getClass().getName()+".read(byte[] buf, int off, int len): index off or len out of bounds."); } if(len<getBufferSize()){ // make sure there is space for whole queue buffer throw new IllegalArgumentException( getClass().getName()+".read(byte[] buf, int off, int len) :\n\t" +"parameter len smaller then audio output buffer size ["+len+" < "+getBufferSize()+"]" ); } try{ byte[] b=(byte[])queue.take(); // len=b.length; System.arraycopy(b,0,buf,off,len); return len; }catch(InterruptedException ie){ return -1; } } // TargetDataLine // Called from Mixer microphone thread. // buf contains default sound input data (microphone) boolean offer(byte[] buf){ if(queue.isFull()){return false;} // avoid synchronized methods as far as possible return queue.offer(buf); // offer only, don't want microphone thread to block! } }