Mercurial > hg > pulseaudio
changeset 24:03101556665f
fixed errors
committer: Ioana Ivan <iivan@redhat.com>
author | Ioana Ivan <iivan@redhat.com> |
---|---|
date | Tue, 29 Jul 2008 11:46:39 -0400 |
parents | 9ce846af2c4d |
children | 7fc1bc131b7e |
files | src/org/openjdk/sound/PulseAudioTargetDataLine.java src/org_openjdk_sound_PulseAudioTargetDataLine.c |
diffstat | 2 files changed, 361 insertions(+), 106 deletions(-) [+] |
line wrap: on
line diff
--- a/src/org/openjdk/sound/PulseAudioTargetDataLine.java Tue Jul 29 11:29:44 2008 -0400 +++ b/src/org/openjdk/sound/PulseAudioTargetDataLine.java Tue Jul 29 11:46:39 2008 -0400 @@ -1,75 +1,84 @@ package org.openjdk.sound; -import java.io.File; +import java.util.ArrayList; + +import javax.sound.sampled.*; +import javax.sound.sampled.Control.Type; + + -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Control; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.TargetDataLine; -import javax.sound.sampled.Control.Type; -public class PulseAudioTargetDataLine implements TargetDataLine { +public class PulseAudioTargetDataLine implements TargetDataLine { + + protected long contextPointer; + protected long mainLoopPointer; + protected long streamPointer; + protected boolean isOpen = false; + protected boolean isPaused = false; + protected int defaultBufferSize; + protected ArrayList<LineListener> listeners; - private boolean isOpen = false; - private long nativeObject; - - public boolean isOpen() { - return isOpen; + public void open(AudioFormat format, int bufferSize) throws LineUnavailableException { + isOpen = true; + + int channels = format.getChannels(); + float rate = format.getSampleRate(); + int sampleSize = format.getSampleSizeInBits(); + String encoding = format.getEncoding().toString(); + boolean bigEndian = format.isBigEndian(); + openStream(encoding, rate, sampleSize, channels, bigEndian, bufferSize); + } + + public void open(AudioFormat format) throws LineUnavailableException { + open(format, defaultBufferSize); + } - public void open(AudioFormat format) { - int channels = format.getChannels(); - float rate = format.getFrameRate(); - boolean bigEndian = format.isBigEndian(); - AudioFormat.Encoding encoding = format.getEncoding(); - openConnection(channels, rate); + + public void open() throws LineUnavailableException { + openStream("PCM_SIGNED", 44100, 16, 2, false, defaultBufferSize); } - - private native void openConnection(int channels, float rate); - private native void write(byte[]data, int bytes, int index); - private native void closeConnection(); - - public static void main(String[] args)throws Exception{ - File soundFile = new File("/home/yyz/iivan/pulse-test/sound.wav"); - AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - PulseAudioSourceDataLine line = new PulseAudioSourceDataLine(1,1); - line.open(audioFormat); - byte[] abData = new byte[10000]; - int bytesRead = 0; - while ( bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - line.write(abData, bytesRead, 0); - } - } - line.closeConnection(); - } - + private native void openStream(String encoding, float rate, int size, int channels, boolean bigEndian, int bufferSize); + static { System.loadLibrary("PulseAudioSourceDataLine"); } - @Override - public void open(AudioFormat format, int bufferSize) - throws LineUnavailableException { - // TODO Auto-generated method stub - - } + @Override public int read(byte[] b, int off, int len) { - // TODO Auto-generated method stub - return 0; + readFromStream(b, off, len); + return len; } + + private native void readFromStream(byte[] b, int off, int len); + + - @Override - public int available() { - // TODO Auto-generated method stub - return 0; + public void start() { + if (isPaused) { + resumeStream(); + isPaused = false; + } else { + startStream(); + } + + for(LineListener l :listeners) { + l.update(new LineEvent(this, LineEvent.Type.START, 0)); + } } + + public void stop() { + pauseStream(); + isPaused = true; + + + } + + private native void startStream(); + private native void pauseStream(); + private native void resumeStream(); + @Override public void drain() { @@ -82,114 +91,101 @@ // TODO Auto-generated method stub } - - @Override + + public void addLineListener(LineListener listener){ + listeners.add(listener); + } + + public void removeLineListener(LineListener listener){ + listeners.remove(listener); + } + + public boolean isOpen() { + return isOpen; + } + + public native int available(); + + public void close() { + closeStream(); + for (LineListener l : listeners) { + l.update(new LineEvent(this, LineEvent.Type.CLOSE, 0)); + } + + } + + private native void closeStream(); + public int getBufferSize() { // TODO Auto-generated method stub return 0; } - @Override + public AudioFormat getFormat() { // TODO Auto-generated method stub return null; } - @Override + public int getFramePosition() { // TODO Auto-generated method stub return 0; } - @Override + public float getLevel() { // TODO Auto-generated method stub return 0; } - @Override + public long getLongFramePosition() { // TODO Auto-generated method stub return 0; } - @Override + public long getMicrosecondPosition() { // TODO Auto-generated method stub return 0; } - @Override + public boolean isActive() { // TODO Auto-generated method stub return false; } - @Override public boolean isRunning() { // TODO Auto-generated method stub return false; } - - @Override - public void start() { - // TODO Auto-generated method stub - - } - - @Override - public void stop() { - // TODO Auto-generated method stub - - } - - @Override - public void addLineListener(LineListener listener) { - // TODO Auto-generated method stub - - } - - @Override - public void close() { - // TODO Auto-generated method stub - - } - - @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 javax.sound.sampled.Line.Info getLineInfo() { - // TODO Auto-generated method stub - return null; + return new Line.Info(SourceDataLine.class); } - @Override + public boolean isControlSupported(Type control) { // TODO Auto-generated method stub return false; } - @Override - public void open() throws LineUnavailableException { - // TODO Auto-generated method stub - - } - - @Override - public void removeLineListener(LineListener listener) { - // TODO Auto-generated method stub - - } + + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_openjdk_sound_PulseAudioTargetDataLine.c Tue Jul 29 11:46:39 2008 -0400 @@ -0,0 +1,259 @@ +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <jni.h> +#include <pulse/pulseaudio.h> +#include <string.h> +#include "org_openjdk_sound_PulseAudioTargetDataLine.h" + + + + + + +void setJavaLongField(JNIEnv *env, jobject obj, void *ptr, char *fieldName) { + jclass cls = (*env)->GetObjectClass(env, obj); + jlong value = (long) ptr; + jfieldID fid =(*env)->GetFieldID(env, cls, fieldName, "J"); + (*env)->SetLongField(env, obj, fid, value); + //CHECK No DeleteLocalReference Method? + //(*env)->DeleteLocalReference(cls); +} + +void *getJavaLongField(JNIEnv *env, jobject obj, char *fieldName) { +jclass cls = (*env)->GetObjectClass(env, obj); + jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "J"); + jlong value = (*env)->GetLongField(env, obj, fid); + //(*env)->DeleteLocalReference(cls); + return (void *) value; +} + + + +static void stream_read_cb(pa_stream* stream, size_t length, void* userdata) { + pa_threaded_mainloop *mainloop = userdata; + pa_threaded_mainloop_signal(mainloop,0); +} + +static void stream_operation_complete_cb(pa_stream* stream, int success, void* userdata) { + pa_threaded_mainloop *mainloop = userdata; + pa_threaded_mainloop_signal(mainloop,0); +} + + + +static void stream_state_cb(pa_stream* stream, void* userdata) { + assert(stream); + pa_threaded_mainloop *mainloop = userdata; + printf("stream state changed to %d\n", pa_stream_get_state(stream)); + switch (pa_stream_get_state(stream)) { + case PA_STREAM_READY: + case PA_STREAM_FAILED: + case PA_STREAM_TERMINATED: + pa_threaded_mainloop_signal(mainloop, 0); + break; + + default: + /* do nothing */ + break; + } + } + + + + +JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_openStream + (JNIEnv * env, jobject obj, jstring string, jfloat rate, jint size, jint channels, jboolean bigEndian, jint bufferSize){ + + //TO DO: Need to deal with the buffer size. Currently ignored + + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_context *context = getJavaLongField(env, obj, "contextPointer"); + + + pa_sample_spec sample_spec; + + char *encoding = GetStringUTFChars(env, string, 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 { + //TO DO: Invalid format :throw Exception; + } + + sample_spec.rate = rate; + sample_spec.channels = channels; + + pa_threaded_mainloop_lock(mainloop); + + pa_stream *stream = pa_stream_new(context, "default stream", &sample_spec, NULL); + + pa_stream_set_state_callback(stream, stream_state_cb, mainloop); + pa_stream_set_read_callback(stream, stream_read_cb, mainloop); + + + pa_threaded_mainloop_unlock(mainloop); + + + setJavaLongField(env, obj, stream, "streamPointer"); + return; + +unlock_and_fail: + pa_threaded_mainloop_unlock(mainloop); + +fail: + return; +} + +JNIEXPORT void JNICALL +Java_org_openjdk_sound_PulseAudioSourceDataLine_startStream(JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL); + pa_threaded_mainloop_wait(mainloop); + if ( pa_stream_get_state(stream) != PA_STREAM_READY ) { + printf("stream initialization failed\n"); + } + pa_threaded_mainloop_unlock(mainloop); +} + +JNIEXPORT void Java_org_openjdk_sound_PulseAudioSourceDataLine_resumeStream(JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + pa_operation *o = pa_stream_cork(stream, 0, stream_operation_complete_cb, mainloop); + while(pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(mainloop); + } + pa_operation_unref(o); + pa_threaded_mainloop_unlock(mainloop); + +} + +JNIEXPORT void Java_org_openjdk_sound_PulseAudioSourceDataLine__pauseStream(JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + pa_operation *o = pa_stream_cork(stream, 1, stream_operation_complete_cb, mainloop); + while(pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(mainloop); + } + pa_operation_unref(o); + pa_threaded_mainloop_unlock(mainloop); +} + + + +J + +JNIEXPORT void JNICALL +Java_org_openjdk_sound_PulseAudioSourceDataLine__closeStream(JNIEnv *env, jobject obj, jint channels, jfloat rate) { + + + + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_strean_disconnect(stream); +} + +JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_available + (JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + int available = pa_stream_writable_size(stream); + pa_threaded_mainloop_unlock(mainloop); + return available; + } + + +JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_drain + (JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + pa_operation *o = pa_stream_drain(stream, stream_operation_complete_cb, mainloop); + while(pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(mainloop); + } + pa_operation_unref(o); + pa_threaded_mainloop_unlock(mainloop); + } + +JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_flush + (JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + pa_operation *o = pa_stream_flush(stream, stream_operation_complete_cb, mainloop); + while(pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(mainloop); + } + pa_operation_unref(o); + pa_threaded_mainloop_unlock(mainloop); + } + + + + + +JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioTargetDataLine_readFromStream + (JNIEnv * env, jobject obj, jbyteArray array, jint length, jint offset); + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + char[length] data; + while(length > 0) { + size_t l; + while(!read_data) { + int r = pa_stream_peek(_stream, &read_data, &read_length); + if(!read_data) { + pa_threaded_mainloop_wait(mainloop); + } else { + read_index = 0; + } + } + + l = read_length < length ? read_length : length; + memcpy(data, read_data+read_index, l); + + data = data + l; + length -= l; + read_index +=l; + read_length-=l; + + if(! read_length) { + int r = pa_stream_drop(stream); + read_data = NULL; + read_length = 0; + read_index = 0; + + } + + + } + + pa_threaded_mainloop_unlock(mainloop); + SetByteArrayRegion(env, array, offset, initialLength, data); +} + + + + + + + + +