Mercurial > hg > pulseaudio
changeset 82:10aa02b5a832
* src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java:
superclass for TargetDataLine and SourceDataLine; moved open
and close here
* src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java:
chnaged the methods written so far to use Stream.java
author | iivan@town.yyz.redhat.com |
---|---|
date | Fri, 15 Aug 2008 16:39:53 -0400 |
parents | 543d5b1cef67 |
children | 3f9cc08fdbc0 |
files | ChangeLog build.xml src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java src/java/org/classpath/icedtea/pulseaudio/SimpleAudioRecorder.java src/java/org/classpath/icedtea/pulseaudio/Stream.java src/java/org/classpath/icedtea/pulseaudio/StreamEvent.java src/java/org/classpath/icedtea/pulseaudio/StreamListener.java src/native/org_classpath_icedtea_pulseaudio_Stream.c |
diffstat | 10 files changed, 172 insertions(+), 286 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Fri Aug 15 15:46:53 2008 -0400 +++ b/ChangeLog Fri Aug 15 16:39:53 2008 -0400 @@ -1,3 +1,12 @@ +2008-08-13 Ioana Ivan <iivan@redhat.com> + + * src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java: + superclass for TargetDataLine and SourceDataLine; moved open + and close here + * src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java: + chnaged the methods written so far to use Stream.java + + 2008-08-13 Ioana Ivan <iivan@redhat.com> * src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java:
--- a/build.xml Fri Aug 15 15:46:53 2008 -0400 +++ b/build.xml Fri Aug 15 16:39:53 2008 -0400 @@ -40,6 +40,7 @@ <class name="org.classpath.icedtea.pulseaudio.Stream"/> <class name="org.classpath.icedtea.pulseaudio.PulseAudioTargetDataLine"/> <class name="org.classpath.icedtea.pulseaudio.PulseAudioStreamVolumeControl"/> + <class name="org.classpath.icedtea.pulseaudio.PulseAudioDataLine"/> </javah> </target>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java Fri Aug 15 16:39:53 2008 -0400 @@ -0,0 +1,118 @@ +package org.classpath.icedtea.pulseaudio; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Semaphore; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Line; +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.LineUnavailableException; + +public abstract class PulseAudioDataLine implements Line { + + protected static final int DEFAULT_BUFFER_SIZE = 1000; + protected static final String PULSEAUDIO_FORMAT_KEY = "PulseAudioFormatKey"; + + protected String streamName = "Java Stream"; + + protected boolean isOpen = false; + protected AudioFormat[] supportedFormats = null; + protected AudioFormat currentFormat = null; + protected AudioFormat defaultFormat = null; + + + protected List<LineListener> lineListeners = new ArrayList<LineListener>();; + + protected EventLoop eventLoop = null; + protected Semaphore semaphore = new Semaphore(0); + protected Stream stream; + + + + public void open(AudioFormat format, int bufferSize) + throws LineUnavailableException { + if (isOpen) { + throw new IllegalStateException("Line is already open"); + } + + // ignore suggested buffer size + + for (AudioFormat myFormat : supportedFormats) { + if (format.matches(myFormat)) { + stream = new Stream(eventLoop.getContextPointer(), streamName, + Stream.Format.valueOf((String) myFormat + .getProperty(PULSEAUDIO_FORMAT_KEY)), + (int) format.getSampleRate(), format.getChannels()); + currentFormat = format; + isOpen = true; + } + } + // no matches found + if (!isOpen) { + throw new IllegalArgumentException("Invalid format"); + } + + Stream.StateListener openCloseListener = new Stream.StateListener() { + + @Override + public void update() { + if (stream.getState() == Stream.State.READY) { + fireLineEvent(new LineEvent(PulseAudioDataLine.this, + LineEvent.Type.OPEN, AudioSystem.NOT_SPECIFIED)); + semaphore.release(); + } else if (stream.getState() == Stream.State.TERMINATED + || stream.getState() == Stream.State.FAILED) { + fireLineEvent((new LineEvent(PulseAudioDataLine.this, + LineEvent.Type.CLOSE, AudioSystem.NOT_SPECIFIED))); + semaphore.release(); + } + } + + }; + + stream.addStateListener(openCloseListener); + + synchronized (eventLoop.threadLock) { + + connectLine(); + } + + try { + semaphore.acquire(); + } catch (InterruptedException e) { + // throw new LineUnavailableException("unable to prepare + // stream"); + } + } + + public void close() { + assert (isOpen); + + synchronized (eventLoop.threadLock) { + stream.drain(); + stream.disconnect(); + } + + try { + semaphore.acquire(); + } catch (InterruptedException e) { + // throw new LineUnavailableException("unable to prepare + // stream"); + } + + } + + private void fireLineEvent(LineEvent e) { + for (LineListener lineListener : lineListeners) { + lineListener.update(e); + } + } + + abstract void connectLine(); + + + +}
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Fri Aug 15 15:46:53 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Fri Aug 15 16:39:53 2008 -0400 @@ -38,37 +38,23 @@ package org.classpath.icedtea.pulseaudio; import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Semaphore; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Control; import javax.sound.sampled.DataLine; -import javax.sound.sampled.LineEvent; import javax.sound.sampled.LineListener; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.AudioFormat.Encoding; import javax.sound.sampled.Control.Type; -public class PulseAudioSourceDataLine implements SourceDataLine { - - private static final int DEFAULT_BUFFER_SIZE = 1000; - private static final String PULSEAUDIO_FORMAT_KEY = "PulseAudioFormatKey"; +public class PulseAudioSourceDataLine extends PulseAudioDataLine implements SourceDataLine { - private String streamName = "Java Stream"; - private EventLoop eventLoop = null; - - private boolean isOpen = false; private boolean isPaused = false; - private AudioFormat[] supportedFormats = null; - private AudioFormat currentFormat = null; - private AudioFormat defaultFormat = null; - private List<LineListener> lineListeners; private Control[] controls = null; private PulseAudioStreamMuteControl muteControl; @@ -76,10 +62,9 @@ private boolean muted; private float volume; - private Semaphore semaphore = new Semaphore(0); private long currentFramePosition = 0; - private Stream stream; + public PulseAudioSourceDataLine(EventLoop eventLoop, AudioFormat[] formats, AudioFormat defaultFormat) { @@ -112,59 +97,8 @@ public void open(AudioFormat format, int bufferSize) throws LineUnavailableException { - if (isOpen) { - throw new IllegalStateException("Line is already open"); - } - - // ignore suggested buffer size - - for (AudioFormat myFormat : supportedFormats) { - if (format.matches(myFormat)) { - stream = new Stream(eventLoop.getContextPointer(), streamName, - Stream.Format.valueOf((String) myFormat - .getProperty(PULSEAUDIO_FORMAT_KEY)), - (int) format.getSampleRate(), format.getChannels()); - currentFormat = format; - isOpen = true; - } - } - // no matches found - if (!isOpen) { - throw new IllegalArgumentException("Invalid format"); - } - - Stream.StateListener openCloseListener = new Stream.StateListener() { - - @Override - public void update() { - if (stream.getState() == Stream.State.READY) { - fireLineEvent(new LineEvent(PulseAudioSourceDataLine.this, - LineEvent.Type.OPEN, AudioSystem.NOT_SPECIFIED)); - semaphore.release(); - } else if (stream.getState() == Stream.State.TERMINATED - || stream.getState() == Stream.State.FAILED) { - fireLineEvent((new LineEvent(PulseAudioSourceDataLine.this, - LineEvent.Type.CLOSE, AudioSystem.NOT_SPECIFIED))); - semaphore.release(); - } - } - - }; - - stream.addStateListener(openCloseListener); - - synchronized (eventLoop.threadLock) { - - stream.connectForPlayback(null); - } - - try { - semaphore.acquire(); - } catch (InterruptedException e) { - // throw new LineUnavailableException("unable to prepare - // stream"); - } - + + super.open(format, bufferSize); controls = new Control[2]; volumeControl = new PulseAudioStreamVolumeControl(this); controls[0] = volumeControl; @@ -172,6 +106,10 @@ controls[1] = muteControl; } + + protected void connectLine() { + stream.connectForPlayback(null); + } public void open(AudioFormat format) throws LineUnavailableException { open(format, DEFAULT_BUFFER_SIZE); @@ -279,22 +217,6 @@ } }; - public void close() { - assert (isOpen); - - synchronized (eventLoop.threadLock) { - stream.drain(); - stream.disconnect(); - } - - try { - semaphore.acquire(); - } catch (InterruptedException e) { - // throw new LineUnavailableException("unable to prepare - // stream"); - } - - } public int getBufferSize() { // FIXME! @@ -418,11 +340,6 @@ } - private void fireLineEvent(LineEvent e) { - for (LineListener lineListener : lineListeners) { - lineListener.update(e); - } - } protected EventLoop getEventLoop() { return this.eventLoop;
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java Fri Aug 15 15:46:53 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java Fri Aug 15 16:39:53 2008 -0400 @@ -37,42 +37,20 @@ package org.classpath.icedtea.pulseaudio; -import java.io.File; + import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Semaphore; - import javax.sound.sampled.*; import javax.sound.sampled.AudioFormat.Encoding; import javax.sound.sampled.Control.Type; -import javax.sound.sampled.Port.Info; + -public class PulseAudioTargetDataLine implements TargetDataLine { +public class PulseAudioTargetDataLine extends PulseAudioDataLine implements TargetDataLine { protected boolean isOpen = false; protected boolean isPaused = false; - - private AudioFormat[] supportedFormats = null; - private AudioFormat currentFormat = null; - private AudioFormat defaultFormat = null; - - private List<LineListener> lineListeners = new LinkedList<LineListener>(); - - private List<StreamListener> streamListeners = new ArrayList<StreamListener>(); - - private String streamName = "Java Stream"; - private static final int DEFAULT_BUFFER_SIZE = 1000; - private static final String PULSEAUDIO_FORMAT_KEY = "PulseAudioFormatKey"; - - private EventLoop eventLoop = null; - - private Semaphore semaphore = new Semaphore(0); @SuppressWarnings("unused") private long streamPointer; @@ -88,16 +66,9 @@ } } - private native void native_open(long contextPointer, String streamName, - String encoding, int sampleRate, int channels, int bufferSize); - - private native void native_start(); private native int native_get_readable_size(); - private native void native_close(); - - private native int native_read(byte[] array, int remaininglength, int position); public PulseAudioTargetDataLine(EventLoop eventLoop, AudioFormat[] formats, AudioFormat defaultFormat) { supportedFormats = formats; @@ -108,64 +79,8 @@ } - public void open(AudioFormat format, int bufferSize) - throws LineUnavailableException { - System.out.println("OPEn CALLED"); - if (isOpen) { - throw new IllegalStateException("Line is already open"); - } - - // ignore suggested buffer size - - for (AudioFormat myFormat : supportedFormats) { - if (format.matches(myFormat)) { - native_open(eventLoop.getContextPointer(), streamName, - (String) myFormat.getProperty(PULSEAUDIO_FORMAT_KEY), - (int) format.getSampleRate(), format.getChannels(), - bufferSize); - currentFormat = format; - isOpen = true; - } - } - // no matches found - if (!isOpen) { - throw new IllegalArgumentException("Invalid format"); - } - - StreamListener openCloseListener = new StreamListener() { - - @Override - public void update(StreamEvent e) { - if (e.getType() == StreamEvent.Type.READY) { - fireLineEvent(new LineEvent(PulseAudioTargetDataLine.this, - LineEvent.Type.OPEN, AudioSystem.NOT_SPECIFIED)); - System.out.println("IN HERE"); - semaphore.release(); - } else if (e.getType() == StreamEvent.Type.TERMINATED - || e.getType() == StreamEvent.Type.FAILED) { - fireLineEvent((new LineEvent(PulseAudioTargetDataLine.this, - LineEvent.Type.CLOSE, AudioSystem.NOT_SPECIFIED))); - semaphore.release(); - } - } - - }; - - addStreamListener(openCloseListener); - - - - synchronized (eventLoop.threadLock) { - - native_start(); - } - - try { - semaphore.acquire(); - } catch (InterruptedException e) { - // throw new LineUnavailableException("unable to prepare - // stream"); - } + protected void connectLine() { + stream.connectForRecording(null); } public void open(AudioFormat format) throws LineUnavailableException { @@ -203,19 +118,16 @@ int position = offset; int remainingLength = length; - int availableSize; - int sizeRead = 0; while (remainingLength != 0) { synchronized (eventLoop.threadLock) { - availableSize = available(); - int toRead = native_read(data, remainingLength, position); + int bytesRead = stream.read(data, remainingLength, position); - sizeRead += toRead; - position += toRead; - remainingLength -= toRead; + sizeRead += bytesRead; + position += bytesRead; + remainingLength -= bytesRead; } @@ -289,25 +201,6 @@ } } - public void close() { - assert (isOpen); - - - synchronized (eventLoop.threadLock) { - native_close(); - } - - try { - semaphore.acquire(); - System.out.println("stream closed"); - } catch (InterruptedException e) { - // throw new LineUnavailableException("unable to prepare - // stream"); - } - - } - - private native void closeStream(); public int getBufferSize() { // TODO Auto-generated method stub @@ -365,57 +258,11 @@ public boolean isControlSupported(Type control) { // TODO Auto-generated method stub return false; + } - public void update(int status) { - synchronized (eventLoop.threadLock) { - switch (status) { - case 0: - fireStreamEvent(new StreamEvent(StreamEvent.Type.UNCONNECTED)); - break; - case 1: - fireStreamEvent(new StreamEvent(StreamEvent.Type.CREATING)); - break; - case 2: - fireStreamEvent(new StreamEvent(StreamEvent.Type.READY)); - break; - case 3: - fireStreamEvent(new StreamEvent(StreamEvent.Type.FAILED)); - break; - case 4: - fireStreamEvent(new StreamEvent(StreamEvent.Type.TERMINATED)); - break; - default: - assert ("not supposed to happen".indexOf("false") >= 0); - } - } - } - private void fireLineEvent(LineEvent e) { - for (LineListener lineListener : lineListeners) { - lineListener.update(e); - } - } + - private void fireStreamEvent(StreamEvent e) { - synchronized (streamListeners) { - for (StreamListener streamListener : streamListeners) { - streamListener.update(e); - } - } - } - - - private void addStreamListener(StreamListener listener) { - synchronized (streamListeners) { - this.streamListeners.add(listener); - } - } - - private void removeStreamListener(StreamListener listener) { - synchronized (streamListeners) { - this.streamListeners.remove(listener); - } - } } \ No newline at end of file
--- a/src/java/org/classpath/icedtea/pulseaudio/SimpleAudioRecorder.java Fri Aug 15 15:46:53 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/SimpleAudioRecorder.java Fri Aug 15 16:39:53 2008 -0400 @@ -1,3 +1,4 @@ + package org.classpath.icedtea.pulseaudio; /*
--- a/src/java/org/classpath/icedtea/pulseaudio/Stream.java Fri Aug 15 15:46:53 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/Stream.java Fri Aug 15 16:39:53 2008 -0400 @@ -96,6 +96,8 @@ private native int native_pa_stream_write(byte[] data, int offset, int length); + + private native int native_pa_stream_read(byte[] array, int length, int position); /* * private native int native_pa_stream_peek (pa_stream *p, const void @@ -366,6 +368,10 @@ public int write(byte[] data, int offset, int length) { return native_pa_stream_write(data, offset, length); } + + public int read(byte[] array, int length, int position) { + return native_pa_stream_read(array, length, position); + } /** * Read the next fragment from the buffer (for recording).
--- a/src/java/org/classpath/icedtea/pulseaudio/StreamEvent.java Fri Aug 15 15:46:53 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -package org.classpath.icedtea.pulseaudio; - -@Deprecated -public class StreamEvent { - - public enum Type { - UNCONNECTED, CREATING, READY, FAILED, TERMINATED - } - - private Type type; - - public StreamEvent(Type type) { - this.type = type; - } - - public Type getType() { - return this.type; - } - -}
--- a/src/java/org/classpath/icedtea/pulseaudio/StreamListener.java Fri Aug 15 15:46:53 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -package org.classpath.icedtea.pulseaudio; - -@Deprecated -public interface StreamListener { - - public void update(StreamEvent e); - -}
--- a/src/native/org_classpath_icedtea_pulseaudio_Stream.c Fri Aug 15 15:46:53 2008 -0400 +++ b/src/native/org_classpath_icedtea_pulseaudio_Stream.c Fri Aug 15 16:39:53 2008 -0400 @@ -45,7 +45,7 @@ } } -static void stream_read_callback(pa_stream *stream, size_t length, +/*static void stream_read_callback(pa_stream *stream, size_t length, void *userdata) { printf("stream_read_callback called\n"); @@ -61,7 +61,7 @@ callJavaVoidMethod(pulse_thread_env, context->obj, "readCallback"); } -} +}*/ static void stream_overflow_callback(pa_stream *stream, void *userdata) { printf("stream_overflow_callback called\n"); @@ -231,7 +231,7 @@ pa_stream_set_state_callback (stream, stream_state_callback, j_context); pa_stream_set_write_callback (stream, stream_write_callback, j_context); - pa_stream_set_read_callback (stream, stream_read_callback, j_context); + //pa_stream_set_read_callback (stream, stream_read_callback, j_context); pa_stream_set_overflow_callback (stream, stream_overflow_callback, j_context); pa_stream_set_underflow_callback (stream, stream_underflow_callback, j_context); // pa_stream_set_started_callback (stream, stream_started_callback, j_context); @@ -398,6 +398,21 @@ return value; } +JNIEXPORT int JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1read + (JNIEnv *env, jobject obj, jbyteArray array, jint length, jint offset) { + pa_stream *stream = getJavaPointer(env, obj, "streamPointer"); + const void *read_data = NULL; + size_t read_length = 0; + pa_stream_peek(stream, &read_data, &read_length); + if (length < read_length) { + read_length = length; + } + + (*env)->SetByteArrayRegion(env, array, offset, read_length, read_data); + pa_stream_drop(stream); + return read_length; +} + /* * Class: org_classpath_icedtea_pulseaudio_Stream * Method: native_pa_stream_writable_size