Mercurial > hg > pulseaudio
changeset 96:9a4c1d255bc6
2008-08-25 Omair Majid <omajid@redhat.com>
* src/java/org/classpath/icedtea/pulseaudio/Operation.java
(Operation): Added a check for value pointer
* src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java
Formatting fixes using eclipse's format
(connectLine): Parameter bufferSize is now used to chose buffer
attributes.
(close): Added a synchronized block to protect shared variables.
(flush): Likewise.
* src/java/org/classpath/icedtea/pulseaudio/PusleAudioDataLine.java
(open): Synchronized stream operations. Pass buffer sizes to the
connectLine function. Also added checks to ensure that the stream
actually connected.
(start): Syncrhonized stream operations.
(connectLine): changed signature from connectLine() to connectLine(int
bufferSize).
* src/java/org/classpath/icedtea/pusleaudio/PulseAudioSourceDataLine.java
(connectLine): Changed buffer values. Some buffer attributes now guessed
from the max buffer size. Synchronized stream operations.
* src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java
(connectLine): Likewise
* src/java/org/classpath/icedtea/pulseaudio/Stream.java
(native_pa_stream_connect_record): Added additional parameters for
buffers.
(addOverflowListener): Synchronized operation.
(removeOverflowListener): Likewise.
(addUnderflowListener): Likewise.
(removeUnderflowListener): Likewise.
(addPlaybackStartedListener): Likewise.
(removePlaybackStartedListener): Likewise.
(addLatencyUpdateListener): Likewise.
(removeLatencyUpdateListener): Likewise.
(addMovedListener): Likewise.
(removeMovedListener): Likewise.
(addSuspenedListener): Likewise.
(removeSuspenedListener): Likewise.
(connectForRecording): Added a paramter to pass in
StreamBufferAttributes.
* src/java/org/classpath/icedtea/pulseaudio/StreamBufferAttributes.java
Fixed SANE_DEFAULT to be a valid numer. Added extra variables to
indicate max and min values.
* src/native/org_classpath_icedtea_pulseaudio_Stream.c
(stream_state_callback): Commented out debug output.
(stream_overflow_callback): Likewise.
(stream_latency_update_callback): Likewise.
(stream_moved_callback): Likewise.
(stream_suspeneded_callback): Likewise.
(Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1connect_1playback):
Using bufferAttributes passed in to connnect the stream. Commented out
debug info. Added a check for return value.
(Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1connect_1record):
Likewise.
(Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1get_1buffer_1attr):
Fixed constructor method id. Added checks to fail if this happens again.
(set_buffer_attr_callback): Checking the new buffer_attr
(Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1set_1buffer_1attr):
Added tests to check if everything works. Added some debug info.
* unittests/org/classpath/icedtea/pusleaudio/PulseSourceDataLineTest.java:
(testPlay): Added some debug output for the test
author | Omair Majid <omajid@redhat.com> |
---|---|
date | Mon, 25 Aug 2008 12:07:04 -0400 |
parents | 23c52715cfb2 |
children | 2e4a2a022ffb |
files | src/java/org/classpath/icedtea/pulseaudio/Operation.java src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java 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/Stream.java src/java/org/classpath/icedtea/pulseaudio/StreamBufferAttributes.java src/native/org_classpath_icedtea_pulseaudio_Stream.c unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java |
diffstat | 9 files changed, 273 insertions(+), 169 deletions(-) [+] |
line wrap: on
line diff
--- a/src/java/org/classpath/icedtea/pulseaudio/Operation.java Wed Aug 20 14:27:45 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/Operation.java Mon Aug 25 12:07:04 2008 -0400 @@ -77,6 +77,7 @@ private native int native_get_state(); public Operation(long operationPointer) { + assert(operationPointer != 0); this.operationPointer = operationPointer; this.eventLoop = EventLoop.getEventLoop(); }
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java Wed Aug 20 14:27:45 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java Mon Aug 25 12:07:04 2008 -0400 @@ -71,68 +71,64 @@ private static final AudioFormat DEFAULT_FORMAT = new AudioFormat( AudioFormat.Encoding.PCM_UNSIGNED, 22050, 8, 2, 2, 22050 / 2, false); - - private static final int DEFAULT_BUFFER_SIZE = 0; public static final String DEFAULT_CLIP_NAME = "Clip"; private Object clipLock = new Object(); private boolean clipThreadStarted; private int loopsLeft; - private Semaphore clipSemaphore= new Semaphore(1); + private Semaphore clipSemaphore = new Semaphore(1); private class ClipThread extends Thread { @Override public void run() { clipThreadStarted = true; - while(loopsLeft >= 0) { + while (loopsLeft >= 0) { writeFrames(currentFrame, endFrame + 1); - if(Thread.interrupted()) { + if (Thread.interrupted()) { //Thread.currentThread().interrupt(); clipThreadStarted = false; return; } - - - - try { - //if loop(0) has been called from the mainThread, - //wait until loopsLeft has been set - clipSemaphore.acquire(); - if(loopsLeft == 0){ + + try { + //if loop(0) has been called from the mainThread, + //wait until loopsLeft has been set + clipSemaphore.acquire(); + if (loopsLeft == 0) { System.out.println("Reading to the end of the file"); - writeFrames( endFrame, getFrameLength()); + writeFrames(endFrame, getFrameLength()); return; - } else { - synchronized (clipLock) { - currentFrame = startFrame; - loopsLeft--; + } else { + synchronized (clipLock) { + currentFrame = startFrame; + loopsLeft--; + } } + clipSemaphore.release(); + } catch (InterruptedException e) { + return; } - clipSemaphore.release(); - } catch (InterruptedException e) { - return; - } - - + } } } - - private ClipThread clipThread; - - + + private ClipThread clipThread; + private void writeFrames(int startingFrame, int lastFrame) { int remainingFrames = lastFrame - startingFrame - 1; - while(remainingFrames > 0) { + while (remainingFrames > 0) { synchronized (eventLoop.threadLock) { int availableSize = stream.getWritableSize(); - int framesToWrite = Math.min(remainingFrames, availableSize / getFormat().getFrameSize()); - stream.write(data, currentFrame * getFormat().getFrameSize(), framesToWrite * getFormat().getFrameSize()); + int framesToWrite = Math.min(remainingFrames, availableSize + / getFormat().getFrameSize()); + stream.write(data, currentFrame * getFormat().getFrameSize(), + framesToWrite * getFormat().getFrameSize()); remainingFrames -= framesToWrite; currentFrame += framesToWrite; - if(Thread.interrupted()) { + if (Thread.interrupted()) { Thread.currentThread().interrupt(); break; } @@ -141,7 +137,6 @@ } } - static { try { String library = new java.io.File(".").getCanonicalPath() @@ -154,27 +149,23 @@ } } - public PulseAudioClip(EventLoop eventLoop, AudioFormat[] formats, AudioFormat defaultFormat) { + public PulseAudioClip(EventLoop eventLoop, AudioFormat[] formats, + AudioFormat defaultFormat) { supportedFormats = formats; this.eventLoop = eventLoop; this.lineListeners = new ArrayList<LineListener>(); - this.defaultFormat = defaultFormat; + this.defaultFormat = defaultFormat; this.currentFormat = defaultFormat; clipThread = new ClipThread(); } - - protected void connectLine() { + + protected void connectLine(int bufferSize) { StreamBufferAttributes bufferAttributes = new StreamBufferAttributes( - StreamBufferAttributes.SANE_DEFAULT, - StreamBufferAttributes.SANE_DEFAULT, - StreamBufferAttributes.SANE_DEFAULT, - StreamBufferAttributes.SANE_DEFAULT, - StreamBufferAttributes.SANE_DEFAULT); + bufferSize, bufferSize / 2, bufferSize / 2, bufferSize / 2, 0); - stream.connectForPlayback(null, bufferAttributes); + stream.connectForPlayback(Stream.DEFAULT_DEVICE, bufferAttributes); } - @Override public int available() { @@ -188,10 +179,12 @@ } catch (InterruptedException e) { e.printStackTrace(); } - - stream.drain(); - stream.disconnect(); - isOpen = false; + + synchronized (eventLoop.threadLock) { + drain(); + stream.disconnect(); + isOpen = false; + } } @Override @@ -209,7 +202,9 @@ @Override public void flush() { - stream.flush(); + synchronized (eventLoop.threadLock) { + stream.flush(); + } } @Override @@ -260,7 +255,7 @@ @Override public long getLongFramePosition() { - synchronized(clipLock) { + synchronized (clipLock) { return framesSinceOpen; } } @@ -270,14 +265,14 @@ if (!isOpen) { return AudioSystem.NOT_SPECIFIED; } - synchronized(clipLock) { + synchronized (clipLock) { return frameCount / currentFormat.getFrameSize(); } } @Override public long getMicrosecondPosition() { - synchronized(clipLock) { + synchronized (clipLock) { return framesSinceOpen / currentFormat.getFrameSize(); } } @@ -308,22 +303,22 @@ @Override public void loop(int count) { System.out.println("Loop " + count + " called"); - if(clipThreadStarted && count != 0) { + if (clipThreadStarted && count != 0) { //Do nothing; behavior not specified by the Java API return; } - synchronized(clipLock) { - if(currentFrame > endFrame) { + synchronized (clipLock) { + if (currentFrame > endFrame) { loopsLeft = 0; } else { - loopsLeft = count; + loopsLeft = count; } } if (!clipThread.isAlive()) { clipThread = new ClipThread(); clipThread.start(); - } - + } + } @Override @@ -338,7 +333,7 @@ super.open(format); this.data = new byte[bufferSize]; System.arraycopy(data, offset, this.data, 0, bufferSize); - frameCount = bufferSize / format.getFrameSize(); + frameCount = bufferSize / format.getFrameSize(); isOpen = true; } @@ -350,7 +345,6 @@ stream.read(buffer, 0, buffer.length); open(stream.getFormat(), buffer, 0, buffer.length); - } @@ -365,8 +359,8 @@ if (frames > frameCount) { throw new IllegalArgumentException("incorreft frame value"); } - - synchronized(clipLock) { + + synchronized (clipLock) { currentFrame = frames; } @@ -383,7 +377,7 @@ "ending point must be greater than or equal to the starting point"); } - synchronized(clipLock) { + synchronized (clipLock) { startFrame = start; endFrame = end; } @@ -393,7 +387,7 @@ @Override public void setMicrosecondPosition(long microseconds) { float frameIndex = microseconds * currentFormat.getFrameRate(); - synchronized(clipLock) { + synchronized (clipLock) { currentFrame = (int) frameIndex; } @@ -401,18 +395,17 @@ @Override public void start() { - if(!clipThread.isAlive()) { - synchronized(clipLock) { + if (!clipThread.isAlive()) { + synchronized (clipLock) { loopsLeft = 0; } clipThread = new ClipThread(); clipThread.start(); } } - - + public void stop() { - if(clipThread.isAlive()) { + if (clipThread.isAlive()) { clipThread.interrupt(); } try { @@ -420,7 +413,7 @@ } catch (InterruptedException e) { e.printStackTrace(); } - synchronized(clipLock) { + synchronized (clipLock) { currentFrame = 0; loopsLeft = 0; }
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java Wed Aug 20 14:27:45 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java Mon Aug 25 12:07:04 2008 -0400 @@ -14,40 +14,38 @@ public abstract class PulseAudioDataLine implements Line { - protected static final int DEFAULT_BUFFER_SIZE = 1000; + protected static final int DEFAULT_BUFFER_SIZE = StreamBufferAttributes.SANE_DEFAULT; protected static final String PULSEAUDIO_FORMAT_KEY = "PulseAudioFormatKey"; protected String streamName = "Java Stream"; - + protected boolean isOpen = false; private boolean isPaused = 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 { + 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()); + synchronized (eventLoop.threadLock) { + stream = new Stream(eventLoop.getContextPointer(), + streamName, Stream.Format.valueOf((String) myFormat + .getProperty(PULSEAUDIO_FORMAT_KEY)), + (int) format.getSampleRate(), format.getChannels()); + + } currentFormat = format; isOpen = true; } @@ -61,40 +59,47 @@ @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(); + synchronized (eventLoop.threadLock) { + 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(); + connectLine(bufferSize); } try { semaphore.acquire(); + synchronized (eventLoop.threadLock) { + if (stream.getState() != Stream.State.READY) { + stream.disconnect(); + throw new LineUnavailableException( + "unable to obtain a line"); + } + } } catch (InterruptedException e) { - // throw new LineUnavailableException("unable to prepare - // stream"); + throw new LineUnavailableException("unable to prepare stream"); } + } - + public void open(AudioFormat format) throws LineUnavailableException { open(format, DEFAULT_BUFFER_SIZE); } - + public void open() throws LineUnavailableException { // pick a random format if (defaultFormat == null) { @@ -105,12 +110,11 @@ open(defaultFormat, DEFAULT_BUFFER_SIZE); } - public void close() { assert (isOpen); synchronized (eventLoop.threadLock) { - //drain(); + // drain(); stream.disconnect(); } @@ -122,10 +126,12 @@ } } - + public void start() { if (isPaused) { - stream.cork(false); + synchronized (eventLoop.threadLock) { + stream.cork(false); + } isPaused = false; } @@ -143,7 +149,7 @@ isPaused = true; } - + public void addLineListener(LineListener listener) { this.lineListeners.add(listener); } @@ -151,20 +157,19 @@ public void removeLineListener(LineListener listener) { this.lineListeners.remove(listener); } - + private void fireLineEvent(LineEvent e) { for (LineListener lineListener : lineListeners) { lineListener.update(e); } } - abstract void connectLine(); + abstract void connectLine(int bufferSize); + abstract void drain(); - + public boolean isOpen() { return isOpen; } - - }
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Wed Aug 20 14:27:45 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Mon Aug 25 12:07:04 2008 -0400 @@ -100,15 +100,13 @@ } - protected void connectLine() { + protected void connectLine(int bufferSize) { StreamBufferAttributes bufferAttributes = new StreamBufferAttributes( - StreamBufferAttributes.SANE_DEFAULT, - StreamBufferAttributes.SANE_DEFAULT, - StreamBufferAttributes.SANE_DEFAULT, - StreamBufferAttributes.SANE_DEFAULT, - StreamBufferAttributes.SANE_DEFAULT); + bufferSize, bufferSize / 4, bufferSize / 4, bufferSize / 10, 0); - stream.connectForPlayback(null, bufferAttributes); + synchronized (eventLoop.threadLock) { + stream.connectForPlayback(Stream.DEFAULT_DEVICE, bufferAttributes); + } } @Override
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java Wed Aug 20 14:27:45 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java Mon Aug 25 12:07:04 2008 -0400 @@ -68,8 +68,12 @@ } - protected void connectLine() { - stream.connectForRecording(null); + protected void connectLine(int bufferSize) { + StreamBufferAttributes bufferAttributes = new StreamBufferAttributes( + bufferSize, 0, 0, 0, bufferSize / 10); + synchronized (eventLoop.threadLock) { + stream.connectForRecording(Stream.DEFAULT_DEVICE, bufferAttributes); + } } @Override
--- a/src/java/org/classpath/icedtea/pulseaudio/Stream.java Wed Aug 20 14:27:45 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/Stream.java Mon Aug 25 12:07:04 2008 -0400 @@ -55,6 +55,8 @@ PA_SAMPLE_U8, PA_SAMPLE_ULAW, PA_SAMPLE_ALAW, PA_SAMPLE_S16LE, PA_SAMPLE_S16BE, PA_SAMPLE_FLOAT32LE, PA_SAMPLE_FLOAT32BE, PA_SAMPLE_S32LE, PA_SAMPLE_S32BE } + public static final String DEFAULT_DEVICE = null; + @SuppressWarnings("unused") private long streamPointer; @@ -91,8 +93,11 @@ int bufferFragmentSize, int flags, long volumePointer, long sync_streamPointer); - private native int native_pa_stream_connect_record(String device, - long buffer_attrPointer, int flags); + private native int native_pa_stream_connect_record(String name, + int bufferMaxLength, int bufferTargetLength, + int bufferPreBuffering, int bufferMinimumRequest, + int bufferFragmentSize, int flags, long volumePointer, + long sync_streamPointer); private native int native_pa_stream_disconnect(); @@ -232,51 +237,75 @@ } public void addOverflowListener(OverflowListener listener) { - overflowListeners.add(listener); + synchronized (overflowListeners) { + overflowListeners.add(listener); + } } public void removeOverflowListener(OverflowListener listener) { - overflowListeners.remove(listener); + synchronized (overflowListeners) { + overflowListeners.remove(listener); + } } public void addUnderflowListener(UnderflowListener listener) { - underflowListeners.add(listener); + synchronized (underflowListeners) { + underflowListeners.add(listener); + } } public void removeUnderflowListener(UnderflowListener listener) { - underflowListeners.remove(listener); + synchronized (underflowListeners) { + underflowListeners.remove(listener); + } } public void addPlaybackStartedListener(PlaybackStartedListener listener) { - playbackStartedListeners.add(listener); + synchronized (playbackStartedListeners) { + playbackStartedListeners.add(listener); + } } public void removePlaybackStartedListener(PlaybackStartedListener listener) { - playbackStartedListeners.remove(listener); + synchronized (playbackStartedListeners) { + playbackStartedListeners.remove(listener); + } } public void addLatencyUpdateListener(LatencyUpdateListener listener) { - latencyUpdateListeners.add(listener); + synchronized (latencyUpdateListeners) { + latencyUpdateListeners.add(listener); + } } public void removeLatencyUpdateListener(LatencyUpdateListener listener) { - latencyUpdateListeners.remove(listener); + synchronized (playbackStartedListeners) { + latencyUpdateListeners.remove(listener); + } } public void addMovedListener(MovedListener listener) { - movedListeners.add(listener); + synchronized (movedListeners) { + movedListeners.add(listener); + } } public void removeMovedListener(MovedListener listener) { - movedListeners.remove(listener); + synchronized (movedListeners) { + movedListeners.remove(listener); + } } public void addSuspendedListener(SuspendedListener listener) { - suspendedListeners.add(listener); + synchronized (suspendedListeners) { + suspendedListeners.add(listener); + } } public void removeSuspendedListener(SuspendedListener listener) { - suspendedListeners.remove(listener); + synchronized (suspendedListeners) { + suspendedListeners.remove(listener); + } } public Stream.State getState() { @@ -337,6 +366,8 @@ * Connect the stream to a sink * * @param deviceName + * the device to connect to. use + * <code>null</code for the default device */ public void connectForPlayback(String deviceName, StreamBufferAttributes bufferAttributes) { @@ -353,8 +384,14 @@ * Connect the stream to a source. * */ - public void connectForRecording(String deviceName) { - int returnValue = native_pa_stream_connect_record(deviceName, 0, 0); + public void connectForRecording(String deviceName, + StreamBufferAttributes bufferAttributes) { + + int returnValue = native_pa_stream_connect_record(deviceName, + bufferAttributes.getMaxLength(), bufferAttributes + .getTargetLength(), bufferAttributes.getPreBuffering(), + bufferAttributes.getMinimumRequest(), bufferAttributes + .getFragmentSize(), 0, 0, 0); assert (returnValue == 0); } @@ -459,6 +496,7 @@ @SuppressWarnings("unused") private void overflowCallback() { + System.out.println("overflowCallback called"); synchronized (overflowListeners) { for (OverflowListener listener : overflowListeners) { listener.update();
--- a/src/java/org/classpath/icedtea/pulseaudio/StreamBufferAttributes.java Wed Aug 20 14:27:45 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/StreamBufferAttributes.java Mon Aug 25 12:07:04 2008 -0400 @@ -2,8 +2,14 @@ public class StreamBufferAttributes { - public static final int SANE_DEFAULT = -1; + public static final int SANE_DEFAULT = 50000; + + // FIXME need to set these to proper values + // integer.max_value will crash the program! + public static final int MAX_VALUE = Integer.MAX_VALUE; + public static final int MIN_VALUE = 0; + private int maxLength; private int targetLength; private int preBuffering;
--- a/src/native/org_classpath_icedtea_pulseaudio_Stream.c Wed Aug 20 14:27:45 2008 -0400 +++ b/src/native/org_classpath_icedtea_pulseaudio_Stream.c Mon Aug 25 12:07:04 2008 -0400 @@ -62,7 +62,7 @@ } static void stream_state_callback(pa_stream* stream, void *userdata) { - printf("stream_state_callback called\n"); + //printf("stream_state_callback called\n"); java_context* context = userdata; assert(stream); @@ -114,7 +114,7 @@ } static void stream_overflow_callback(pa_stream *stream, void *userdata) { - printf("stream_overflow_callback called\n"); + //printf("stream_overflow_callback called\n"); java_context* context = userdata; assert(stream); @@ -165,7 +165,7 @@ */ static void stream_latency_update_callback(pa_stream *stream, void *userdata) { - printf("stream_latency_update_callback called\n"); + // printf("stream_latency_update_callback called\n"); java_context* context = userdata; assert(stream); @@ -182,7 +182,7 @@ } static void stream_moved_callback(pa_stream *stream, void *userdata) { - printf("stream_moved_callback called\n"); + // printf("stream_moved_callback called\n"); java_context* context = userdata; assert(stream); @@ -199,7 +199,7 @@ } static void stream_suspended_callback(pa_stream *stream, void *userdata) { - printf("stream_suspended_callback called\n"); + // printf("stream_suspended_callback called\n"); java_context* context = userdata; assert(stream); @@ -224,7 +224,7 @@ (JNIEnv* env, jobject obj, jlong contextPointer, jstring nameString, jstring encodingString, jint sampleRate, jint channels) { - printf("creating a new PulseAudio stream\n"); + // printf("creating a new PulseAudio stream\n"); java_context* j_context = malloc(sizeof(java_context)); assert(j_context); @@ -379,13 +379,22 @@ jlong volumePointer, jlong sync_streamPointer) { pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, "streamPointer"); - pa_buffer_attr buffer_attributes; + pa_buffer_attr buffer_attr; + + memset(&buffer_attr, 0, sizeof(buffer_attr)); - buffer_attributes.maxlength = bufferMaxLength; - buffer_attributes.tlength = bufferTargetLength; - buffer_attributes.prebuf = bufferPreBuffering; - buffer_attributes.minreq = bufferMinimumRequest; - buffer_attributes.fragsize = bufferFragmentSize; + buffer_attr.maxlength = (uint32_t) bufferMaxLength; + buffer_attr.tlength = (uint32_t) bufferTargetLength; + buffer_attr.prebuf = (uint32_t) bufferPreBuffering; + buffer_attr.minreq = (uint32_t) bufferMinimumRequest; + + /* + printf("buffer maxlength: %u\n", buffer_attr.maxlength); + printf("buffer tlength: %u\n", buffer_attr.tlength); + printf("buffer prebuf: %u\n", buffer_attr.prebuf); + printf("buffer minreq: %u\n", buffer_attr.minreq); + printf("buffer fragsize: %u\n", buffer_attr.fragsize); + */ const char* dev = NULL; if (device != NULL) { @@ -394,7 +403,8 @@ return -1; // oome thrown } } - int value = pa_stream_connect_playback(stream, dev, NULL, 0, NULL, NULL); + int value = pa_stream_connect_playback(stream, dev, &buffer_attr, 0, NULL, NULL); + assert(value >= 0); if (dev != NULL) { (*env)->ReleaseStringUTFChars(env, device, dev); dev = NULL; @@ -405,12 +415,30 @@ /* * Class: org_classpath_icedtea_pulseaudio_Stream * Method: native_pa_stream_connect_record - * Signature: (Ljava/lang/String;JI)I + * Signature: (Ljava/lang/String;IIIIIIJJ)I */ JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1connect_1record -(JNIEnv* env, jobject obj, jstring device, jlong bufferPointer, jint flags) { +(JNIEnv* env, jobject obj, jstring device, jint bufferMaxLength, + jint bufferTargetLength, jint bufferPreBuffering, + jint bufferMinimumRequest, jint bufferFragmentSize, jint flags, + jlong volumePointer, jlong sync_streamPointer) { + pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, "streamPointer"); assert(stream); + + pa_buffer_attr buffer_attr; + memset(&buffer_attr, 0 , sizeof(buffer_attr)); + buffer_attr.maxlength = (uint32_t) bufferMaxLength; + buffer_attr.fragsize = (uint32_t) bufferFragmentSize; + + /* + printf("buffer maxlength: %u\n", buffer_attr.maxlength); + printf("buffer tlength: %u\n", buffer_attr.tlength); + printf("buffer prebuf: %u\n", buffer_attr.prebuf); + printf("buffer minreq: %u\n", buffer_attr.minreq); + printf("buffer fragsize: %u\n", buffer_attr.fragsize); + */ + const char* dev = NULL; if (device != NULL) { dev = (*env)->GetStringUTFChars(env, device, NULL); @@ -418,9 +446,10 @@ return -1; // oome thrown } } - pa_buffer_attr* buffer = convertJavaLongToPointer(bufferPointer); - assert(buffer == NULL); - int value = pa_stream_connect_record(stream, dev, buffer, flags); + + int value = pa_stream_connect_record(stream, dev, &buffer_attr, flags); + assert(value >= 0); + if (dev != NULL) { (*env)->ReleaseStringUTFChars(env, device, dev); dev = NULL; @@ -709,14 +738,19 @@ */ JNIEXPORT jobject JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1get_1buffer_1attr (JNIEnv* env, jobject obj) { + + // printf("in native_pa_stream_get_buffer_attributes"); + pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, "streamPointer"); assert(stream); const pa_buffer_attr* buffer = pa_stream_get_buffer_attr(stream); + assert(buffer); const char* class_name = "Lorg/classpath/icedtea/pulseaudio/StreamBufferAttributes;"; jclass cls = (*env)->FindClass(env, class_name); - jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "<init>", "V"); - + assert(cls); + jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "<init>", "(IIIII)V"); + assert(constructor_mid); jint maxLength = buffer->maxlength; jint targetLength = buffer->tlength; jint preBuffering = buffer->prebuf; @@ -725,18 +759,23 @@ jobject return_object = (*env)->NewObject(env, cls, constructor_mid, maxLength, targetLength, preBuffering, minimumRequest, fragmentSize); + assert(return_object); return return_object; } -static void set_buffer_attr_callback(pa_stream* stream, int success, void* userdata) { +static void set_buffer_attr_callback(pa_stream* stream, int success, + void* userdata) { + + const pa_buffer_attr* buffer = pa_stream_get_buffer_attr(stream); + assert(buffer); + assert(success); JNIEnv* env = pulse_thread_env; notifyWaitingOperations(env); } - /* * Class: org_classpath_icedtea_pulseaudio_Stream * Method: native_pa_stream_set_buffer_attr @@ -749,30 +788,46 @@ assert(stream); jclass cls = (*env)->GetObjectClass(env, bufferAttributeObject); + assert(cls); - pa_buffer_attr* buffer = malloc(sizeof(pa_buffer_attr)); + pa_buffer_attr buffer; jmethodID getMaxLengthID = (*env)->GetMethodID(env,cls,"getMaxLength","()I"); - buffer->maxlength = (*env)->CallIntMethod(env, bufferAttributeObject, getMaxLengthID); + assert(getMaxLengthID); + buffer.maxlength = (uint32_t) (*env)->CallIntMethod(env, bufferAttributeObject, getMaxLengthID); jmethodID getTargetLengthID = (*env)->GetMethodID(env,cls,"getTargetLength","()I"); - buffer->tlength = (*env)->CallIntMethod(env, bufferAttributeObject, getTargetLengthID); + assert(getTargetLengthID); + buffer.tlength = (uint32_t) (*env)->CallIntMethod(env, bufferAttributeObject, getTargetLengthID); jmethodID getPreBufferingID = (*env)->GetMethodID(env,cls,"getPreBuffering","()I"); - buffer->prebuf = (*env)->CallIntMethod(env, bufferAttributeObject, getPreBufferingID); + assert(getPreBufferingID); + buffer.prebuf = (uint32_t) (*env)->CallIntMethod(env, bufferAttributeObject, getPreBufferingID); - jmethodID getMinimumRequestID = (*env)->GetMethodID(env,cls,"getMinimumRequest ","()I"); - buffer->minreq = (*env)->CallIntMethod(env, bufferAttributeObject, getMinimumRequestID ); + jmethodID getMinimumRequestID = (*env)->GetMethodID(env, cls, "getMinimumRequest", "()I"); + assert(getMinimumRequestID); + buffer.minreq = (uint32_t) (*env)->CallIntMethod(env, bufferAttributeObject, getMinimumRequestID ); jmethodID getFragmentSizeID = (*env)->GetMethodID(env,cls,"getFragmentSize","()I"); - buffer->fragsize = (*env)->CallIntMethod(env, bufferAttributeObject, getFragmentSizeID ); + assert(getFragmentSizeID); + buffer.fragsize = (uint32_t) (*env)->CallIntMethod(env, bufferAttributeObject, getFragmentSizeID ); + + /* + const pa_buffer_attr* old_buffer = pa_stream_get_buffer_attr(stream); - pa_operation* operation = pa_stream_set_buffer_attr(stream, buffer, set_buffer_attr_callback, NULL); + printf("old buffer values: %u %u %u %u %u\n", old_buffer->maxlength, old_buffer->tlength, old_buffer->prebuf, old_buffer->minreq, old_buffer->fragsize); + + printf("want these values: %u %u %u %u %u\n", buffer.maxlength, buffer.tlength, buffer.prebuf, buffer.minreq, buffer.fragsize); + */ + + pa_operation* operation = pa_stream_set_buffer_attr(stream, &buffer, set_buffer_attr_callback, NULL); + assert(operation); return convertPointerToJavaLong(operation); } -static void update_sample_rate_callback(pa_stream* stream, int success, void* userdata) { +static void update_sample_rate_callback(pa_stream* stream, int success, + void* userdata) { assert(success); JNIEnv* env = pulse_thread_env; notifyWaitingOperations(env);
--- a/unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java Wed Aug 20 14:27:45 2008 -0400 +++ b/unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java Mon Aug 25 12:07:04 2008 -0400 @@ -94,8 +94,9 @@ Assert.assertNotNull(line); line.open(audioFormat); + System.out.println("opened"); line.start(); - + System.out.println("started"); byte[] abData = new byte[1000]; int bytesRead = 0; @@ -105,9 +106,12 @@ line.write(abData, 0, bytesRead); } } + System.out.println("done"); line.flush(); + System.out.println("flushed"); line.close(); + System.out.println("closed"); }