changeset 70:3c53bfe980bc

2008-08-13 Omair Majid <omajid@redhat.com> * build.xml: now generates headers for PulseAudioClip.java * src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java: new file. implements the Clip interface. currently mainly a stub * src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java: added support for getting a clip from the mixer * src/native/Makefile.am: added src/native/*PulseAudioClip.{c,h} to list of files to build * src/native/org_classpath_icedtea_pulseaudio_PulseAudioClip.c: new file * unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java: new file. junit tests for PulseAudioClip
author Omair Majid <omajid@redhat.com>
date Wed, 13 Aug 2008 13:00:36 -0400
parents c054a0681a49
children 9ed589465932
files build.xml src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java src/native/Makefile.am src/native/org_classpath_icedtea_pulseaudio_PulseAudioClip.c unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java
diffstat 6 files changed, 357 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/build.xml	Wed Aug 13 10:12:49 2008 -0400
+++ b/build.xml	Wed Aug 13 13:00:36 2008 -0400
@@ -38,6 +38,7 @@
 			<class name="org.classpath.icedtea.pulseaudio.EventLoop"/>
 			<class name="org.classpath.icedtea.pulseaudio.Operation"/>
 			<class name="org.classpath.icedtea.pulseaudio.PulseAudioSourceDataLine"/>
+			<class name="org.classpath.icedtea.pulseaudio.PulseAudioClip"/>
 			<class name="org.classpath.icedtea.pulseaudio.PulseAudioStreamVolumeControl"/>
 		</javah>
 	</target>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java	Wed Aug 13 13:00:36 2008 -0400
@@ -0,0 +1,268 @@
+package org.classpath.icedtea.pulseaudio;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.Control;
+import javax.sound.sampled.Line;
+import javax.sound.sampled.LineListener;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.Control.Type;
+
+public class PulseAudioClip implements Clip {
+
+	private byte[] data = null;
+	private int bufferSize = 0;
+
+	// these are frame indices. so counted from 0
+	private long currentFrame = 0;
+	private int frameCount = 0;
+	private long startFrame = 0;
+	private long endFrame = 0;
+	private long framesSinceOpen = 0;
+
+	private AudioFormat currentFormat = null;
+	private static final AudioFormat DEFAULT_FORMAT = new AudioFormat(
+			AudioFormat.Encoding.PCM_UNSIGNED, 22050, 8, 2, 2, 22050 / 2, false);
+
+	private boolean isOpen = false;
+
+	private List<LineListener> lineListeners = null;
+
+	private static final int DEFAULT_BUFFER_SIZE = 0;
+
+	@SuppressWarnings("unused")
+	private long streamPointer = 0;
+
+	private native void native_open();
+
+	private native void native_close();
+
+	private native void native_start();
+
+	private native void native_stop();
+
+	private native long native_drain();
+
+	private native long native_flush();
+
+	static {
+		try {
+			String library = new java.io.File(".").getCanonicalPath()
+					+ java.io.File.separatorChar
+					+ System.mapLibraryName("pulse-java");
+			System.out.println(library);
+			System.load(library);
+		} catch (IOException e) {
+			assert ("Loading failed".endsWith("library"));
+		}
+	}
+
+	public PulseAudioClip() {
+		lineListeners = new LinkedList<LineListener>();
+	}
+
+	@Override
+	public void addLineListener(LineListener listener) {
+		lineListeners.add(listener);
+	}
+
+	@Override
+	public int available() {
+		return 0; // a clip always returns 0
+	}
+
+	@Override
+	public void close() {
+		// TODO Auto-generated method stub
+		native_close();
+		isOpen = false;
+	}
+
+	@Override
+	public void drain() {
+		// TODO Auto-generated method stub
+		native_drain();
+	}
+
+	@Override
+	public void flush() {
+		// TODO Auto-generated method stub
+		native_flush();
+	}
+
+	@Override
+	public int getBufferSize() {
+		return bufferSize;
+	}
+
+	@Override
+	public Control getControl(Type control) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public Control[] getControls() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public AudioFormat getFormat() {
+		if (!isOpen) {
+			return DEFAULT_FORMAT;
+		}
+		return currentFormat;
+	}
+
+	@Override
+	public int getFrameLength() {
+		return frameCount;
+	}
+
+	@Override
+	public int getFramePosition() {
+		return (int) framesSinceOpen;
+	}
+
+	@Override
+	public float getLevel() {
+		// TODO Auto-generated method stub
+		return AudioSystem.NOT_SPECIFIED;
+	}
+
+	@Override
+	public javax.sound.sampled.Line.Info getLineInfo() {
+		return new Line.Info(this.getClass());
+	}
+
+	@Override
+	public long getLongFramePosition() {
+		return framesSinceOpen;
+	}
+
+	@Override
+	public long getMicrosecondLength() {
+		if (!isOpen) {
+			return AudioSystem.NOT_SPECIFIED;
+		}
+		return frameCount / currentFormat.getFrameSize();
+	}
+
+	@Override
+	public long getMicrosecondPosition() {
+		return framesSinceOpen / currentFormat.getFrameSize();
+	}
+
+	@Override
+	public boolean isActive() {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+	@Override
+	public boolean isControlSupported(Type control) {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+	@Override
+	public boolean isOpen() {
+		return isOpen;
+	}
+
+	@Override
+	public boolean isRunning() {
+		// really confused about what this is supposed to do
+		return isActive();
+	}
+
+	@Override
+	public void loop(int count) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void open() throws LineUnavailableException {
+		throw new IllegalArgumentException("open() on a Clip is not allowed");
+	}
+
+	@Override
+	public void open(AudioFormat format, byte[] data, int offset, int bufferSize)
+			throws LineUnavailableException {
+		// TODO Auto-generated method stub
+
+		native_open();
+
+		isOpen = true;
+	}
+
+	@Override
+	public void open(AudioInputStream stream) throws LineUnavailableException,
+			IOException {
+		// TODO Auto-generated method stub
+
+		byte[] buffer = new byte[(int) (stream.getFrameLength() * stream
+				.getFormat().getFrameSize())];
+
+		open(stream.getFormat(), buffer, 0, DEFAULT_BUFFER_SIZE);
+
+	}
+
+	@Override
+	public void removeLineListener(LineListener listener) {
+		lineListeners.remove(listener);
+	}
+
+	@Override
+	public void setFramePosition(int frames) {
+
+		if (frames > frameCount) {
+			throw new IllegalArgumentException("incorreft frame value");
+		}
+
+		currentFrame = frames;
+
+	}
+
+	@Override
+	public void setLoopPoints(int start, int end) {
+		if (end == -1) {
+			end = frameCount;
+		}
+
+		if (end < start) {
+			throw new IllegalArgumentException(
+					"ending point must be greater than or equal to the starting point");
+		}
+
+		startFrame = start;
+		endFrame = end;
+
+	}
+
+	@Override
+	public void setMicrosecondPosition(long microseconds) {
+		float frameIndex = microseconds * currentFormat.getFrameRate();
+		currentFrame = (long) frameIndex;
+
+	}
+
+	@Override
+	public void start() {
+		native_start();
+	}
+
+	@Override
+	public void stop() {
+		native_stop();
+	}
+
+}
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java	Wed Aug 13 10:12:49 2008 -0400
+++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java	Wed Aug 13 13:00:36 2008 -0400
@@ -73,7 +73,8 @@
 
 	private List<PulseAudioSourceDataLine> sourceLines = new ArrayList<PulseAudioSourceDataLine>();
 	// private List<PulseAudioTargetDataLine> targetLines = null;
-
+	private List<PulseAudioClip> clips = new ArrayList<PulseAudioClip>();
+	
 	// private Line.Info targetDataLineInfo = new
 	// Line.Info(PulseAudioTargetDataLine.class);
 
@@ -144,6 +145,14 @@
 		// return targetLine;
 		// }
 
+		PulseAudioClip clip = new PulseAudioClip();
+		
+		if (info.matches(clip.getLineInfo())) {
+			clips.add(clip);
+			return clip;
+		}
+		
+		
 		throw new IllegalArgumentException();
 	}
 
--- a/src/native/Makefile.am	Wed Aug 13 10:12:49 2008 -0400
+++ b/src/native/Makefile.am	Wed Aug 13 13:00:36 2008 -0400
@@ -10,7 +10,9 @@
 	org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl.c \
 	org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl.h \
 	org_classpath_icedtea_pulseaudio_Operation.h \
-	org_classpath_icedtea_pulseaudio_Operation.c
+	org_classpath_icedtea_pulseaudio_Operation.c \
+	org_classpath_icedtea_pulseaudio_PulseAudioClip.c \
+	org_classpath_icedtea_pulseaudio_PulseAudioClip.h
 
 AM_CFLAGS = -g -Wall -Werror $(PLATFORM_FLAGS) $(LIBPULSE_CFLAGS)
 AM_LDFLAGS = -g -Wall -Werror $(LIBPULSE_LIBS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/native/org_classpath_icedtea_pulseaudio_PulseAudioClip.c	Wed Aug 13 13:00:36 2008 -0400
@@ -0,0 +1,24 @@
+#include "org_classpath_icedtea_pulseaudio_PulseAudioClip.h"
+
+#include "jni-common.h"
+
+/*
+ * Class:     org_classpath_icedtea_pulseaudio_PulseAudioClip
+ * Method:    native_open
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioClip_native_1open
+(JNIEnv* env, jobject obj) {
+
+}
+
+/*
+ * Class:     org_classpath_icedtea_pulseaudio_PulseAudioClip
+ * Method:    native_close
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioClip_native_1close
+(JNIEnv* env, jobject obj) {
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java	Wed Aug 13 13:00:36 2008 -0400
@@ -0,0 +1,51 @@
+package org.classpath.icedtea.pulseaudio;
+
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.Line;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.Mixer;
+
+import junit.framework.JUnit4TestAdapter;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PulseAudioClipTest {
+
+	Mixer mixer;
+
+	public static junit.framework.Test suite() {
+		return new JUnit4TestAdapter(PulseAudioClipTest.class);
+	}
+
+	@Before
+	public void setUp() throws LineUnavailableException {
+		Mixer.Info wantedMixerInfo = null;
+		Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo();
+		for (Mixer.Info mixerInfo : mixerInfos) {
+			if (mixerInfo.getName().contains("PulseAudio")) {
+				wantedMixerInfo = mixerInfo;
+				break;
+			}
+		}
+		assert (wantedMixerInfo != null);
+		mixer = AudioSystem.getMixer(wantedMixerInfo);
+		mixer.open();
+	}
+
+	@Test
+	public void testObtainingAClip() throws LineUnavailableException {
+		Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class));
+		Assert.assertNotNull(clip);
+	}
+
+	
+	@After
+	public void tearDown() {
+
+	}
+
+}