Mercurial > hg > pulseaudio
changeset 29:b9836224602b
added open() and start() in SourceDataLine
committer: Ioana Ivan <iivan@redhat.com>
author | Ioana Ivan <iivan@redhat.com> |
---|---|
date | Fri, 01 Aug 2008 10:59:19 -0400 |
parents | f1a1eaa0f610 |
children | f05acd4ee58b 3e7111680ba6 |
files | src/org/openjdk/sound/PulseAudioMixer.java src/org/openjdk/sound/PulseAudioSourceDataLine.java src/org/openjdk/sound/StreamEvent.java src/org/openjdk/sound/StreamListener.java src/org_openjdk_sound_PulseAudioSourceDataLine.c |
diffstat | 5 files changed, 261 insertions(+), 25 deletions(-) [+] |
line wrap: on
line diff
--- a/src/org/openjdk/sound/PulseAudioMixer.java Thu Jul 31 17:29:47 2008 -0400 +++ b/src/org/openjdk/sound/PulseAudioMixer.java Fri Aug 01 10:59:19 2008 -0400 @@ -1,11 +1,14 @@ package org.openjdk.sound; +import java.io.File; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Semaphore; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Control; import javax.sound.sampled.Line; @@ -13,6 +16,7 @@ import javax.sound.sampled.LineListener; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.Control.Type; public class PulseAudioMixer implements javax.sound.sampled.Mixer { @@ -27,11 +31,11 @@ private boolean isOpen = false; - // private List<PulseAudioSourceDataLine> _sourceLines = null; + private List<PulseAudioSourceDataLine> _sourceLines = new ArrayList(); // private List<PulseAudioTargetDataLine> _targetLines = null; - // private Line.Info _sourceDataLineInfo = new - // Line.Info(PulseAudioSourceDataLine.class); + private Line.Info _sourceDataLineInfo = new + Line.Info(PulseAudioSourceDataLine.class); // private Line.Info _targetDataLineInfo = new // Line.Info(PulseAudioTargetDataLine.class); @@ -58,13 +62,13 @@ throw new LineUnavailableException(); } - // if ( info.matches(_sourceDataLineInfo)) { - // PulseAudioSourceDataLine sourceLine = null; + if ( info.matches(_sourceDataLineInfo)) { + PulseAudioSourceDataLine sourceLine = null; // // FIXME : THIS LINE HERE v - // // sourceLine = new PulseAudioSourceDataLine(eventLoop); - // _sourceLines.add(sourceLine); - // return sourceLine; - // } + sourceLine = new PulseAudioSourceDataLine(eventLoop); + _sourceLines.add(sourceLine); + return sourceLine; + } // if (info.matches(_targetDataLineInfo)) { // PulseAudioTargetDataLine targetLine = new PulseAudioTargetDataLine(); @@ -343,8 +347,14 @@ .getMixer(selectedMixerInfo); selectedMixer.open(); - + SourceDataLine line = (SourceDataLine)selectedMixer.getLine(new Line.Info(PulseAudioSourceDataLine.class)); + File soundFile = new File("/home/yyz/omajid/PulseAudio/main-loop/multi-stream/new.wav"); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(soundFile); + AudioFormat audioFormat = audioInputStream.getFormat(); + line.open(audioFormat); + line.start(); selectedMixer.close(); + }
--- a/src/org/openjdk/sound/PulseAudioSourceDataLine.java Thu Jul 31 17:29:47 2008 -0400 +++ b/src/org/openjdk/sound/PulseAudioSourceDataLine.java Fri Aug 01 10:59:19 2008 -0400 @@ -2,6 +2,8 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Semaphore; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.Control; @@ -13,19 +15,22 @@ 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 String streamName = "Java Stream"; + private List<StreamListener> streamListeners = new ArrayList(); + private EventLoop eventLoop = null; private boolean isOpen = false; private boolean isPaused = false; - private final AudioFormat format = null; + private AudioFormat format = null; private ArrayList<LineListener> listeners; @@ -52,7 +57,7 @@ private native void native_close(); - static { + /*static { try { String library = new java.io.File(".").getCanonicalPath() + java.io.File.separatorChar + "lib" @@ -63,7 +68,7 @@ } catch (IOException e) { assert ("Loading failed".endsWith("library")); } - } + }*/ public PulseAudioSourceDataLine(EventLoop eventLoop) { this.eventLoop = eventLoop; @@ -90,14 +95,8 @@ } public void open() throws LineUnavailableException { -// format = new AudioFormat(Encoding.PCM_SIGNED, 44100, 16, 2, ); - -// synchronized (eventLoop.threadLock) { -// openStream("PCM_SIGNED", 44100, 16, 2, false, DEFAULT_BUFFER_SIZE); -// -// } - - open(null); + format = new AudioFormat(44100, 16, 2, true, false); + open(format, DEFAULT_BUFFER_SIZE); } @@ -121,8 +120,38 @@ native_resume(); isPaused = false; } else { - native_start(); - } + final Semaphore semaphore = new Semaphore(0); + + synchronized (eventLoop.threadLock) { + + this.addStreamListener(new StreamListener() { + @Override + public void update(StreamEvent e) { + System.out.println(this.getClass().getName() + + " waiting to stream to become ready"); + if (e.getType() == StreamEvent.Type.READY) { + semaphore.release(); + } + } + }); + + System.out.println("about to open stream"); + native_start(); + } + + + try { + semaphore.acquire(); + } catch (InterruptedException e) { + //throw new LineUnavailableException("unable to prepare stream"); + } + System.out.println(this.getClass().getName() + "stream is ready"); + } + + + + + /* * for(LineListener l :listeners) { l.update(new LineEvent(this, @@ -145,6 +174,10 @@ public void removeLineListener(LineListener listener) { this.listeners.remove(listener); } + + private void addStreamListener(StreamListener listener) { + this.streamListeners.add(listener); + } public boolean isOpen() { return isOpen; @@ -235,5 +268,38 @@ // TODO Auto-generated method stub } + + public void update(int status) { + synchronized(eventLoop.threadLock) { + System.out.println(this.getClass().getCanonicalName() + ".update() called! status = " + status); + switch (status) { + case 0: + fireEvent(new StreamEvent(org.openjdk.sound.StreamEvent.Type.UNCONNECTED)); + break; + case 1: + fireEvent(new StreamEvent(org.openjdk.sound.StreamEvent.Type.CREATING)); + break; + case 2: + fireEvent(new StreamEvent(org.openjdk.sound.StreamEvent.Type.READY)); + break; + case 3: + fireEvent(new StreamEvent(org.openjdk.sound.StreamEvent.Type.FAILED)); + break; + case 4: + break; + default: + assert ("not supposed to happen".indexOf("false") >= 0); + } + } + } + + private void fireEvent(StreamEvent e) { + + for (StreamListener streamListener : streamListeners) { + streamListener.update(e); + } +} + + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/openjdk/sound/StreamEvent.java Fri Aug 01 10:59:19 2008 -0400 @@ -0,0 +1,20 @@ +package org.openjdk.sound; + +public class StreamEvent { + + public static enum Type { + UNCONNECTED, CREATING, READY, FAILED, TERMINATED, + } + + + private Type type; + + public StreamEvent(StreamEvent.Type type) { + this.type = type; + } + + public Type getType() { + return this.type; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/openjdk/sound/StreamListener.java Fri Aug 01 10:59:19 2008 -0400 @@ -0,0 +1,10 @@ +package org.openjdk.sound; + +import javax.sound.sampled.LineListener; + +public interface StreamListener{ + + public void update(StreamEvent e); + +} +
--- a/src/org_openjdk_sound_PulseAudioSourceDataLine.c Thu Jul 31 17:29:47 2008 -0400 +++ b/src/org_openjdk_sound_PulseAudioSourceDataLine.c Fri Aug 01 10:59:19 2008 -0400 @@ -1,6 +1,90 @@ +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <jni.h> +#include <pulse/pulseaudio.h> #include "org_openjdk_sound_PulseAudioSourceDataLine.h" -#include <pulse/pulseaudio.h> +void setJavaIntField(JNIEnv *env, jobject obj, void *ptr, char *fieldName) { + jclass cls = (*env)->GetObjectClass(env, obj); + jlong value = (int) ptr; + jfieldID fid =(*env)->GetFieldID(env, cls, fieldName, "I"); + (*env)->SetIntField(env, obj, fid, value); + //CHECK No DeleteLocalReference Method? + //(*env)->DeleteLocalReference(cls); +} + +void *getJavaIntField(JNIEnv *env, jobject obj, char *fieldName) { +jclass cls = (*env)->GetObjectClass(env, obj); + jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "I"); + jlong value = (*env)->GetIntField(env, obj, fid); + //(*env)->DeleteLocalReference(cls); + return (void *) value; +} + + +typedef struct java_context_t { + JNIEnv* env; + jobject obj; +} java_context_t; + + +/* defined in EventLoop.c */ +extern JNIEnv* pulse_thread_env; + +static void stream_drain_complete_callback(pa_stream* stream, int success, + void* userdata) { + assert(stream); + assert(success != 0); + + pa_stream_disconnect(stream); +} + +static void stream_state_change_callback(pa_stream* stream, void* userdata) { + assert(stream); + assert(userdata); + + printf("entering stream_state_change_callback\n"); + + java_context_t* java_context = (java_context_t*)userdata; + JNIEnv* env; + + /* needed so we can create a stream from another thread + */ + if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { + printf("java thread\n"); + env = java_context->env; + } else { + env = pulse_thread_env; + } + + jobject obj = java_context->obj; + + printf("stream state changed to %d\n", pa_stream_get_state(stream)); + + /* Call the 'update' method in java + * to handle all java-side events + */ + jclass cls = (*env)->GetObjectClass(env, obj); + if (cls == NULL) { + printf("unable to get class of object"); + return; + } + jmethodID mid = (*env)->GetMethodID(env, cls, "update", "(I)V"); + if (mid == NULL) { + printf("unable to get callback method\n"); + return; + + } + printf("calling update on java\n"); + (*env)->CallVoidMethod(env, obj, mid, pa_stream_get_state(stream)); + + printf("returning form stream_state_change_callback\n"); + return; + +} + + /* * Class: org_openjdk_sound_PulseAudioSourceDataLine @@ -8,8 +92,48 @@ * Signature: (ILjava/lang/String;Ljava/lang/String;FIIZI)V */ JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1open -(JNIEnv* env, jobject obj, jint arg, jstring arg1, jstring arg2, jfloat arg3, jint arg4, jint arg5, jboolean arg6, jint arg7) { +(JNIEnv* env, jobject obj, jint contextPointer, jstring name, jstring encodingString, jfloat rate, jint size, jint channels, jboolean bigEndian, jint bufferSize) { + java_context_t* java_context = malloc(sizeof(java_context)); + java_context->env = env; +; + java_context->obj = (*env)->NewGlobalRef(env, obj); +; + + pa_sample_spec sample_spec; + + char *encoding = (*env)->GetStringUTFChars(env, encodingString, NULL); + + if( (strcmp(encoding, "PCM_UNSIGNED") == 0) && (size == 8)) { + sample_spec.format = PA_SAMPLE_U8; + } else if( (strcmp(encoding, "ALAW") == 0) && (size == 8)) { + sample_spec.format = PA_SAMPLE_ALAW; + } else if( (strcmp(encoding, "ULAW") == 0) && (size == 8)) { + sample_spec.format = PA_SAMPLE_ULAW; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 1)) { + sample_spec.format = PA_SAMPLE_S16BE; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 0)) { + sample_spec.format = PA_SAMPLE_S16LE; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 1)) { + sample_spec.format = PA_SAMPLE_S32BE; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 0)) { + sample_spec.format = PA_SAMPLE_S32LE; + } else { + printf("error in open"); + //TO DO: Invalid format :throw Exception; + } + + sample_spec.rate = rate; + sample_spec.channels = channels; + + + pa_stream *stream = pa_stream_new(contextPointer, "default stream", &sample_spec, NULL); + + pa_stream_set_state_callback(stream, stream_state_change_callback, java_context); + + + + setJavaIntField(env, obj, stream, "streamPointer"); } /* @@ -60,6 +184,12 @@ */ JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1start (JNIEnv *env, jobject obj) { + printf("start called\n"); + + pa_stream *stream = getJavaIntField(env, obj, "streamPointer"); + + pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL); + }